Theory Symmetric_Generation
section ‹Generating the Symmetric Group›
theory Symmetric_Generation
imports Symmetric_Group Sylow_Theorems
begin
text ‹@{term "Sn n"} is finite: it is a set of permutations of a finite set. Stated here at the top
level --- it was previously inside the anonymous context below that fixes a @{term p}-cycle
@{term g}, so the exported fact carried that context's four irrelevant assumptions.›
lemma finite_Sn: "finite (Sn n)"
unfolding Sn_def using finite_permutations[of "{0..<n}"] by simp
text ‹
The symmetric group @{term "Sn n"} is generated by a single transposition
together with a full @{term n}-cycle, and (for prime @{term p}) by ∗‹any› transposition
together with ∗‹any› @{term p}-cycle. These generation results are the combinatorial
ingredient that, combined with ‹Sn_not_solvable›, shows that the Galois group
of a quintic with exactly two non-real roots is the whole of @{term "Sn 5"}.›
subsection ‹A general lemma on generated subgroups›
text ‹Powers of an element of a generated subgroup stay inside it.›
lemma (in Group) generate_funpow:
assumes "g ∈ generate S"
shows "power g k ∈ generate S"
by (induction k) (auto simp add: assms generate.intros)
subsection ‹Conjugation is an automorphism of the generated subgroup›
text ‹Conjugation by a group element @{term g} fixes the unit and commutes with generation:
the image of @{term "generate S"} under @{term "conjugation g"} is the subgroup generated by
the image of @{term S}. This lets a generation result be transported along conjugacy, which
is what upgrades the standard-cycle generation theorem to an ∗‹arbitrary› cycle.›
lemma (in Group) conjugation_one: "g ∈ G ⟹ conjugation g 𝟭 = 𝟭"
by (simp add: conjugation_def invertible_right_inverse)
lemma (in Group) conjugation_inv_cancel:
assumes g: "g ∈ G" and x: "x ∈ G"
shows "conjugation (inverse g) (conjugation g x) = x"
using g x by (simp add: conjugation_def associative invertible_left_inverse2 invertible_right_inverse2)
lemma (in Group) conjugation_generate_sub:
assumes g: "g ∈ G"
shows "conjugation g ` generate S ⊆ generate (conjugation g ` (S ∩ G))"
proof
fix y assume "y ∈ conjugation g ` generate S"
then obtain x where x: "x ∈ generate S" and yx: "y = conjugation g x" by auto
from x have "conjugation g x ∈ generate (conjugation g ` (S ∩ G))"
proof induction
case unit
then show ?case using conjugation_one[OF g] generate.unit by simp
next
case (incl x) then show ?case
by (simp add: generate.incl conjugation_closed g)
next
case (comp x y)
then show ?case
using conjugation_hom generate.comp generate_subset_carrier by (smt (cvc5, best) in_mono)
next
case (inv x)
then show ?case
by (metis IntD2 conjugation_inverse g generate.inv generate_subset_carrier inf.orderE)
qed
then show "y ∈ generate (conjugation g ` (S ∩ G))" using yx by simp
qed
lemma (in Group) conjugation_generate_eq:
assumes g: "g ∈ G"
shows "conjugation g ` generate S = generate (conjugation g ` (S ∩ G))"
proof
show "conjugation g ` generate S ⊆ generate (conjugation g ` (S ∩ G))"
by (rule conjugation_generate_sub[OF g])
next
have ginv: "inverse g ∈ G" using g by blast
let ?T = "conjugation g ` (S ∩ G)"
have sub2: "conjugation (inverse g) ` generate ?T ⊆ generate (conjugation (inverse g) ` (?T ∩ G))"
by (rule conjugation_generate_sub[OF ginv])
have "conjugation (inverse g) ` (?T ∩ G) ⊆ S ∩ G"
by (auto simp: conjugation_inv_cancel g)
then have step: "generate (conjugation (inverse g) ` (?T ∩ G)) ⊆ generate (S ∩ G)"
by (rule generate_mono)
show "generate ?T ⊆ conjugation g ` generate S"
proof
fix y assume y: "y ∈ generate ?T"
have yG: "y ∈ G" using y generate_subset_carrier by blast
have "conjugation g (conjugation (inverse g) y) ∈ conjugation g ` generate (S ∩ G)"
using sub2 y step by auto
moreover have "conjugation g (conjugation (inverse g) y) = y"
using ginv yG conjugation_inv_cancel[OF ginv yG] g by simp
ultimately show "y ∈ conjugation g ` generate S"
using generate_mono[of "S ∩ G" S] by auto
qed
qed
subsection ‹Transpositions generate the symmetric group›
text ‹The set of transpositions of points of @{term "{0..<n}"}.›
definition transpositions :: "nat ⇒ (nat ⇒ nat) set"
where "transpositions n = {Transposition.transpose a b | a b. a ∈ {0..<n} ∧ b ∈ {0..<n}}"
lemma transpositions_subset_Sn: "transpositions n ⊆ Sn n"
by (auto simp: transpositions_def Sn_def permutes_swap_id)
subsection ‹The standard ‹n›-cycle›
text ‹The cyclic shift sending ‹i› to ‹Suc i mod n› on @{term "{0..<n}"}, fixing everything
outside. We work with this explicit form rather than @{const cycle_of_list} because its
powers have the transparent closed form @{term "(i + k) mod n"}.›
definition ncycle :: "nat ⇒ nat ⇒ nat"
where "ncycle n i = (if i < n then Suc i mod n else i)"
lemma ncycle_lt: "i < n ⟹ ncycle n i < n" by (auto simp: ncycle_def)
lemma ncycle_inv_right: "i < n ⟹ ncycle n ((i + (n-1)) mod n) = i"
by (simp add: mod_if ncycle_def)
lemma ncycle_inv_left: "i < n ⟹ (ncycle n i + (n-1)) mod n = i"
using mod_if ncycle_def by force
lemma ncycle_permutes: "ncycle n permutes {0..<n}"
proof (rule bij_imp_permutes)
show "bij_betw (ncycle n) {0..<n} {0..<n}"
proof (rule bij_betw_byWitness)
show "∀i∈{0..<n}. ncycle n (if i < n then (i + (n-1)) mod n else i) = i"
using ncycle_inv_right by auto
qed (use ncycle_lt ncycle_inv_left in auto)
qed (auto simp: ncycle_def)
lemma ncycle_in_Sn: "ncycle n ∈ Sn n" by (simp add: Sn_def ncycle_permutes)
lemma ncycle_bij: "bij (ncycle n)"
by (rule permutes_bij[OF ncycle_permutes])
text ‹The closed form for the iterates of the @{term n}-cycle.›
lemma ncycle_funpow: "i < n ⟹ (ncycle n ^^ k) i = (i + k) mod n"
by (induction k; simp add: mod_Suc_eq ncycle_def)
context
fixes n::nat
begin
interpretation S: Group "Sn n" "(∘)" id
by (rule Group_Sn)
text ‹Every permutation of @{term "{0..<n}"} is a product of transpositions, so the
transpositions generate @{term "Sn n"}. This follows directly from the tailored induction
rule @{thm [source] permutes_induct}.›
lemma Sn_generated_by_transpositions:
"Group.generate (Sn n) (∘) id (transpositions n) = Sn n"
proof
show "S.generate (transpositions n) ⊆ Sn n"
using S.generate_subset_carrier by simp
next
show "Sn n ⊆ S.generate (transpositions n)"
proof
fix p assume "p ∈ Sn n"
then have "p permutes {0..<n}" "finite {0..<n}" by (simp_all add: Sn_def)
then show "p ∈ S.generate (transpositions n)"
proof (induction p rule: permutes_induct)
case id
show ?case
using S.generate.unit by blast
next
case (swap a b p)
then obtain "Transposition.transpose a b ∈ transpositions n"
"Transposition.transpose a b ∈ Sn n"
using transpositions_def transpositions_subset_Sn by fastforce
then show ?case
by (metis Int_iff S.generate.comp S.generate.incl swap.IH)
qed
qed
qed
subsection ‹Conjugating a transposition›
text ‹Conjugating a transposition by a bijection transposes the images of the two points.›
lemma transpose_conjug:
assumes "bij q"
shows "q ∘ Transposition.transpose a b ∘ inv q = Transposition.transpose (q a) (q b)"
proof -
have "Transposition.transpose (q a) (q b) ∘ q = q ∘ Transposition.transpose a b"
using assms by (simp add: bij_def transpose_comp_eq)
then show ?thesis
by (metis assms bij_betw_inv_into bij_is_inj o_inv_o_cancel)
qed
subsection ‹The symmetric group is generated by a transposition and a cycle›
text ‹The group power in @{term "Sn n"} (composition) is just function iteration.›
lemma Sn_power_funpow: "Monoid.power (∘) id (g :: nat ⇒ nat) k = g ^^ k"
by (metis S.power_def comp_funpow comp_id)
text ‹In @{term "Sn n"} the group inverse is the functional inverse.›
lemma Sn_inverse_eq:
assumes "p ∈ Sn n"
shows "Monoid.inverse (Sn n) (∘) id p = inv p"
using S.invertible_left_inverse2 Sn_iff assms permutes_inv permutes_inv_o(1) by fastforce
lemma t01_in_Sn: "1 < n ⟹ Transposition.transpose 0 1 ∈ Sn n"
by (simp add: Sn_def permutes_swap_id)
text ‹Conjugating @{term "transpose 0 1"} by the @{term k}-th power of the @{term n}-cycle
yields the adjacent transposition @{term "transpose (k mod n) (Suc k mod n)"}.›
lemma adjacent_transpose_conjug:
assumes "k < n" "1 < n"
shows "(ncycle n ^^ k) ∘ Transposition.transpose 0 1 ∘ inv (ncycle n ^^ k)
= Transposition.transpose (k mod n) (Suc k mod n)"
proof -
have "(ncycle n ^^ k) ∘ Transposition.transpose 0 1 ∘ inv (ncycle n ^^ k)
= Transposition.transpose ((ncycle n ^^ k) 0) ((ncycle n ^^ k) 1)"
using ncycle_bij bij_fn transpose_conjug by metis
then show ?thesis
by (metis One_nat_def Suc_lessD add_0 assms(2) ncycle_funpow plus_1_eq_Suc)
qed
text ‹Hence each adjacent transposition lies in the subgroup generated by
@{term "transpose 0 1"} and the @{term n}-cycle.›
lemma adjacent_in_generate:
assumes "k < n" "1 < n"
defines "S ≡ {Transposition.transpose 0 1, ncycle n}"
shows "Transposition.transpose (k mod n) (Suc k mod n) ∈ Group.generate (Sn n) (∘) id S"
proof -
have t01: "Transposition.transpose 0 1 ∈ S.generate S"
using Group.generate_incl S.Group_axioms S_def assms(2) t01_in_Sn by fastforce
have nc: "ncycle n ∈ S.generate S"
using ncycle_in_Sn by (intro S.generate.incl) (simp add: S_def)
have powk: "S.power (ncycle n) k ∈ S.generate S" using nc by (rule S.generate_funpow)
have powkSn: "S.power (ncycle n) k ∈ Sn n" using powk S.generate_subset_carrier by blast
have conj: "S.power (ncycle n) k ∘ Transposition.transpose 0 1 ∘ S.inverse (S.power (ncycle n) k) ∈ S.generate S"
using powk t01 by (meson S.generate.simps)
have "S.inverse (S.power (ncycle n) k) = inv (ncycle n ^^ k)"
using Sn_power_funpow powkSn Sn_inverse_eq by simp
with conj Sn_power_funpow adjacent_transpose_conjug[OF assms(1,2)]
show ?thesis by simp
qed
text ‹Building from adjacent transpositions, every transposition ‹transpose i j› with
‹i < j < n› lies in the subgroup.›
lemma transpose_extend:
assumes "a ≠ b" "b ≠ c" "a ≠ c"
shows "Transposition.transpose a c = Transposition.transpose a b ∘ Transposition.transpose b c ∘ Transposition.transpose a b"
using assms by (simp add: transpose_comp_triple)
lemma all_transpose_in_generate_aux:
assumes "1 < n"
defines "S ≡ {Transposition.transpose 0 1, ncycle n}"
shows "∀i. i + Suc d < n ⟶ Transposition.transpose i (i + Suc d) ∈ Group.generate (Sn n) (∘) id S"
proof (induction d)
case 0
show ?case
unfolding S_def
using adjacent_in_generate[OF _ assms(1)]
by (metis One_nat_def Suc_eq_plus1 Suc_lessD mod_less)
next
case (Suc d)
show ?case
proof (intro allI impI)
fix i assume i: "i + Suc (Suc d) < n"
let ?b = "i + Suc d" and ?c = "i + Suc (Suc d)"
have §: "i + Suc d < n" using i by simp
then have ib: "Transposition.transpose i ?b ∈ S.generate S"
using Suc.IH unfolding S_def by blast
have "?b mod n = ?b" "Suc ?b mod n = Suc ?b" using i by auto
then have §: "Transposition.transpose ?b (Suc ?b) ∈ S.generate S"
using adjacent_in_generate[OF _ assms(1)] unfolding S_def by (metis §)
have "Transposition.transpose i ?c
= Transposition.transpose i ?b ∘ Transposition.transpose ?b ?c ∘ Transposition.transpose i ?b"
by (rule transpose_extend) auto
with ib § show "Transposition.transpose i ?c ∈ S.generate S"
by (auto intro: S.generate.comp simp: o_assoc)
qed
qed
lemma transpose_in_generate:
assumes "a < n" "b < n" "1 < n"
shows "Transposition.transpose a b ∈ Group.generate (Sn n) (∘) id {Transposition.transpose 0 1, ncycle n}"
proof (cases "a=b")
case True
then show ?thesis
by (simp add: S.generate.unit)
next
case False
then show ?thesis
using assms add_Suc_right less_natE all_transpose_in_generate_aux
by (metis (no_types, lifting) linorder_not_le order_less_le transpose_commute)
qed
text ‹The canonical generation theorem: a transposition of two adjacent points together with
the standard @{term n}-cycle generate the whole symmetric group.›
theorem Sn_generated_canonical:
assumes "1 < n"
shows "Group.generate (Sn n) (∘) id {Transposition.transpose 0 1, ncycle n} = Sn n"
proof
show "S.generate {Transposition.transpose 0 1, ncycle n} ⊆ Sn n"
using S.generate_subset_carrier by simp
next
have sub: "S.generate (transpositions n) ⊆ S.generate {Transposition.transpose 0 1, ncycle n}"
using transpose_in_generate[OF _ _ assms]
by (intro S.generate_minimal S.generate_is_subgroup) (auto simp: transpositions_def)
then show "Sn n ⊆ S.generate {Transposition.transpose 0 1, ncycle n}"
using Sn_generated_by_transpositions by simp
qed
subsection ‹A transposition and a ‹p›-cycle generate ‹S⇩p› for prime ‹p››
text ‹For prime @{term p}, the standard @{term p}-cycle together with ∗‹any› transposition
generates @{term "Sn p"}. The primality is essential: it guarantees that the conjugates of
the transposition by powers of the cycle have supports forming a single orbit covering all
points, from which every transposition can be recovered.›
text ‹Conjugating @{term "transpose a b"} by the @{term k}-th power of the @{term n}-cycle
shifts both points by @{term k} (modulo @{term n}); the result stays in the subgroup
generated by the cycle and the transposition.›
lemma ncycle_conj_transpose_in_generate:
assumes "a < n" "b < n" "1 < n"
defines "S ≡ {ncycle n, Transposition.transpose a b}"
shows "Transposition.transpose ((a + k) mod n) ((b + k) mod n) ∈ Group.generate (Sn n) (∘) id S"
proof -
have tabSn: "Transposition.transpose a b ∈ Sn n"
using assms by (auto simp: Sn_def permutes_swap_id)
have tab: "Transposition.transpose a b ∈ S.generate S"
using tabSn by (intro S.generate.incl) (simp add: S_def)
have nc: "ncycle n ∈ S.generate S"
using ncycle_in_Sn by (intro S.generate.incl) (simp add: S_def)
have invk: "S.inverse (S.power (ncycle n) k) ∈ S.generate S"
using nc by (intro S.generate.inv S.generate_funpow)
have conj: "S.power (ncycle n) k ∘ Transposition.transpose a b ∘ S.inverse (S.power (ncycle n) k) ∈ S.generate S"
by (simp add: S.generate.comp S.generate_funpow invk nc tab)
have inveq: "S.inverse (S.power (ncycle n) k) = inv (ncycle n ^^ k)"
using S.power_closed Sn_inverse_eq Sn_power_funpow ncycle_in_Sn by force
have "ncycle n ^^ k ∘ Transposition.transpose a b ∘ inv (ncycle n ^^ k)
= Transposition.transpose ((ncycle n ^^ k) a) ((ncycle n ^^ k) b)"
using ncycle_bij by (intro transpose_conjug bij_fn)
with ncycle_funpow [of _ n k] assms
have "ncycle n ^^ k ∘ Transposition.transpose a b ∘ inv (ncycle n ^^ k)
= Transposition.transpose ((a + k) mod n) ((b + k) mod n)" by presburger
with conj Sn_power_funpow inveq show ?thesis by simp
qed
text ‹If a subgroup contains two transpositions sharing a point, it contains their ``sum''.›
lemma transpose_chain:
assumes H: "Subgroup H (Sn n) (∘) id"
and "Transposition.transpose x y ∈ H"
and "Transposition.transpose y z ∈ H"
and "x ≠ z" "y ≠ z"
shows "Transposition.transpose x z ∈ H"
proof -
interpret H: Subgroup H "Sn n" "(∘)" id by (rule H)
show ?thesis
using assms by (metis H.sub_composition_closed transpose_comp_triple)
qed
end
context
fixes p::nat
assumes p: "prime p"
begin
interpretation G: Group "Sn p" "(∘)" id
by (rule Group_Sn)
lemma p_gt1: "1 < p"
using p by (simp add: prime_nat_iff)
text ‹Number-theoretic facts about the stride @{term d} (the gap of the transposition).›
lemma coprime_prime_stride:
assumes "0 < d" "d < p"
shows "coprime p d"
by (simp add: assms nat_dvd_not_less p prime_imp_coprime)
lemma kd_mod_zero_iff:
assumes "0 < d" "d < p"
shows "(k * d) mod p = 0 ⟷ p dvd k"
by (simp add: coprime_dvd_mult_left_iff coprime_prime_stride assms mod_eq_0_iff_dvd)
lemma stride_endpoints_distinct:
assumes "0 < d" "d < p"
shows "(k * d) mod p ≠ (Suc k * d) mod p"
by (metis assms add_implies_diff le_add2 mod_eq_dvd_iff_nat mult_Suc nat_dvd_not_less)
text ‹Each ``stride edge'' ‹transpose (k * d mod p) (Suc k * d mod p)› lies in the subgroup
generated by the cycle and @{term "transpose 0 d"}.›
lemma stride_edge:
assumes d1: "0 < d" and d2: "d < p"
defines "S ≡ {ncycle p, Transposition.transpose 0 d}"
shows "Transposition.transpose ((k * d) mod p) ((Suc k * d) mod p) ∈ Group.generate (Sn p) (∘) id S"
using S_def Symmetric_Generation.ncycle_conj_transpose_in_generate d2
by (metis add_0 mult_Suc p prime_gt_0_nat prime_nat_iff)
text ‹Chaining the stride edges, every ‹transpose 0 (k * d mod p)› (for ‹k› not a
multiple of @{term p}) lies in the subgroup.›
lemma stride_walk:
fixes d :: nat
assumes d1: "0 < d" and d2: "d < p"
defines "S ≡ {ncycle p, Transposition.transpose 0 d}"
shows "¬ p dvd k ⟹ Transposition.transpose 0 ((k * d) mod p) ∈ Group.generate (Sn p) (∘) id S"
proof (induction k)
case 0
then show ?case by simp
next
case (Suc k)
have edge: "Transposition.transpose ((k * d) mod p) ((Suc k * d) mod p) ∈ G.generate S"
using stride_edge[OF d1 d2] unfolding S_def by blast
have suc_ne0: "(Suc k * d) mod p ≠ 0"
using Suc.prems d1 d2 kd_mod_zero_iff by blast
show ?case
proof (cases "p dvd k")
case True
then show ?thesis by (metis edge dvd_imp_mod_0 dvd_mult2)
next
case False
have ih: "Transposition.transpose 0 ((k * d) mod p) ∈ G.generate S"
using Suc.IH[OF False] unfolding S_def by blast
have kne0: "(k * d) mod p ≠ 0"
using False d1 d2 kd_mod_zero_iff by blast
have ne: "(k * d) mod p ≠ (Suc k * d) mod p"
using d1 d2 stride_endpoints_distinct by blast
show ?thesis
using transpose_chain[OF G.generate_is_subgroup ih edge] kne0 suc_ne0 ne
unfolding S_def by argo
qed
qed
lemma pymod: "(p * y + 1) mod p = (1::nat) mod p"
by (metis mod_mult_self3 mult.commute)
text ‹Since @{term d} is coprime to the prime @{term p}, some multiple of @{term d} is
congruent to @{term 1}, so @{term "transpose 0 1"} is reached.›
lemma stride_reaches_one:
fixes d :: nat
assumes d1: "0 < d" and d2: "d < p"
shows "∃k. (k * d) mod p = 1 ∧ ¬ p dvd k"
proof -
have cop: "coprime d p" using coprime_prime_stride[OF d1 d2] by (simp add: coprime_commute)
obtain x y where xy: "d * x = p * y + 1" using coprime_bezout_strong[OF cop] p_gt1 by auto
have one: "(x * d) mod p = 1"
by (metis mod_less mult.commute p_gt1 pymod xy)
with one show ?thesis by auto
qed
lemma t01_in_stride_generate:
assumes "0 < d" "d < p"
shows "Transposition.transpose 0 1 ∈ Group.generate (Sn p) (∘) id {ncycle p, Transposition.transpose 0 d}"
by (metis assms stride_reaches_one stride_walk)
text ‹The cycle and a stride-@{term d} transposition generate @{term "Sn p"}.›
theorem Sn_generated_cycle_transpose_0d:
fixes d :: nat
assumes d1: "0 < d" and d2: "d < p"
shows "Group.generate (Sn p) (∘) id {ncycle p, Transposition.transpose 0 d} = Sn p"
proof
have nc: "ncycle p ∈ G.generate {ncycle p, Transposition.transpose 0 d}"
using ncycle_in_Sn by (intro G.generate.incl) simp
have sub: "G.generate {Transposition.transpose 0 1, ncycle p} ⊆ G.generate {ncycle p, Transposition.transpose 0 d}"
using t01_in_stride_generate[OF d1 d2] nc
by (intro G.generate_minimal G.generate_is_subgroup) auto
then show "Sn p ⊆ G.generate {ncycle p, Transposition.transpose 0 d}"
using Sn_generated_canonical[OF p_gt1] by simp
qed (use G.generate_subset_carrier in simp)
lemma sum_pa_bounds:
fixes a b :: nat
assumes "a < p" "b < p" "a ≠ b"
shows "0 < (b + (p - a)) mod p"
proof (rule ccontr)
have *: "0 < b + (p - a)" "b + (p - a) < 2 * p" "b + (p - a) ≠ p" using assms
by auto
assume "¬ 0 < (b + (p - a)) mod p"
then obtain k where "b + (p - a) = p * k" by (auto simp: dvd_def)
with * show False by auto
qed
text ‹The main result of this section: for prime @{term p}, the standard @{term p}-cycle and
∗‹any› transposition generate @{term "Sn p"}.›
theorem Sn_generated_ncycle_transpose:
fixes a b :: nat
assumes a: "a < p" and b: "b < p" and ab: "a ≠ b"
shows "Group.generate (Sn p) (∘) id {ncycle p, Transposition.transpose a b} = Sn p"
proof
define d where "d ≡ (b + (p - a)) mod p"
obtain d: "0 < d" "d < p" unfolding d_def using p_gt1
using a ab b sum_pa_bounds by (metis mod_less_divisor not_gr0 not_less0)
have t0d: "Transposition.transpose 0 d ∈ G.generate {ncycle p, Transposition.transpose a b}"
using ncycle_conj_transpose_in_generate[OF a b p_gt1, of "p - a"] a d_def by auto
have nc: "ncycle p ∈ G.generate {ncycle p, Transposition.transpose a b}"
using ncycle_in_Sn by (intro G.generate.incl) simp
have sub: "G.generate {ncycle p, Transposition.transpose 0 d} ⊆ G.generate {ncycle p, Transposition.transpose a b}"
using t0d nc by (intro G.generate_minimal G.generate_is_subgroup) auto
then show "Sn p ⊆ G.generate {ncycle p, Transposition.transpose a b}"
using Sn_generated_cycle_transpose_0d[OF d] by simp
qed (use G.generate_subset_carrier in simp)
subsection ‹An arbitrary cycle and transposition generate ‹S⇩p››
text ‹In @{term "Sn n"} the group conjugation specialises to the familiar
@{term "g ∘ x ∘ inv g"}.›
lemma Sn_conjugation_eq:
assumes g: "g ∈ Sn n" and x: "x ∈ Sn n"
shows "Group.conjugation (Sn n) (∘) id g x = g ∘ x ∘ inv g"
by (simp add: Group.conjugation_def Group_Sn Sn_inverse_eq g x)
text ‹Transporting @{thm [source] Sn_generated_ncycle_transpose} along conjugacy: for prime
@{term p}, ∗‹any› conjugate @{term "q ∘ ncycle p ∘ inv q"} of the standard @{term p}-cycle,
together with the conjugate @{term "q ∘ transpose a b ∘ inv q"} of a transposition, generates
@{term "Sn p"}.›
lemma Sn_generated_conj_cycle_transpose:
fixes q :: "nat ⇒ nat" and a b :: nat
assumes q: "q ∈ Sn p" and a: "a < p" and b: "b < p" and ab: "a ≠ b"
shows "Group.generate (Sn p) (∘) id
{q ∘ ncycle p ∘ inv q, q ∘ Transposition.transpose a b ∘ inv q} = Sn p"
proof -
interpret G: Group "Sn p" "(∘)" id by (rule Group_Sn)
have qp: "q permutes {0..<p}" using q by (simp add: Sn_def)
define S where "S = {ncycle p, Transposition.transpose a b}"
have genS: "G.generate S = Sn p"
unfolding S_def by (rule Sn_generated_ncycle_transpose[OF a b ab])
have SsubSn: "S ⊆ Sn p"
unfolding S_def using ncycle_in_Sn a b by (auto simp: Sn_def permutes_swap_id)
have "G.generate {q ∘ ncycle p ∘ inv q, q ∘ Transposition.transpose a b ∘ inv q}
= G.conjugation q ` G.generate S"
using G.conjugation_generate_eq[OF q] G.conjugation_def S_def Sn_inverse_eq SsubSn q by force
also have "… = Sn p" using G.conjugation_bij[OF q] by (simp add: genS bij_betw_imp_surj_on)
finally show ?thesis .
qed
subsection ‹An order-‹p› element of ‹S⇩p› is a ‹p›-cycle›
text ‹The combinatorial counterpart of the previous result: every element of @{term "Sn p"}
of order @{term p} (for @{term p} prime) is conjugate to the standard cycle, hence is itself
a @{term p}-cycle. Together with @{thm [source] Sn_generated_conj_cycle_transpose} this lets
Cauchy's theorem (which only yields ∗‹some› order-@{term p} element) feed the generation
argument for the quintic.›
text ‹Iterating @{term g} is periodic with period dividing @{term n} once @{term "g ^^ n = id"}.›
lemma funpow_mod_period:
assumes "(g ^^ n) = id"
shows "(g ^^ (k mod n)) = (g ^^ k)"
by (metis (no_types, lifting) ext assms funpow_mod_eq id_apply)
text ‹If @{term g} has order @{term p} (prime) and moves @{term x}, then no smaller positive
power fixes @{term x}: the only powers fixing @{term x} are the multiples of @{term p}.›
lemma cycle_period_prime:
assumes p: "prime p" and gp: "(g ^^ p) = id" and gx: "g x ≠ x"
and d: "(g ^^ d) x = x"
shows "d mod p = 0"
proof (rule ccontr)
assume "d mod p ≠ 0"
have dmod: "(g ^^ (d mod p)) x = x"
using funpow_mod_period[OF gp, of d] d by simp
obtain k where k: "(k * (d mod p)) mod p = 1"
using ‹d mod p ≠ 0› p stride_reaches_one
by (meson mod_less_divisor not_gr_zero prime_gt_0_nat)
then have "(g ^^ ((k * (d mod p)) mod p)) x = x"
using funpow_mod_period[OF gp] by (metis dmod funpow_mod_eq mod_mult_self2_is_0 mod_self)
with gx show False using k by simp
qed
text ‹The conjugator: the map sending @{term i} to @{term "(g ^^ i) x"} on @{term "{0..<p}"}
and fixing the rest.›
definition qmap :: "(nat ⇒ nat) ⇒ nat ⇒ nat ⇒ nat"
where "qmap g x i = (if i < p then (g ^^ i) x else i)"
context
fixes g :: "nat ⇒ nat" and x :: nat
assumes gSn: "g ∈ Sn p" and gp: "(g ^^ p) = id"
and gx: "g x ≠ x" and xp: "x < p"
begin
lemma g_funpow_lt: "i < p ⟹ (g ^^ i) x < p"
using gSn permutes_in_funpow_image xp by (fastforce simp: Sn_def permutes_funpow)
lemma qmap_inj_aux:
assumes ij: "i < p" "j < p" "i ≤ j" and eq: "(g ^^ i) x = (g ^^ j) x"
shows "i = j"
proof -
have bij_i: "bij (g ^^ i)" using Sn_def gSn permutes_bij by fastforce
have "(g ^^ i) x = (g ^^ i) ((g ^^ (j - i)) x)"
by (metis Sn_iff bij_betw_def eq funpow_diff gSn ij(3) permutes_bij)
then have "(j - i) mod p = 0"
using cycle_period_prime[OF p gp gx] by (simp add: bij_i bij_is_inj inj_eq)
then show "i = j" using ij by auto
qed
lemma qmap_inj_on: "inj_on (qmap g x) {0..<p}"
proof (rule inj_onI)
fix i j assume "i ∈ {0..<p}" "j ∈ {0..<p}" "qmap g x i = qmap g x j"
then have "i < p" "j < p" "(g ^^ i) x = (g ^^ j) x"
by (auto simp: qmap_def)
then show "i = j"
by (metis nat_le_linear qmap_inj_aux)
qed
lemma qmap_image: "qmap g x ` {0..<p} = {0..<p}"
proof (rule endo_inj_surj)
show "finite {0..<p}" by simp
show "qmap g x ` {0..<p} ⊆ {0..<p}" using g_funpow_lt by (auto simp: qmap_def)
show "inj_on (qmap g x) {0..<p}" by (rule qmap_inj_on)
qed
lemma qmap_permutes: "qmap g x permutes {0..<p}"
using qmap_inj_on qmap_image
by (intro bij_imp_permutes) (auto simp: bij_betw_def qmap_def)
lemma qmap_in_Sn: "qmap g x ∈ Sn p"
using qmap_permutes by (simp add: Sn_def)
lemma g_qmap_eq:
assumes "i < p"
shows "g (qmap g x i) = qmap g x (ncycle p i)"
using funpow_mod_period[OF gp, of "Suc i"] assms by (simp add: qmap_def ncycle_def)
lemma g_comp_qmap: "g ∘ qmap g x = qmap g x ∘ ncycle p"
using g_qmap_eq gSn by (auto simp: Sn_def permutes_def ncycle_def qmap_def)
lemma g_conj_ncycle: "g = qmap g x ∘ ncycle p ∘ inv (qmap g x)"
by (metis comp_assoc comp_id g_comp_qmap permutes_inv_o(1) qmap_permutes)
end
theorem order_p_elt_conj_ncycle:
fixes g :: "nat ⇒ nat"
assumes gSn: "g ∈ Sn p" and gp: "(g ^^ p) = id" and gne: "g ≠ id"
shows "∃q ∈ Sn p. g = q ∘ ncycle p ∘ inv q"
proof -
obtain x where x: "g x ≠ x" using gne by (auto simp: fun_eq_iff)
with gSn have xp: "x < p"
by (auto simp: Sn_def permutes_def)
show ?thesis
using gSn g_conj_ncycle gp qmap_in_Sn x xp by blast
qed
text ‹The same conclusion phrased through the group's @{const Monoid.element_order}: an element
of @{term "Sn p"} of order @{term p} is a conjugate of the standard cycle.›
theorem order_p_elt_conj_ncycle_order:
fixes g :: "nat ⇒ nat"
assumes gSn: "g ∈ Sn p"
and ord: "Monoid.element_order (∘) id g = p"
shows "∃q ∈ Sn p. g = q ∘ ncycle p ∘ inv q"
proof -
have gp: "(g ^^ p) = id"
using G.power_element_order Sn_power_funpow finite_Sn gSn ord by force
have gne: "g ≠ id"
using ord p by force
show ?thesis by (rule order_p_elt_conj_ncycle[OF gSn gp gne])
qed
end
end