diff options
| author | Enrico Tassi | 2015-03-09 11:07:53 +0100 |
|---|---|---|
| committer | Enrico Tassi | 2015-03-09 11:24:38 +0100 |
| commit | fc84c27eac260dffd8f2fb1cb56d599f1e3486d9 (patch) | |
| tree | c16205f1637c80833a4c4598993c29fa0fd8c373 /mathcomp/fingroup/action.v | |
Initial commit
Diffstat (limited to 'mathcomp/fingroup/action.v')
| -rw-r--r-- | mathcomp/fingroup/action.v | 2719 |
1 files changed, 2719 insertions, 0 deletions
diff --git a/mathcomp/fingroup/action.v b/mathcomp/fingroup/action.v new file mode 100644 index 0000000..902e9ca --- /dev/null +++ b/mathcomp/fingroup/action.v @@ -0,0 +1,2719 @@ +(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *) +Require Import ssreflect ssrbool ssrfun eqtype ssrnat div seq fintype. +Require Import bigop finset fingroup morphism perm automorphism quotient. + +(******************************************************************************) +(* Group action: orbits, stabilisers, transitivity. *) +(* is_action D to == the function to : T -> aT -> T defines an action *) +(* of D : {set aT} on T. *) +(* action D T == structure for a function defining an action of D. *) +(* act_dom to == the domain D of to : action D rT. *) +(* {action: aT &-> T} == structure for a total action. *) +(* := action [set: aT] T *) +(* TotalAction to1 toM == the constructor for total actions; to1 and toM *) +(* are the proofs of the action identities for 1 and *) +(* a * b, respectively. *) +(* is_groupAction R to == to is a group action on range R: for all a in D, *) +(* the permutation induced by to a is in Aut R. Thus *) +(* the action of D must be trivial outside R. *) +(* groupAction D R == the structure for group actions of D on R. This *) +(* is a telescope on action D rT. *) +(* gact_range to == the range R of to : groupAction D R. *) +(* GroupAction toAut == construct a groupAction for action to from *) +(* toAut : actm to @* D \subset Aut R (actm to is *) +(* the morphism to {perm rT} associated to 'to'). *) +(* orbit to A x == the orbit of x under the action of A via to. *) +(* orbit_transversal to A S == a transversal of the partition orbit to A @: S *) +(* of S, provided A acts on S via to. *) +(* amove to A x y == the set of a in A whose action send x to y. *) +(* 'C_A[x | to] == the stabiliser of x : rT in A :&: D. *) +(* 'C_A(S | to) == the point-wise stabiliser of S : {set rT} in D :&: A. *) +(* 'N_A(S | to) == the global stabiliser of S : {set rT} in D :&: A. *) +(* 'Fix_(S | to)[a] == the set of fixpoints of a in S. *) +(* 'Fix_(S | to)(A) == the set of fixpoints of A in S. *) +(* In the first three _A can be omitted and defaults to the domain D of to; *) +(* In the last two S can be omitted and defaults to [set: T], so 'Fix_to[a] *) +(* is the set of all fixpoints of a. *) +(* The domain restriction ensures that stabilisers have a canonical group *) +(* structure, but note that 'Fix sets are generally not groups. Indeed, we *) +(* provide alternative definitions when to is a group action on R: *) +(* 'C_(G | to)(A) == the centraliser in R :&: G of the group action of *) +(* D :&: A via to *) +(* 'C_(G | to)[a] == the centraliser in R :&: G of a \in D, via to. *) +(* These sets are groups when G is. G can be omitted: 'C(|to)(A) is the *) +(* centraliser in R of the action of D :&: A via to. *) +(* [acts A, on S | to] == A \subset D acts on the set S via to. *) +(* {acts A, on S | to} == A acts on the set S (Prop statement). *) +(* {acts A, on group G | to} == [acts A, on S | to] /\ G \subset R, i.e., *) +(* A \subset D acts on G \subset R, via *) +(* to : groupAction D R. *) +(* [transitive A, on S | to] == A acts transitively on S. *) +(* [faithful A, on S | to] == A acts faithfully on S. *) +(* acts_irreducibly to A G == A acts irreducibly via the groupAction to *) +(* on the nontrivial group G, i.e., A does *) +(* not act on any nontrivial subgroup of G. *) +(* Important caveat: the definitions of orbit, amove, 'Fix_(S | to)(A), *) +(* transitive and faithful assume that A is a subset of the domain D. As most *) +(* of the permutation actions we consider are total this is usually harmless. *) +(* (Note that the theory of partial actions is only partially developed.) *) +(* In all of the above, to is expected to be the actual action structure, *) +(* not merely the function. There is a special scope %act for actions, and *) +(* constructions and notations for many classical actions: *) +(* 'P == natural action of a permutation group via aperm. *) +(* 'J == internal group action (conjugation) via conjg (_ ^ _). *) +(* 'R == regular group action (right translation) via mulg (_ * _). *) +(* (but, to limit ambiguity, _ * _ is NOT a canonical action) *) +(* to^* == the action induced by to on {set rT} via to^* (== setact to). *) +(* 'Js == the internal action on subsets via _ :^ _, equivalent to 'J^*. *) +(* 'Rs == the regular action on subsets via rcoset, equivalent to 'R^*. *) +(* 'JG == the conjugation action on {group rT} via (_ :^ _)%G. *) +(* to / H == the action induced by to on coset_of H via qact to H, and *) +(* restricted to qact_dom to H == 'N(rcosets H 'N(H) | to^* ). *) +(* 'Q == the action induced to cosets by conjugation; the domain is *) +(* qact_dom 'J H, which is provably equal to 'N(H). *) +(* to %% A == the action of coset_of A via modact to A, with domain D / A *) +(* and support restricted to 'C(D :&: A | to). *) +(* to \ sAD == the action of A via ract to sAD == to, if sAD : A \subset D. *) +(* [Aut G] == the permutation action restricted to Aut G, via autact G. *) +(* <[nRA]> == the action of A on R via actby nRA == to in A and on R, and *) +(* the trivial action elsewhere; here nRA : [acts A, on R | to] *) +(* or nRA : {acts A, on group R | to}. *) +(* to^? == the action induced by to on sT : @subType rT P, via subact to *) +(* with domain subact_dom P to == 'N([set x | P x] | to). *) +(* <<phi>> == the action of phi : D >-> {perm rT}, via mact phi. *) +(* to \o f == the composite action (with domain f @*^-1 D) of the action to *) +(* with f : {morphism G >-> aT}, via comp_act to f. Here f must *) +(* be the actual morphism object (e.g., coset_morphism H), not *) +(* the underlying function (e.g., coset H). *) +(* The explicit application of an action to is usually written (to%act x a), *) +(* where the %act omitted if to is an abstract action or a set action to0^*. *) +(* Note that this form will simplify and expose the acting function. *) +(* There is a %gact scope for group actions; the notations above are *) +(* recognised in %gact when they denote canonical group actions. *) +(* Actions can be used to define morphisms: *) +(* actperm to == the morphism D >-> {perm rT} induced by to. *) +(* actm to a == if a \in D the function on D induced by the action to, else *) +(* the identity function. If to is a group action with range R *) +(* then actm to a is canonically a morphism on R. *) +(* We also define here the restriction operation on permutations (the domain *) +(* of this operations is a stabiliser), and local automorphpism groups: *) +(* restr_perm S p == if p acts on S, the permutation with support in S that *) +(* coincides with p on S; else the identity. Note that *) +(* restr_perm is a permutation group morphism that maps *) +(* Aut G to Aut S when S is a subgroup of G. *) +(* Aut_in A G == the local permutation group 'N_A(G | 'P) / 'C_A(G | 'P) *) +(* Usually A is an automorphism group, and then Aut_in A G *) +(* is isomorphic to a subgroup of Aut G, specifically *) +(* restr_perm @* A. *) +(* Finally, gproduct.v will provide a semi-direct group construction that *) +(* maps an external group action to an internal one; the theory of morphisms *) +(* between such products makes use of the following definition: *) +(* morph_act to to' f fA <=> the action of to' on the images of f and fA is *) +(* the image of the action of to, i.e., for all x and a we *) +(* have f (to x a) = to' (f x) (fA a). Note that there is *) +(* no mention of the domains of to and to'; if needed, this *) +(* predicate should be restricted via the {in ...} notation *) +(* and domain conditions should be added. *) +(******************************************************************************) + +Set Implicit Arguments. +Unset Strict Implicit. +Unset Printing Implicit Defensive. + +Import GroupScope. + +Section ActionDef. + +Variables (aT : finGroupType) (D : {set aT}) (rT : Type). +Implicit Types a b : aT. +Implicit Type x : rT. + +Definition act_morph to x := forall a b, to x (a * b) = to (to x a) b. + +Definition is_action to := + left_injective to /\ forall x, {in D &, act_morph to x}. + +Record action := Action {act :> rT -> aT -> rT; _ : is_action act}. + +Definition clone_action to := + let: Action _ toP := to return {type of Action for to} -> action in + fun k => k toP. + +End ActionDef. + +(* Need to close the Section here to avoid re-declaring all Argument Scopes *) +Delimit Scope action_scope with act. +Bind Scope action_scope with action. +Arguments Scope act_morph [_ group_scope _ _ group_scope]. +Arguments Scope is_action [_ group_scope _ _]. +Arguments Scope act + [_ group_scope type_scope action_scope group_scope group_scope]. +Arguments Scope clone_action [_ group_scope type_scope action_scope _]. + +Notation "{ 'action' aT &-> T }" := (action [set: aT] T) + (at level 0, format "{ 'action' aT &-> T }") : type_scope. + +Notation "[ 'action' 'of' to ]" := (clone_action (@Action _ _ _ to)) + (at level 0, format "[ 'action' 'of' to ]") : form_scope. + +Definition act_dom aT D rT of @action aT D rT := D. + +Section TotalAction. + +Variables (aT : finGroupType) (rT : Type) (to : rT -> aT -> rT). +Hypotheses (to1 : to^~ 1 =1 id) (toM : forall x, act_morph to x). + +Lemma is_total_action : is_action setT to. +Proof. +split=> [a | x a b _ _] /=; last by rewrite toM. +by apply: can_inj (to^~ a^-1) _ => x; rewrite -toM ?mulgV. +Qed. + +Definition TotalAction := Action is_total_action. + +End TotalAction. + +Section ActionDefs. + +Variables (aT aT' : finGroupType) (D : {set aT}) (D' : {set aT'}). + +Definition morph_act rT rT' (to : action D rT) (to' : action D' rT') f fA := + forall x a, f (to x a) = to' (f x) (fA a). + +Variable rT : finType. (* Most definitions require a finType structure on rT *) +Implicit Type to : action D rT. +Implicit Type A : {set aT}. +Implicit Type S : {set rT}. + +Definition actm to a := if a \in D then to^~ a else id. + +Definition setact to S a := [set to x a | x in S]. + +Definition orbit to A x := to x @: A. + +Definition amove to A x y := [set a in A | to x a == y]. + +Definition afix to A := [set x | A \subset [set a | to x a == x]]. + +Definition astab S to := D :&: [set a | S \subset [set x | to x a == x]]. + +Definition astabs S to := D :&: [set a | S \subset to^~ a @^-1: S]. + +Definition acts_on A S to := {in A, forall a x, (to x a \in S) = (x \in S)}. + +Definition atrans A S to := S \in orbit to A @: S. + +Definition faithful A S to := A :&: astab S to \subset [1]. + +End ActionDefs. + +Arguments Scope setact [_ group_scope _ action_scope group_scope group_scope]. +Arguments Scope orbit [_ group_scope _ action_scope group_scope group_scope]. +Arguments Scope amove + [_ group_scope _ action_scope group_scope group_scope group_scope]. +Arguments Scope afix [_ group_scope _ action_scope group_scope]. +Arguments Scope astab [_ group_scope _ group_scope action_scope]. +Arguments Scope astabs [_ group_scope _ group_scope action_scope]. +Arguments Scope acts_on [_ group_scope _ group_scope group_scope action_scope]. +Arguments Scope atrans [_ group_scope _ group_scope group_scope action_scope]. +Arguments Scope faithful [_ group_scope _ group_scope group_scope action_scope]. + +Notation "to ^*" := (setact to) (at level 2, format "to ^*") : fun_scope. + +Prenex Implicits orbit amove. + +Notation "''Fix_' to ( A )" := (afix to A) + (at level 8, to at level 2, format "''Fix_' to ( A )") : group_scope. + +(* camlp4 grammar factoring *) +Notation "''Fix_' ( to ) ( A )" := 'Fix_to(A) + (at level 8, only parsing) : group_scope. + +Notation "''Fix_' ( S | to ) ( A )" := (S :&: 'Fix_to(A)) + (at level 8, format "''Fix_' ( S | to ) ( A )") : group_scope. + +Notation "''Fix_' to [ a ]" := ('Fix_to([set a])) + (at level 8, to at level 2, format "''Fix_' to [ a ]") : group_scope. + +Notation "''Fix_' ( S | to ) [ a ]" := (S :&: 'Fix_to[a]) + (at level 8, format "''Fix_' ( S | to ) [ a ]") : group_scope. + +Notation "''C' ( S | to )" := (astab S to) + (at level 8, format "''C' ( S | to )") : group_scope. + +Notation "''C_' A ( S | to )" := (A :&: 'C(S | to)) + (at level 8, A at level 2, format "''C_' A ( S | to )") : group_scope. +Notation "''C_' ( A ) ( S | to )" := 'C_A(S | to) + (at level 8, only parsing) : group_scope. + +Notation "''C' [ x | to ]" := ('C([set x] | to)) + (at level 8, format "''C' [ x | to ]") : group_scope. + +Notation "''C_' A [ x | to ]" := (A :&: 'C[x | to]) + (at level 8, A at level 2, format "''C_' A [ x | to ]") : group_scope. +Notation "''C_' ( A ) [ x | to ]" := 'C_A[x | to] + (at level 8, only parsing) : group_scope. + +Notation "''N' ( S | to )" := (astabs S to) + (at level 8, format "''N' ( S | to )") : group_scope. + +Notation "''N_' A ( S | to )" := (A :&: 'N(S | to)) + (at level 8, A at level 2, format "''N_' A ( S | to )") : group_scope. + +Notation "[ 'acts' A , 'on' S | to ]" := (A \subset pred_of_set 'N(S | to)) + (at level 0, format "[ 'acts' A , 'on' S | to ]") : form_scope. + +Notation "{ 'acts' A , 'on' S | to }" := (acts_on A S to) + (at level 0, format "{ 'acts' A , 'on' S | to }") : form_scope. + +Notation "[ 'transitive' A , 'on' S | to ]" := (atrans A S to) + (at level 0, format "[ 'transitive' A , 'on' S | to ]") : form_scope. + +Notation "[ 'faithful' A , 'on' S | to ]" := (faithful A S to) + (at level 0, format "[ 'faithful' A , 'on' S | to ]") : form_scope. + +Section RawAction. +(* Lemmas that do not require the group structure on the action domain. *) +(* Some lemmas like actMin would be actually be valid for arbitrary rT, *) +(* e.g., for actions on a function type, but would be difficult to use *) +(* as a view due to the confusion between parameters and assumptions. *) + +Variables (aT : finGroupType) (D : {set aT}) (rT : finType) (to : action D rT). + +Implicit Types (a : aT) (x y : rT) (A B : {set aT}) (S T : {set rT}). + +Lemma act_inj : left_injective to. Proof. by case: to => ? []. Qed. +Implicit Arguments act_inj []. + +Lemma actMin x : {in D &, act_morph to x}. +Proof. by case: to => ? []. Qed. + +Lemma actmEfun a : a \in D -> actm to a = to^~ a. +Proof. by rewrite /actm => ->. Qed. + +Lemma actmE a : a \in D -> actm to a =1 to^~ a. +Proof. by move=> Da; rewrite actmEfun. Qed. + +Lemma setactE S a : to^* S a = [set to x a | x in S]. +Proof. by []. Qed. + +Lemma mem_setact S a x : x \in S -> to x a \in to^* S a. +Proof. exact: mem_imset. Qed. + +Lemma card_setact S a : #|to^* S a| = #|S|. +Proof. by apply: card_imset; exact: act_inj. Qed. + +Lemma setact_is_action : is_action D to^*. +Proof. +split=> [a R S eqRS | a b Da Db S]; last first. + rewrite /setact /= -imset_comp; apply: eq_imset => x; exact: actMin. +apply/setP=> x; apply/idP/idP=> /(mem_setact a). + by rewrite eqRS => /imsetP[y Sy /act_inj->]. +by rewrite -eqRS => /imsetP[y Sy /act_inj->]. +Qed. + +Canonical set_action := Action setact_is_action. + +Lemma orbitE A x : orbit to A x = to x @: A. Proof. by []. Qed. + +Lemma orbitP A x y : + reflect (exists2 a, a \in A & to x a = y) (y \in orbit to A x). +Proof. by apply: (iffP imsetP) => [] [a]; exists a. Qed. + +Lemma mem_orbit A x a : a \in A -> to x a \in orbit to A x. +Proof. exact: mem_imset. Qed. + +Lemma afixP A x : reflect (forall a, a \in A -> to x a = x) (x \in 'Fix_to(A)). +Proof. +rewrite inE; apply: (iffP subsetP) => [xfix a /xfix | xfix a Aa]. + by rewrite inE => /eqP. +by rewrite inE xfix. +Qed. + +Lemma afixS A B : A \subset B -> 'Fix_to(B) \subset 'Fix_to(A). +Proof. by move=> sAB; apply/subsetP=> u; rewrite !inE; exact: subset_trans. Qed. + +Lemma afixU A B : 'Fix_to(A :|: B) = 'Fix_to(A) :&: 'Fix_to(B). +Proof. by apply/setP=> x; rewrite !inE subUset. Qed. + +Lemma afix1P a x : reflect (to x a = x) (x \in 'Fix_to[a]). +Proof. by rewrite inE sub1set inE; exact: eqP. Qed. + +Lemma astabIdom S : 'C_D(S | to) = 'C(S | to). +Proof. by rewrite setIA setIid. Qed. + +Lemma astab_dom S : {subset 'C(S | to) <= D}. +Proof. by move=> a /setIP[]. Qed. + +Lemma astab_act S a x : a \in 'C(S | to) -> x \in S -> to x a = x. +Proof. +rewrite 2!inE => /andP[_ cSa] Sx; apply/eqP. +by have:= subsetP cSa x Sx; rewrite inE. +Qed. + +Lemma astabS S1 S2 : S1 \subset S2 -> 'C(S2 | to) \subset 'C(S1 | to). +Proof. +move=> sS12; apply/subsetP=> x; rewrite !inE => /andP[->]. +exact: subset_trans. +Qed. + +Lemma astabsIdom S : 'N_D(S | to) = 'N(S | to). +Proof. by rewrite setIA setIid. Qed. + +Lemma astabs_dom S : {subset 'N(S | to) <= D}. +Proof. by move=> a /setIdP[]. Qed. + +Lemma astabs_act S a x : a \in 'N(S | to) -> (to x a \in S) = (x \in S). +Proof. +rewrite 2!inE subEproper properEcard => /andP[_]. +rewrite (card_preimset _ (act_inj _)) ltnn andbF orbF => /eqP{2}->. +by rewrite inE. +Qed. + +Lemma astab_sub S : 'C(S | to) \subset 'N(S | to). +Proof. +apply/subsetP=> a cSa; rewrite !inE (astab_dom cSa). +by apply/subsetP=> x Sx; rewrite inE (astab_act cSa). +Qed. + +Lemma astabsC S : 'N(~: S | to) = 'N(S | to). +Proof. +apply/setP=> a; apply/idP/idP=> nSa; rewrite !inE (astabs_dom nSa). + by rewrite -setCS -preimsetC; apply/subsetP=> x; rewrite inE astabs_act. +by rewrite preimsetC setCS; apply/subsetP=> x; rewrite inE astabs_act. +Qed. + +Lemma astabsI S T : 'N(S | to) :&: 'N(T | to) \subset 'N(S :&: T | to). +Proof. +apply/subsetP=> a; rewrite !inE -!andbA preimsetI => /and4P[-> nSa _ nTa] /=. +by rewrite setISS. +Qed. + +Lemma astabs_setact S a : a \in 'N(S | to) -> to^* S a = S. +Proof. +move=> nSa; apply/eqP; rewrite eqEcard card_setact leqnn andbT. +by apply/subsetP=> _ /imsetP[x Sx ->]; rewrite astabs_act. +Qed. + +Lemma astab1_set S : 'C[S | set_action] = 'N(S | to). +Proof. +apply/setP=> a; apply/idP/idP=> nSa. + case/setIdP: nSa => Da; rewrite !inE Da sub1set inE => /eqP defS. + by apply/subsetP=> x Sx; rewrite inE -defS mem_setact. +by rewrite !inE (astabs_dom nSa) sub1set inE /= astabs_setact. +Qed. + +Lemma astabs_set1 x : 'N([set x] | to) = 'C[x | to]. +Proof. +apply/eqP; rewrite eqEsubset astab_sub andbC setIS //. +by apply/subsetP=> a; rewrite ?(inE,sub1set). +Qed. + +Lemma acts_dom A S : [acts A, on S | to] -> A \subset D. +Proof. by move=> nSA; rewrite (subset_trans nSA) ?subsetIl. Qed. + +Lemma acts_act A S : [acts A, on S | to] -> {acts A, on S | to}. +Proof. by move=> nAS a Aa x; rewrite astabs_act ?(subsetP nAS). Qed. + +Lemma astabCin A S : + A \subset D -> (A \subset 'C(S | to)) = (S \subset 'Fix_to(A)). +Proof. +move=> sAD; apply/subsetP/subsetP=> [sAC x xS | sSF a aA]. + by apply/afixP=> a aA; exact: astab_act (sAC _ aA) xS. +rewrite !inE (subsetP sAD _ aA); apply/subsetP=> x xS. +by move/afixP/(_ _ aA): (sSF _ xS); rewrite inE => ->. +Qed. + +Section ActsSetop. + +Variables (A : {set aT}) (S T : {set rT}). +Hypotheses (AactS : [acts A, on S | to]) (AactT : [acts A, on T | to]). + +Lemma astabU : 'C(S :|: T | to) = 'C(S | to) :&: 'C(T | to). +Proof. by apply/setP=> a; rewrite !inE subUset; case: (a \in D). Qed. + +Lemma astabsU : 'N(S | to) :&: 'N(T | to) \subset 'N(S :|: T | to). +Proof. +by rewrite -(astabsC S) -(astabsC T) -(astabsC (S :|: T)) setCU astabsI. +Qed. + +Lemma astabsD : 'N(S | to) :&: 'N(T | to) \subset 'N(S :\: T| to). +Proof. by rewrite setDE -(astabsC T) astabsI. Qed. + +Lemma actsI : [acts A, on S :&: T | to]. +Proof. by apply: subset_trans (astabsI S T); rewrite subsetI AactS. Qed. + +Lemma actsU : [acts A, on S :|: T | to]. +Proof. by apply: subset_trans astabsU; rewrite subsetI AactS. Qed. + +Lemma actsD : [acts A, on S :\: T | to]. +Proof. by apply: subset_trans astabsD; rewrite subsetI AactS. Qed. + +End ActsSetop. + +Lemma acts_in_orbit A S x y : + [acts A, on S | to] -> y \in orbit to A x -> x \in S -> y \in S. +Proof. +by move=> nSA/imsetP[a Aa ->{y}] Sx; rewrite (astabs_act _ (subsetP nSA a Aa)). +Qed. + +Lemma subset_faithful A B S : + B \subset A -> [faithful A, on S | to] -> [faithful B, on S | to]. +Proof. by move=> sAB; apply: subset_trans; exact: setSI. Qed. + +Section Reindex. + +Variables (vT : Type) (idx : vT) (op : Monoid.com_law idx) (S : {set rT}). + +Lemma reindex_astabs a F : a \in 'N(S | to) -> + \big[op/idx]_(i in S) F i = \big[op/idx]_(i in S) F (to i a). +Proof. +move=> nSa; rewrite (reindex_inj (act_inj a)); apply: eq_bigl => x. +exact: astabs_act. +Qed. + +Lemma reindex_acts A a F : [acts A, on S | to] -> a \in A -> + \big[op/idx]_(i in S) F i = \big[op/idx]_(i in S) F (to i a). +Proof. by move=> nSA /(subsetP nSA); exact: reindex_astabs. Qed. + +End Reindex. + +End RawAction. + +(* Warning: this directive depends on names of bound variables in the *) +(* definition of injective, in ssrfun.v. *) +Implicit Arguments act_inj [[aT] [D] [rT] x1 x2]. + +Notation "to ^*" := (set_action to) : action_scope. + +Implicit Arguments orbitP [aT D rT to A x y]. +Implicit Arguments afixP [aT D rT to A x]. +Implicit Arguments afix1P [aT D rT to a x]. +Prenex Implicits orbitP afixP afix1P. + +Implicit Arguments reindex_astabs [aT D rT vT idx op S F]. +Implicit Arguments reindex_acts [aT D rT vT idx op S A a F]. + +Section PartialAction. +(* Lemmas that require a (partial) group domain. *) + +Variables (aT : finGroupType) (D : {group aT}) (rT : finType). +Variable to : action D rT. + +Implicit Types a : aT. +Implicit Types x y : rT. +Implicit Types A B : {set aT}. +Implicit Types G H : {group aT}. +Implicit Types S : {set rT}. + +Lemma act1 x : to x 1 = x. +Proof. by apply: (act_inj to 1); rewrite -actMin ?mulg1. Qed. + +Lemma actKin : {in D, right_loop invg to}. +Proof. by move=> a Da /= x; rewrite -actMin ?groupV // mulgV act1. Qed. + +Lemma actKVin : {in D, rev_right_loop invg to}. +Proof. by move=> a Da /= x; rewrite -{2}(invgK a) actKin ?groupV. Qed. + +Lemma setactVin S a : a \in D -> to^* S a^-1 = to^~ a @^-1: S. +Proof. +by move=> Da; apply: can2_imset_pre; [exact: actKVin | exact: actKin]. +Qed. + +Lemma actXin x a i : a \in D -> to x (a ^+ i) = iter i (to^~ a) x. +Proof. +move=> Da; elim: i => /= [|i <-]; first by rewrite act1. +by rewrite expgSr actMin ?groupX. +Qed. + +Lemma afix1 : 'Fix_to(1) = setT. +Proof. by apply/setP=> x; rewrite !inE sub1set inE act1 eqxx. Qed. + +Lemma afixD1 G : 'Fix_to(G^#) = 'Fix_to(G). +Proof. by rewrite -{2}(setD1K (group1 G)) afixU afix1 setTI. Qed. + +Lemma orbit_refl G x : x \in orbit to G x. +Proof. by rewrite -{1}[x]act1 mem_orbit. Qed. + +Local Notation orbit_rel A := (fun x y => y \in orbit to A x). + +Lemma contra_orbit G x y : x \notin orbit to G y -> x != y. +Proof. by apply: contraNneq => ->; exact: orbit_refl. Qed. + +Lemma orbit_in_sym G : G \subset D -> symmetric (orbit_rel G). +Proof. +move=> sGD; apply: symmetric_from_pre => x y /imsetP[a Ga]. +by move/(canLR (actKin (subsetP sGD a Ga))) <-; rewrite mem_orbit ?groupV. +Qed. + +Lemma orbit_in_trans G : G \subset D -> transitive (orbit_rel G). +Proof. +move=> sGD _ x _ /imsetP[a Ga ->] /imsetP[b Gb ->]. +by rewrite -actMin ?mem_orbit ?groupM // (subsetP sGD). +Qed. + +Lemma orbit_in_transl G x y : + G \subset D -> y \in orbit to G x -> orbit to G y = orbit to G x. +Proof. +move=> sGD Gxy; apply/setP=> z. +by apply/idP/idP; apply: orbit_in_trans; rewrite // orbit_in_sym. +Qed. + +Lemma orbit_in_transr G x y z : + G \subset D -> y \in orbit to G x -> + (y \in orbit to G z) = (x \in orbit to G z). +Proof. +by move=> sGD Gxy; rewrite !(orbit_in_sym _ z) ?(orbit_in_transl _ Gxy). +Qed. + +Lemma orbit_act_in x a G : + G \subset D -> a \in G -> orbit to G (to x a) = orbit to G x. +Proof. by move=> sGD /mem_orbit/orbit_in_transl->. Qed. + +Lemma orbit_actr_in x a G y : + G \subset D -> a \in G -> (to y a \in orbit to G x) = (y \in orbit to G x). +Proof. by move=> sGD /mem_orbit/orbit_in_transr->. Qed. + +Lemma orbit_inv_in A x y : + A \subset D -> (y \in orbit to A^-1 x) = (x \in orbit to A y). +Proof. +move/subsetP=> sAD; apply/imsetP/imsetP=> [] [a Aa ->]. + by exists a^-1; rewrite -?mem_invg ?actKin // -groupV sAD -?mem_invg. +by exists a^-1; rewrite ?memV_invg ?actKin // sAD. +Qed. + +Lemma orbit_lcoset_in A a x : + A \subset D -> a \in D -> + orbit to (a *: A) x = orbit to A (to x a). +Proof. +move/subsetP=> sAD Da; apply/setP=> y; apply/imsetP/imsetP=> [] [b Ab ->{y}]. + by exists (a^-1 * b); rewrite -?actMin ?mulKVg // ?sAD -?mem_lcoset. +by exists (a * b); rewrite ?mem_mulg ?set11 ?actMin // sAD. +Qed. + +Lemma orbit_rcoset_in A a x y : + A \subset D -> a \in D -> + (to y a \in orbit to (A :* a) x) = (y \in orbit to A x). +Proof. +move=> sAD Da; rewrite -orbit_inv_in ?mul_subG ?sub1set // invMg. +by rewrite invg_set1 orbit_lcoset_in ?inv_subG ?groupV ?actKin ?orbit_inv_in. +Qed. + +Lemma orbit_conjsg_in A a x y : + A \subset D -> a \in D -> + (to y a \in orbit to (A :^ a) (to x a)) = (y \in orbit to A x). +Proof. +move=> sAD Da; rewrite conjsgE. +by rewrite orbit_lcoset_in ?groupV ?mul_subG ?sub1set ?actKin ?orbit_rcoset_in. +Qed. + +Lemma orbit1P G x : reflect (orbit to G x = [set x]) (x \in 'Fix_to(G)). +Proof. +apply: (iffP afixP) => [xfix | xfix a Ga]. + apply/eqP; rewrite eq_sym eqEsubset sub1set -{1}[x]act1 mem_imset //=. + by apply/subsetP=> y; case/imsetP=> a Ga ->; rewrite inE xfix. +by apply/set1P; rewrite -xfix mem_imset. +Qed. + +Lemma card_orbit1 G x : #|orbit to G x| = 1%N -> orbit to G x = [set x]. +Proof. +move=> orb1; apply/eqP; rewrite eq_sym eqEcard {}orb1 cards1. +by rewrite sub1set orbit_refl. +Qed. + +Lemma orbit_partition G S : + [acts G, on S | to] -> partition (orbit to G @: S) S. +Proof. +move=> actsGS; have sGD := acts_dom actsGS. +have eqiG: {in S & &, equivalence_rel [rel x y | y \in orbit to G x]}. + by move=> x y z * /=; rewrite orbit_refl; split=> // /orbit_in_transl->. +congr (partition _ _): (equivalence_partitionP eqiG). +apply: eq_in_imset => x Sx; apply/setP=> y. +by rewrite inE /= andb_idl // => /acts_in_orbit->. +Qed. + +Definition orbit_transversal A S := transversal (orbit to A @: S) S. + +Lemma orbit_transversalP G S (P := orbit to G @: S) + (X := orbit_transversal G S) : + [acts G, on S | to] -> + [/\ is_transversal X P S, X \subset S, + {in X &, forall x y, (y \in orbit to G x) = (x == y)} + & forall x, x \in S -> exists2 a, a \in G & to x a \in X]. +Proof. +move/orbit_partition; rewrite -/P => partP. +have [/eqP defS tiP _] := and3P partP. +have trXP: is_transversal X P S := transversalP partP. +have sXS: X \subset S := transversal_sub trXP. +split=> // [x y Xx Xy /= | x Sx]. + have Sx := subsetP sXS x Xx. + rewrite -(inj_in_eq (pblock_inj trXP)) // eq_pblock ?defS //. + by rewrite (def_pblock tiP (mem_imset _ Sx)) ?orbit_refl. +have /imsetP[y Xy defxG]: orbit to G x \in pblock P @: X. + by rewrite (pblock_transversal trXP) ?mem_imset. +suffices /orbitP[a Ga def_y]: y \in orbit to G x by exists a; rewrite ?def_y. +by rewrite defxG mem_pblock defS (subsetP sXS). +Qed. + +Lemma group_set_astab S : group_set 'C(S | to). +Proof. +apply/group_setP; split=> [|a b cSa cSb]. + by rewrite !inE group1; apply/subsetP=> x _; rewrite inE act1. +rewrite !inE groupM ?(@astab_dom _ _ _ to S) //; apply/subsetP=> x Sx. +by rewrite inE actMin ?(@astab_dom _ _ _ to S) ?(astab_act _ Sx). +Qed. + +Canonical astab_group S := group (group_set_astab S). + +Lemma afix_gen_in A : A \subset D -> 'Fix_to(<<A>>) = 'Fix_to(A). +Proof. +move=> sAD; apply/eqP; rewrite eqEsubset afixS ?sub_gen //=. +by rewrite -astabCin gen_subG ?astabCin. +Qed. + +Lemma afix_cycle_in a : a \in D -> 'Fix_to(<[a]>) = 'Fix_to[a]. +Proof. by move=> Da; rewrite afix_gen_in ?sub1set. Qed. + +Lemma afixYin A B : + A \subset D -> B \subset D -> 'Fix_to(A <*> B) = 'Fix_to(A) :&: 'Fix_to(B). +Proof. by move=> sAD sBD; rewrite afix_gen_in ?afixU // subUset sAD. Qed. + +Lemma afixMin G H : + G \subset D -> H \subset D -> 'Fix_to(G * H) = 'Fix_to(G) :&: 'Fix_to(H). +Proof. +by move=> sGD sHD; rewrite -afix_gen_in ?mul_subG // genM_join afixYin. +Qed. + +Lemma sub_astab1_in A x : + A \subset D -> (A \subset 'C[x | to]) = (x \in 'Fix_to(A)). +Proof. by move=> sAD; rewrite astabCin ?sub1set. Qed. + +Lemma group_set_astabs S : group_set 'N(S | to). +Proof. +apply/group_setP; split=> [|a b cSa cSb]. + by rewrite !inE group1; apply/subsetP=> x Sx; rewrite inE act1. +rewrite !inE groupM ?(@astabs_dom _ _ _ to S) //; apply/subsetP=> x Sx. +by rewrite inE actMin ?(@astabs_dom _ _ _ to S) ?astabs_act. +Qed. + +Canonical astabs_group S := group (group_set_astabs S). + +Lemma astab_norm S : 'N(S | to) \subset 'N('C(S | to)). +Proof. +apply/subsetP=> a nSa; rewrite inE sub_conjg; apply/subsetP=> b cSb. +have [Da Db] := (astabs_dom nSa, astab_dom cSb). +rewrite mem_conjgV !inE groupJ //; apply/subsetP=> x Sx. +rewrite inE !actMin ?groupM ?groupV //. +by rewrite (astab_act cSb) ?actKVin ?astabs_act ?groupV. +Qed. + +Lemma astab_normal S : 'C(S | to) <| 'N(S | to). +Proof. by rewrite /normal astab_sub astab_norm. Qed. + +Lemma acts_sub_orbit G S x : + [acts G, on S | to] -> (orbit to G x \subset S) = (x \in S). +Proof. +move/acts_act=> GactS. +apply/subsetP/idP=> [| Sx y]; first by apply; exact: orbit_refl. +by case/orbitP=> a Ga <-{y}; rewrite GactS. +Qed. + +Lemma acts_orbit G x : G \subset D -> [acts G, on orbit to G x | to]. +Proof. +move/subsetP=> sGD; apply/subsetP=> a Ga; rewrite !inE sGD //. +apply/subsetP=> _ /imsetP[b Gb ->]. +by rewrite inE -actMin ?sGD // mem_imset ?groupM. +Qed. + +Lemma acts_subnorm_fix A : [acts 'N_D(A), on 'Fix_to(D :&: A) | to]. +Proof. +apply/subsetP=> a nAa; have [Da _] := setIP nAa; rewrite !inE Da. +apply/subsetP=> x Cx; rewrite inE; apply/afixP=> b DAb. +have [Db _]:= setIP DAb; rewrite -actMin // conjgCV actMin ?groupJ ?groupV //. +by rewrite /= (afixP Cx) // memJ_norm // groupV (subsetP (normsGI _ _) _ nAa). +Qed. + +Lemma atrans_orbit G x : [transitive G, on orbit to G x | to]. +Proof. by apply: mem_imset; exact: orbit_refl. Qed. + +Section OrbitStabilizer. + +Variables (G : {group aT}) (x : rT). +Hypothesis sGD : G \subset D. +Let ssGD := subsetP sGD. + +Lemma amove_act a : a \in G -> amove to G x (to x a) = 'C_G[x | to] :* a. +Proof. +move=> Ga; apply/setP=> b; have Da := ssGD Ga. +rewrite mem_rcoset !(inE, sub1set) !groupMr ?groupV //. +by case Gb: (b \in G); rewrite //= actMin ?groupV ?ssGD ?(canF_eq (actKVin Da)). +Qed. + +Lemma amove_orbit : amove to G x @: orbit to G x = rcosets 'C_G[x | to] G. +Proof. +apply/setP => Ha; apply/imsetP/rcosetsP=> [[y] | [a Ga ->]]. + by case/imsetP=> b Gb -> ->{Ha y}; exists b => //; rewrite amove_act. +by rewrite -amove_act //; exists (to x a); first exact: mem_orbit. +Qed. + +Lemma amoveK : + {in orbit to G x, cancel (amove to G x) (fun Ca => to x (repr Ca))}. +Proof. +move=> _ /orbitP[a Ga <-]; rewrite amove_act //= -[G :&: _]/(gval _). +case: repr_rcosetP => b; rewrite !(inE, sub1set)=> /and3P[Gb _ xbx]. +by rewrite actMin ?ssGD ?(eqP xbx). +Qed. + +Lemma orbit_stabilizer : + orbit to G x = [set to x (repr Ca) | Ca in rcosets 'C_G[x | to] G]. +Proof. +rewrite -amove_orbit -imset_comp /=; apply/setP=> z. +by apply/idP/imsetP=> [xGz | [y xGy ->]]; first exists z; rewrite /= ?amoveK. +Qed. + +Lemma act_reprK : + {in rcosets 'C_G[x | to] G, cancel (to x \o repr) (amove to G x)}. +Proof. +move=> _ /rcosetsP[a Ga ->] /=; rewrite amove_act ?rcoset_repr //. +rewrite -[G :&: _]/(gval _); case: repr_rcosetP => b /setIP[Gb _]. +exact: groupM. +Qed. + +End OrbitStabilizer. + +Lemma card_orbit_in G x : G \subset D -> #|orbit to G x| = #|G : 'C_G[x | to]|. +Proof. +move=> sGD; rewrite orbit_stabilizer 1?card_in_imset //. +exact: can_in_inj (act_reprK _). +Qed. + +Lemma card_orbit_in_stab G x : + G \subset D -> (#|orbit to G x| * #|'C_G[x | to]|)%N = #|G|. +Proof. by move=> sGD; rewrite mulnC card_orbit_in ?Lagrange ?subsetIl. Qed. + +Lemma acts_sum_card_orbit G S : + [acts G, on S | to] -> \sum_(T in orbit to G @: S) #|T| = #|S|. +Proof. by move/orbit_partition/card_partition. Qed. + +Lemma astab_setact_in S a : a \in D -> 'C(to^* S a | to) = 'C(S | to) :^ a. +Proof. +move=> Da; apply/setP=> b; rewrite mem_conjg !inE -mem_conjg conjGid //. +apply: andb_id2l => Db; rewrite sub_imset_pre; apply: eq_subset_r => x. +by rewrite !inE !actMin ?groupM ?groupV // invgK (canF_eq (actKVin Da)). +Qed. + +Lemma astab1_act_in x a : a \in D -> 'C[to x a | to] = 'C[x | to] :^ a. +Proof. by move=> Da; rewrite -astab_setact_in // /setact imset_set1. Qed. + +Theorem Frobenius_Cauchy G S : [acts G, on S | to] -> + \sum_(a in G) #|'Fix_(S | to)[a]| = (#|orbit to G @: S| * #|G|)%N. +Proof. +move=> GactS; have sGD := acts_dom GactS. +transitivity (\sum_(a in G) \sum_(x in 'Fix_(S | to)[a]) 1%N). + by apply: eq_bigr => a _; rewrite -sum1_card. +rewrite (exchange_big_dep (mem S)) /= => [|a x _]; last by case/setIP. +rewrite (set_partition_big _ (orbit_partition GactS)) -sum_nat_const /=. +apply: eq_bigr => _ /imsetP[x Sx ->]. +rewrite -(card_orbit_in_stab x sGD) -sum_nat_const. +apply: eq_bigr => y; rewrite orbit_in_sym // => /imsetP[a Ga defx]. +rewrite defx astab1_act_in ?(subsetP sGD) //. +rewrite -{2}(conjGid Ga) -conjIg cardJg -sum1_card setIA (setIidPl sGD). +by apply: eq_bigl => b; rewrite !(sub1set, inE) -(acts_act GactS Ga) -defx Sx. +Qed. + +Lemma atrans_dvd_index_in G S : + G \subset D -> [transitive G, on S | to] -> #|S| %| #|G : 'C_G(S | to)|. +Proof. +move=> sGD /imsetP[x Sx {1}->]; rewrite card_orbit_in //. +by rewrite indexgS // setIS // astabS // sub1set. +Qed. + +Lemma atrans_dvd_in G S : + G \subset D -> [transitive G, on S | to] -> #|S| %| #|G|. +Proof. +move=> sGD transG; apply: dvdn_trans (atrans_dvd_index_in sGD transG) _. +exact: dvdn_indexg. +Qed. + +Lemma atransPin G S : + G \subset D -> [transitive G, on S | to] -> + forall x, x \in S -> orbit to G x = S. +Proof. by move=> sGD /imsetP[y _ ->] x; exact: orbit_in_transl. Qed. + +Lemma atransP2in G S : + G \subset D -> [transitive G, on S | to] -> + {in S &, forall x y, exists2 a, a \in G & y = to x a}. +Proof. by move=> sGD transG x y /(atransPin sGD transG) <- /imsetP. Qed. + +Lemma atrans_acts_in G S : + G \subset D -> [transitive G, on S | to] -> [acts G, on S | to]. +Proof. +move=> sGD transG; apply/subsetP=> a Ga; rewrite !inE (subsetP sGD) //. +by apply/subsetP=> x /(atransPin sGD transG) <-; rewrite inE mem_imset. +Qed. + +Lemma subgroup_transitivePin G H S x : + x \in S -> H \subset G -> G \subset D -> [transitive G, on S | to] -> + reflect ('C_G[x | to] * H = G) [transitive H, on S | to]. +Proof. +move=> Sx sHG sGD trG; have sHD := subset_trans sHG sGD. +apply: (iffP idP) => [trH | defG]. + rewrite group_modr //; apply/setIidPl/subsetP=> a Ga. + have Sxa: to x a \in S by rewrite (acts_act (atrans_acts_in sGD trG)). + have [b Hb xab]:= atransP2in sHD trH Sxa Sx. + have Da := subsetP sGD a Ga; have Db := subsetP sHD b Hb. + rewrite -(mulgK b a) mem_mulg ?groupV // !inE groupM //= sub1set inE. + by rewrite actMin -?xab. +apply/imsetP; exists x => //; apply/setP=> y; rewrite -(atransPin sGD trG Sx). +apply/imsetP/imsetP=> [] [a]; last by exists a; first exact: (subsetP sHG). +rewrite -defG => /imset2P[c b /setIP[_ cxc] Hb ->] ->. +exists b; rewrite ?actMin ?(astab_dom cxc) ?(subsetP sHD) //. +by rewrite (astab_act cxc) ?inE. +Qed. + +End PartialAction. + +Arguments Scope orbit_transversal + [_ group_scope _ action_scope group_scope group_scope]. +Implicit Arguments orbit1P [aT D rT to G x]. +Implicit Arguments contra_orbit [aT D rT x y]. +Prenex Implicits orbit1P. + +Notation "''C' ( S | to )" := (astab_group to S) : Group_scope. +Notation "''C_' A ( S | to )" := (setI_group A 'C(S | to)) : Group_scope. +Notation "''C_' ( A ) ( S | to )" := (setI_group A 'C(S | to)) + (only parsing) : Group_scope. +Notation "''C' [ x | to ]" := (astab_group to [set x%g]) : Group_scope. +Notation "''C_' A [ x | to ]" := (setI_group A 'C[x | to]) : Group_scope. +Notation "''C_' ( A ) [ x | to ]" := (setI_group A 'C[x | to]) + (only parsing) : Group_scope. +Notation "''N' ( S | to )" := (astabs_group to S) : Group_scope. +Notation "''N_' A ( S | to )" := (setI_group A 'N(S | to)) : Group_scope. + +Section TotalActions. +(* These lemmas are only established for total actions (domain = [set: rT]) *) + +Variable (aT : finGroupType) (rT : finType). + +Variable to : {action aT &-> rT}. + +Implicit Types (a b : aT) (x y z : rT) (A B : {set aT}) (G H : {group aT}). +Implicit Type S : {set rT}. + +Lemma actM x a b : to x (a * b) = to (to x a) b. +Proof. by rewrite actMin ?inE. Qed. + +Lemma actK : right_loop invg to. +Proof. by move=> a; apply: actKin; rewrite inE. Qed. + +Lemma actKV : rev_right_loop invg to. +Proof. by move=> a; apply: actKVin; rewrite inE. Qed. + +Lemma actX x a n : to x (a ^+ n) = iter n (to^~ a) x. +Proof. by elim: n => [|n /= <-]; rewrite ?act1 // -actM expgSr. Qed. + +Lemma actCJ a b x : to (to x a) b = to (to x b) (a ^ b). +Proof. by rewrite !actM actK. Qed. + +Lemma actCJV a b x : to (to x a) b = to (to x (b ^ a^-1)) a. +Proof. by rewrite (actCJ _ a) conjgKV. Qed. + +Lemma orbit_sym G x y : (y \in orbit to G x) = (x \in orbit to G y). +Proof. by apply: orbit_in_sym; exact: subsetT. Qed. + +Lemma orbit_trans G x y z : + y \in orbit to G x -> z \in orbit to G y -> z \in orbit to G x. +Proof. by apply: orbit_in_trans; exact: subsetT. Qed. + +Lemma orbit_transl G x y : y \in orbit to G x -> orbit to G y = orbit to G x. +Proof. +move=> Gxy; apply/setP=> z; apply/idP/idP; apply: orbit_trans => //. +by rewrite orbit_sym. +Qed. + +Lemma orbit_transr G x y z : + y \in orbit to G x -> (y \in orbit to G z) = (x \in orbit to G z). +Proof. by move=> Gxy; rewrite orbit_sym (orbit_transl Gxy) orbit_sym. Qed. + +Lemma orbit_act G a x: a \in G -> orbit to G (to x a) = orbit to G x. +Proof. by move/mem_orbit/orbit_transl; exact. Qed. + +Lemma orbit_actr G a x y : + a \in G -> (to y a \in orbit to G x) = (y \in orbit to G x). +Proof. by move/mem_orbit/orbit_transr; exact. Qed. + +Lemma orbit_eq_mem G x y : + (orbit to G x == orbit to G y) = (x \in orbit to G y). +Proof. by apply/eqP/idP=> [<-|]; [exact: orbit_refl | exact: orbit_transl]. Qed. + +Lemma orbit_inv A x y : (y \in orbit to A^-1 x) = (x \in orbit to A y). +Proof. by rewrite orbit_inv_in ?subsetT. Qed. + +Lemma orbit_lcoset A a x : orbit to (a *: A) x = orbit to A (to x a). +Proof. by rewrite orbit_lcoset_in ?subsetT ?inE. Qed. + +Lemma orbit_rcoset A a x y : + (to y a \in orbit to (A :* a) x) = (y \in orbit to A x). +Proof. by rewrite orbit_rcoset_in ?subsetT ?inE. Qed. + +Lemma orbit_conjsg A a x y : + (to y a \in orbit to (A :^ a) (to x a)) = (y \in orbit to A x). +Proof. by rewrite orbit_conjsg_in ?subsetT ?inE. Qed. + +Lemma astabP S a : reflect (forall x, x \in S -> to x a = x) (a \in 'C(S | to)). +Proof. +apply: (iffP idP) => [cSa x|cSa]; first exact: astab_act. +by rewrite !inE; apply/subsetP=> x Sx; rewrite inE cSa. +Qed. + +Lemma astab1P x a : reflect (to x a = x) (a \in 'C[x | to]). +Proof. by rewrite !inE sub1set inE; exact: eqP. Qed. + +Lemma sub_astab1 A x : (A \subset 'C[x | to]) = (x \in 'Fix_to(A)). +Proof. by rewrite sub_astab1_in ?subsetT. Qed. + +Lemma astabC A S : (A \subset 'C(S | to)) = (S \subset 'Fix_to(A)). +Proof. by rewrite astabCin ?subsetT. Qed. + +Lemma afix_cycle a : 'Fix_to(<[a]>) = 'Fix_to[a]. +Proof. by rewrite afix_cycle_in ?inE. Qed. + +Lemma afix_gen A : 'Fix_to(<<A>>) = 'Fix_to(A). +Proof. by rewrite afix_gen_in ?subsetT. Qed. + +Lemma afixM G H : 'Fix_to(G * H) = 'Fix_to(G) :&: 'Fix_to(H). +Proof. by rewrite afixMin ?subsetT. Qed. + +Lemma astabsP S a : + reflect (forall x, (to x a \in S) = (x \in S)) (a \in 'N(S | to)). +Proof. +apply: (iffP idP) => [nSa x|nSa]; first exact: astabs_act. +by rewrite !inE; apply/subsetP=> x; rewrite inE nSa. +Qed. + +Lemma card_orbit G x : #|orbit to G x| = #|G : 'C_G[x | to]|. +Proof. by rewrite card_orbit_in ?subsetT. Qed. + +Lemma dvdn_orbit G x : #|orbit to G x| %| #|G|. +Proof. by rewrite card_orbit dvdn_indexg. Qed. + +Lemma card_orbit_stab G x : (#|orbit to G x| * #|'C_G[x | to]|)%N = #|G|. +Proof. by rewrite mulnC card_orbit Lagrange ?subsetIl. Qed. + +Lemma actsP A S : reflect {acts A, on S | to} [acts A, on S | to]. +Proof. +apply: (iffP idP) => [nSA x|nSA]; first exact: acts_act. +by apply/subsetP=> a Aa; rewrite !inE; apply/subsetP=> x; rewrite inE nSA. +Qed. +Implicit Arguments actsP [A S]. + +Lemma setact_orbit A x b : to^* (orbit to A x) b = orbit to (A :^ b) (to x b). +Proof. +apply/setP=> y; apply/idP/idP=> /imsetP[_ /imsetP[a Aa ->] ->{y}]. + by rewrite actCJ mem_orbit ?memJ_conjg. +by rewrite -actCJ mem_setact ?mem_orbit. +Qed. + +Lemma astab_setact S a : 'C(to^* S a | to) = 'C(S | to) :^ a. +Proof. +apply/setP=> b; rewrite mem_conjg. +apply/astabP/astabP=> stab x => [Sx|]. + by rewrite conjgE invgK !actM stab ?actK //; apply/imsetP; exists x. +by case/imsetP=> y Sy ->{x}; rewrite -actM conjgCV actM stab. +Qed. + +Lemma astab1_act x a : 'C[to x a | to] = 'C[x | to] :^ a. +Proof. by rewrite -astab_setact /setact imset_set1. Qed. + +Lemma atransP G S : [transitive G, on S | to] -> + forall x, x \in S -> orbit to G x = S. +Proof. by case/imsetP=> x _ -> y; exact: orbit_transl. Qed. + +Lemma atransP2 G S : [transitive G, on S | to] -> + {in S &, forall x y, exists2 a, a \in G & y = to x a}. +Proof. by move=> GtrS x y /(atransP GtrS) <- /imsetP. Qed. + +Lemma atrans_acts G S : [transitive G, on S | to] -> [acts G, on S | to]. +Proof. +move=> GtrS; apply/subsetP=> a Ga; rewrite !inE. +by apply/subsetP=> x /(atransP GtrS) <-; rewrite inE mem_imset. +Qed. + +Lemma atrans_supgroup G H S : + G \subset H -> [transitive G, on S | to] -> + [transitive H, on S | to] = [acts H, on S | to]. +Proof. +move=> sGH trG; apply/idP/idP=> [|actH]; first exact: atrans_acts. +case/imsetP: trG => x Sx defS; apply/imsetP; exists x => //. +by apply/eqP; rewrite eqEsubset acts_sub_orbit ?Sx // defS imsetS. +Qed. + +Lemma atrans_acts_card G S : + [transitive G, on S | to] = + [acts G, on S | to] && (#|orbit to G @: S| == 1%N). +Proof. +apply/idP/andP=> [GtrS | [nSG]]. + split; first exact: atrans_acts. + rewrite ((_ @: S =P [set S]) _) ?cards1 // eqEsubset sub1set. + apply/andP; split=> //; apply/subsetP=> _ /imsetP[x Sx ->]. + by rewrite inE (atransP GtrS). +rewrite eqn_leq andbC lt0n => /andP[/existsP[X /imsetP[x Sx X_Gx]]]. +rewrite (cardD1 X) {X}X_Gx mem_imset // ltnS leqn0 => /eqP GtrS. +apply/imsetP; exists x => //; apply/eqP. +rewrite eqEsubset acts_sub_orbit // Sx andbT. +apply/subsetP=> y Sy; have:= card0_eq GtrS (orbit to G y). +rewrite !inE /= mem_imset // andbT => /eqP <-; exact: orbit_refl. +Qed. + +Lemma atrans_dvd G S : [transitive G, on S | to] -> #|S| %| #|G|. +Proof. by case/imsetP=> x _ ->; exact: dvdn_orbit. Qed. + +(* Aschbacher 5.2 *) +Lemma acts_fix_norm A B : A \subset 'N(B) -> [acts A, on 'Fix_to(B) | to]. +Proof. +move=> nAB; have:= acts_subnorm_fix to B; rewrite !setTI. +exact: subset_trans. +Qed. + +Lemma faithfulP A S : + reflect (forall a, a \in A -> {in S, to^~ a =1 id} -> a = 1) + [faithful A, on S | to]. +Proof. +apply: (iffP subsetP) => [Cto1 a Aa Ca | Cto1 a]. + apply/set1P; rewrite Cto1 // inE Aa; exact/astabP. +case/setIP=> Aa /astabP Ca; apply/set1P; exact: Cto1. +Qed. + +(* This is the first part of Aschbacher (5.7) *) +Lemma astab_trans_gcore G S u : + [transitive G, on S | to] -> u \in S -> 'C(S | to) = gcore 'C[u | to] G. +Proof. +move=> transG Su; apply/eqP; rewrite eqEsubset. +rewrite gcore_max ?astabS ?sub1set //=; last first. + exact: subset_trans (atrans_acts transG) (astab_norm _ _). +apply/subsetP=> x cSx; apply/astabP=> uy. +case/(atransP2 transG Su) => y Gy ->{uy}. +by apply/astab1P; rewrite astab1_act (bigcapP cSx). +Qed. + +(* Aschbacher 5.20 *) +Theorem subgroup_transitiveP G H S x : + x \in S -> H \subset G -> [transitive G, on S | to] -> + reflect ('C_G[x | to] * H = G) [transitive H, on S | to]. +Proof. by move=> Sx sHG; exact: subgroup_transitivePin (subsetT G). Qed. + +(* Aschbacher 5.21 *) +Lemma trans_subnorm_fixP x G H S : + let C := 'C_G[x | to] in let T := 'Fix_(S | to)(H) in + [transitive G, on S | to] -> x \in S -> H \subset C -> + reflect ((H :^: G) ::&: C = H :^: C) [transitive 'N_G(H), on T | to]. +Proof. +move=> C T trGS Sx sHC; have actGS := acts_act (atrans_acts trGS). +have:= sHC; rewrite subsetI sub_astab1 => /andP[sHG cHx]. +have Tx: x \in T by rewrite inE Sx. +apply: (iffP idP) => [trN | trC]. + apply/setP=> Ha; apply/setIdP/imsetP=> [[]|[a Ca ->{Ha}]]; last first. + by rewrite conj_subG //; case/setIP: Ca => Ga _; rewrite mem_imset. + case/imsetP=> a Ga ->{Ha}; rewrite subsetI !sub_conjg => /andP[_ sHCa]. + have Txa: to x a^-1 \in T. + by rewrite inE -sub_astab1 astab1_act actGS ?Sx ?groupV. + have [b] := atransP2 trN Tx Txa; case/setIP=> Gb nHb cxba. + exists (b * a); last by rewrite conjsgM (normP nHb). + by rewrite inE groupM //; apply/astab1P; rewrite actM -cxba actKV. +apply/imsetP; exists x => //; apply/setP=> y; apply/idP/idP=> [Ty|]. + have [Sy cHy]:= setIP Ty; have [a Ga defy] := atransP2 trGS Sx Sy. + have: H :^ a^-1 \in H :^: C. + rewrite -trC inE subsetI mem_imset 1?conj_subG ?groupV // sub_conjgV. + by rewrite -astab1_act -defy sub_astab1. + case/imsetP=> b /setIP[Gb /astab1P cxb] defHb. + rewrite defy -{1}cxb -actM mem_orbit // inE groupM //. + by apply/normP; rewrite conjsgM -defHb conjsgKV. +case/imsetP=> a /setIP[Ga nHa] ->{y}. +by rewrite inE actGS // Sx (acts_act (acts_fix_norm _) nHa). +Qed. + +End TotalActions. + +Implicit Arguments astabP [aT rT to S a]. +Implicit Arguments astab1P [aT rT to x a]. +Implicit Arguments astabsP [aT rT to S a]. +Implicit Arguments atransP [aT rT to G S]. +Implicit Arguments actsP [aT rT to A S]. +Implicit Arguments faithfulP [aT rT to A S]. +Prenex Implicits astabP astab1P astabsP atransP actsP faithfulP. + +Section Restrict. + +Variables (aT : finGroupType) (D : {set aT}) (rT : Type). +Variables (to : action D rT) (A : {set aT}). + +Definition ract of A \subset D := act to. + +Variable sAD : A \subset D. + +Lemma ract_is_action : is_action A (ract sAD). +Proof. +rewrite /ract; case: to => f [injf fM]. +split=> // x; exact: (sub_in2 (subsetP sAD)). +Qed. + +Canonical raction := Action ract_is_action. + +Lemma ractE : raction =1 to. Proof. by []. Qed. + +(* Other properties of raction need rT : finType; we defer them *) +(* until after the definition of actperm. *) + +End Restrict. + +Notation "to \ sAD" := (raction to sAD) (at level 50) : action_scope. + +Section ActBy. + +Variables (aT : finGroupType) (D : {set aT}) (rT : finType). + +Definition actby_cond (A : {set aT}) R (to : action D rT) : Prop := + [acts A, on R | to]. + +Definition actby A R to of actby_cond A R to := + fun x a => if (x \in R) && (a \in A) then to x a else x. + +Variables (A : {group aT}) (R : {set rT}) (to : action D rT). +Hypothesis nRA : actby_cond A R to. + +Lemma actby_is_action : is_action A (actby nRA). +Proof. +rewrite /actby; split=> [a x y | x a b Aa Ab /=]; last first. + rewrite Aa Ab groupM // !andbT actMin ?(subsetP (acts_dom nRA)) //. + by case Rx: (x \in R); rewrite ?(acts_act nRA) ?Rx. +case Aa: (a \in A); rewrite ?andbF ?andbT //. +case Rx: (x \in R); case Ry: (y \in R) => // eqxy; first exact: act_inj eqxy. + by rewrite -eqxy (acts_act nRA Aa) Rx in Ry. +by rewrite eqxy (acts_act nRA Aa) Ry in Rx. +Qed. + +Canonical action_by := Action actby_is_action. +Local Notation "<[nRA]>" := action_by : action_scope. + +Lemma actbyE x a : x \in R -> a \in A -> <[nRA]>%act x a = to x a. +Proof. by rewrite /= /actby => -> ->. Qed. + +Lemma afix_actby B : 'Fix_<[nRA]>(B) = ~: R :|: 'Fix_to(A :&: B). +Proof. +apply/setP=> x; rewrite !inE /= /actby. +case: (x \in R); last by apply/subsetP=> a _; rewrite !inE. +apply/subsetP/subsetP=> [cBx a | cABx a Ba]; rewrite !inE. + by case/andP=> Aa /cBx; rewrite inE Aa. +by case: ifP => //= Aa; have:= cABx a; rewrite !inE Aa => ->. +Qed. + +Lemma astab_actby S : 'C(S | <[nRA]>) = 'C_A(R :&: S | to). +Proof. +apply/setP=> a; rewrite setIA (setIidPl (acts_dom nRA)) !inE. +case Aa: (a \in A) => //=; apply/subsetP/subsetP=> cRSa x => [|Sx]. + by case/setIP=> Rx /cRSa; rewrite !inE actbyE. +by have:= cRSa x; rewrite !inE /= /actby Aa Sx; case: (x \in R) => //; apply. +Qed. + +Lemma astabs_actby S : 'N(S | <[nRA]>) = 'N_A(R :&: S | to). +Proof. +apply/setP=> a; rewrite setIA (setIidPl (acts_dom nRA)) !inE. +case Aa: (a \in A) => //=; apply/subsetP/subsetP=> nRSa x => [|Sx]. + by case/setIP=> Rx /nRSa; rewrite !inE actbyE ?(acts_act nRA) ?Rx. +have:= nRSa x; rewrite !inE /= /actby Aa Sx ?(acts_act nRA) //. +by case: (x \in R) => //; apply. +Qed. + +Lemma acts_actby (B : {set aT}) S : + [acts B, on S | <[nRA]>] = (B \subset A) && [acts B, on R :&: S | to]. +Proof. by rewrite astabs_actby subsetI. Qed. + +End ActBy. + +Notation "<[ nRA ] >" := (action_by nRA) : action_scope. + +Section SubAction. + +Variables (aT : finGroupType) (D : {group aT}). +Variables (rT : finType) (sP : pred rT) (sT : subFinType sP) (to : action D rT). +Implicit Type A : {set aT}. +Implicit Type u : sT. +Implicit Type S : {set sT}. + +Definition subact_dom := 'N([set x | sP x] | to). +Canonical subact_dom_group := [group of subact_dom]. + +Implicit Type Na : {a | a \in subact_dom}. +Lemma sub_act_proof u Na : sP (to (val u) (val Na)). +Proof. by case: Na => a /= /(astabs_act (val u)); rewrite !inE valP. Qed. + +Definition subact u a := + if insub a is Some Na then Sub _ (sub_act_proof u Na) else u. + +Lemma val_subact u a : + val (subact u a) = if a \in subact_dom then to (val u) a else val u. +Proof. +by rewrite /subact -if_neg; case: insubP => [Na|] -> //=; rewrite SubK => ->. +Qed. + +Lemma subact_is_action : is_action subact_dom subact. +Proof. +split=> [a u v eq_uv | u a b Na Nb]; apply: val_inj. + move/(congr1 val): eq_uv; rewrite !val_subact. + by case: (a \in _); first move/act_inj. +have Da := astabs_dom Na; have Db := astabs_dom Nb. +by rewrite !val_subact Na Nb groupM ?actMin. +Qed. + +Canonical subaction := Action subact_is_action. + +Lemma astab_subact S : 'C(S | subaction) = subact_dom :&: 'C(val @: S | to). +Proof. +apply/setP=> a; rewrite inE in_setI; apply: andb_id2l => sDa. +have [Da _] := setIP sDa; rewrite !inE Da. +apply/subsetP/subsetP=> [cSa _ /imsetP[x Sx ->] | cSa x Sx]; rewrite !inE. + by have:= cSa x Sx; rewrite inE -val_eqE val_subact sDa. +by have:= cSa _ (mem_imset val Sx); rewrite inE -val_eqE val_subact sDa. +Qed. + +Lemma astabs_subact S : 'N(S | subaction) = subact_dom :&: 'N(val @: S | to). +Proof. +apply/setP=> a; rewrite inE in_setI; apply: andb_id2l => sDa. +have [Da _] := setIP sDa; rewrite !inE Da. +apply/subsetP/subsetP=> [nSa _ /imsetP[x Sx ->] | nSa x Sx]; rewrite !inE. + by have:= nSa x Sx; rewrite inE => /(mem_imset val); rewrite val_subact sDa. +have:= nSa _ (mem_imset val Sx); rewrite inE => /imsetP[y Sy def_y]. +by rewrite ((_ a =P y) _) // -val_eqE val_subact sDa def_y. +Qed. + +Lemma afix_subact A : + A \subset subact_dom -> 'Fix_subaction(A) = val @^-1: 'Fix_to(A). +Proof. +move/subsetP=> sAD; apply/setP=> u. +rewrite !inE !(sameP setIidPl eqP); congr (_ == A). +apply/setP=> a; rewrite !inE; apply: andb_id2l => Aa. +by rewrite -val_eqE val_subact sAD. + +Qed. + +End SubAction. + +Notation "to ^?" := (subaction _ to) + (at level 2, format "to ^?") : action_scope. + +Section QuotientAction. + +Variables (aT : finGroupType) (D : {group aT}) (rT : finGroupType). +Variables (to : action D rT) (H : {group rT}). + +Definition qact_dom := 'N(rcosets H 'N(H) | to^*). +Canonical qact_dom_group := [group of qact_dom]. + +Local Notation subdom := (subact_dom (coset_range H) to^*). +Fact qact_subdomE : subdom = qact_dom. +Proof. by congr 'N(_|_); apply/setP=> Hx; rewrite !inE genGid. Qed. +Lemma qact_proof : qact_dom \subset subdom. +Proof. by rewrite qact_subdomE. Qed. + +Definition qact : coset_of H -> aT -> coset_of H := act (to^*^? \ qact_proof). + +Canonical quotient_action := [action of qact]. + +Lemma acts_qact_dom : [acts qact_dom, on 'N(H) | to]. +Proof. +apply/subsetP=> a nNa; rewrite !inE (astabs_dom nNa); apply/subsetP=> x Nx. +have: H :* x \in rcosets H 'N(H) by rewrite -rcosetE mem_imset. +rewrite inE -(astabs_act _ nNa) => /rcosetsP[y Ny defHy]. +have: to x a \in H :* y by rewrite -defHy (mem_imset (to^~a)) ?rcoset_refl. +by apply: subsetP; rewrite mul_subG ?sub1set ?normG. +Qed. + +Lemma qactEcond x a : + x \in 'N(H) -> + quotient_action (coset H x) a = + (if a \in qact_dom then coset H (to x a) else coset H x). +Proof. +move=> Nx; apply: val_inj; rewrite val_subact //= qact_subdomE. +have: H :* x \in rcosets H 'N(H) by rewrite -rcosetE mem_imset. +case nNa: (a \in _); rewrite // -(astabs_act _ nNa). +rewrite !val_coset ?(acts_act acts_qact_dom nNa) //=. +case/rcosetsP=> y Ny defHy; rewrite defHy; apply: rcoset_transl. +by rewrite rcoset_sym -defHy (mem_imset (_^~_)) ?rcoset_refl. +Qed. + +Lemma qactE x a : + x \in 'N(H) -> a \in qact_dom -> + quotient_action (coset H x) a = coset H (to x a). +Proof. by move=> Nx nNa; rewrite qactEcond ?nNa. Qed. + +Lemma acts_quotient (A : {set aT}) (B : {set rT}) : + A \subset 'N_qact_dom(B | to) -> [acts A, on B / H | quotient_action]. +Proof. +move=> nBA; apply: subset_trans {A}nBA _; apply/subsetP=> a /setIP[dHa nBa]. +rewrite inE dHa inE; apply/subsetP=> _ /morphimP[x nHx Bx ->]. +rewrite inE /= qactE //. +by rewrite mem_morphim ?(acts_act acts_qact_dom) ?(astabs_act _ nBa). +Qed. + +Lemma astabs_quotient (G : {group rT}) : + H <| G -> 'N(G / H | quotient_action) = 'N_qact_dom(G | to). +Proof. +move=> nsHG; have [_ nHG] := andP nsHG. +apply/eqP; rewrite eqEsubset acts_quotient // andbT. +apply/subsetP=> a nGa; have dHa := astabs_dom nGa; have [Da _]:= setIdP dHa. +rewrite inE dHa 2!inE Da; apply/subsetP=> x Gx; have nHx := subsetP nHG x Gx. +rewrite -(quotientGK nsHG) 2!inE (acts_act acts_qact_dom) ?nHx //= inE. +by rewrite -qactE // (astabs_act _ nGa) mem_morphim. +Qed. + +End QuotientAction. + +Notation "to / H" := (quotient_action to H) : action_scope. + +Section ModAction. + +Variables (aT : finGroupType) (D : {group aT}) (rT : finType). +Variable to : action D rT. +Implicit Types (G : {group aT}) (S : {set rT}). + +Section GenericMod. + +Variable H : {group aT}. + +Local Notation dom := 'N_D(H). +Local Notation range := 'Fix_to(D :&: H). +Let acts_dom : {acts dom, on range | to} := acts_act (acts_subnorm_fix to H). + +Definition modact x (Ha : coset_of H) := + if x \in range then to x (repr (D :&: Ha)) else x. + +Lemma modactEcond x a : + a \in dom -> modact x (coset H a) = (if x \in range then to x a else x). +Proof. +case/setIP=> Da Na; case: ifP => Cx; rewrite /modact Cx //. +rewrite val_coset // -group_modr ?sub1set //. +case: (repr _) / (repr_rcosetP (D :&: H) a) => a' Ha'. +by rewrite actMin ?(afixP Cx _ Ha') //; case/setIP: Ha'. +Qed. + +Lemma modactE x a : + a \in D -> a \in 'N(H) -> x \in range -> modact x (coset H a) = to x a. +Proof. by move=> Da Na Rx; rewrite modactEcond ?Rx // inE Da. Qed. + +Lemma modact_is_action : is_action (D / H) modact. +Proof. +split=> [Ha x y | x Ha Hb]; last first. + case/morphimP=> a Na Da ->{Ha}; case/morphimP=> b Nb Db ->{Hb}. + rewrite -morphM //= !modactEcond // ?groupM ?(introT setIP _) //. + by case: ifP => Cx; rewrite ?(acts_dom, Cx, actMin, introT setIP _). +case: (set_0Vmem (D :&: Ha)) => [Da0 | [a /setIP[Da NHa]]]. + by rewrite /modact Da0 repr_set0 !act1 !if_same. +have Na := subsetP (coset_norm _) _ NHa. +have NDa: a \in 'N_D(H) by rewrite inE Da. +rewrite -(coset_mem NHa) !modactEcond //. +do 2![case: ifP]=> Cy Cx // eqxy; first exact: act_inj eqxy. + by rewrite -eqxy acts_dom ?Cx in Cy. +by rewrite eqxy acts_dom ?Cy in Cx. +Qed. + +Canonical mod_action := Action modact_is_action. + +Section Stabilizers. + +Variable S : {set rT}. +Hypothesis cSH : H \subset 'C(S | to). + +Let fixSH : S \subset 'Fix_to(D :&: H). +Proof. by rewrite -astabCin ?subsetIl // subIset ?cSH ?orbT. Qed. + +Lemma astabs_mod : 'N(S | mod_action) = 'N(S | to) / H. +Proof. +apply/setP=> Ha; apply/idP/morphimP=> [nSa | [a nHa nSa ->]]. + case/morphimP: (astabs_dom nSa) => a nHa Da defHa. + exists a => //; rewrite !inE Da; apply/subsetP=> x Sx; rewrite !inE. + by have:= Sx; rewrite -(astabs_act x nSa) defHa /= modactE ?(subsetP fixSH). +have Da := astabs_dom nSa; rewrite !inE mem_quotient //; apply/subsetP=> x Sx. +by rewrite !inE /= modactE ?(astabs_act x nSa) ?(subsetP fixSH). +Qed. + +Lemma astab_mod : 'C(S | mod_action) = 'C(S | to) / H. +Proof. +apply/setP=> Ha; apply/idP/morphimP=> [cSa | [a nHa cSa ->]]. + case/morphimP: (astab_dom cSa) => a nHa Da defHa. + exists a => //; rewrite !inE Da; apply/subsetP=> x Sx; rewrite !inE. + by rewrite -{2}[x](astab_act cSa) // defHa /= modactE ?(subsetP fixSH). +have Da := astab_dom cSa; rewrite !inE mem_quotient //; apply/subsetP=> x Sx. +by rewrite !inE /= modactE ?(astab_act cSa) ?(subsetP fixSH). +Qed. + +End Stabilizers. + +Lemma afix_mod G S : + H \subset 'C(S | to) -> G \subset 'N_D(H) -> + 'Fix_(S | mod_action)(G / H) = 'Fix_(S | to)(G). +Proof. +move=> cSH /subsetIP[sGD nHG]. +apply/eqP; rewrite eqEsubset !subsetI !subsetIl /= -!astabCin ?quotientS //. +have cfixH F: H \subset 'C(S :&: F | to). + by rewrite (subset_trans cSH) // astabS ?subsetIl. +rewrite andbC astab_mod ?quotientS //=; last by rewrite astabCin ?subsetIr. +by rewrite -(quotientSGK nHG) //= -astab_mod // astabCin ?quotientS ?subsetIr. +Qed. + +End GenericMod. + +Lemma modact_faithful G S : + [faithful G / 'C_G(S | to), on S | mod_action 'C_G(S | to)]. +Proof. +rewrite /faithful astab_mod ?subsetIr //=. +by rewrite -quotientIG ?subsetIr ?trivg_quotient. +Qed. + +End ModAction. + +Notation "to %% H" := (mod_action to H) : action_scope. + +Section ActPerm. +(* Morphism to permutations induced by an action. *) + +Variables (aT : finGroupType) (D : {set aT}) (rT : finType). +Variable to : action D rT. + +Definition actperm a := perm (act_inj to a). + +Lemma actpermM : {in D &, {morph actperm : a b / a * b}}. +Proof. by move=> a b Da Db; apply/permP=> x; rewrite permM !permE actMin. Qed. + +Canonical actperm_morphism := Morphism actpermM. + +Lemma actpermE a x : actperm a x = to x a. +Proof. by rewrite permE. Qed. + +Lemma actpermK x a : aperm x (actperm a) = to x a. +Proof. exact: actpermE. Qed. + +Lemma ker_actperm : 'ker actperm = 'C(setT | to). +Proof. +congr (_ :&: _); apply/setP=> a; rewrite !inE /=. +apply/eqP/subsetP=> [a1 x _ | a1]; first by rewrite inE -actpermE a1 perm1. +by apply/permP=> x; apply/eqP; have:= a1 x; rewrite !inE actpermE perm1 => ->. +Qed. + +End ActPerm. + +Section RestrictActionTheory. + +Variables (aT : finGroupType) (D : {set aT}) (rT : finType). +Variables (to : action D rT). + +Lemma faithful_isom (A : {group aT}) S (nSA : actby_cond A S to) : + [faithful A, on S | to] -> isom A (actperm <[nSA]> @* A) (actperm <[nSA]>). +Proof. +by move=> ffulAS; apply/isomP; rewrite ker_actperm astab_actby setIT. +Qed. + +Variables (A : {set aT}) (sAD : A \subset D). + +Lemma ractpermE : actperm (to \ sAD) =1 actperm to. +Proof. by move=> a; apply/permP=> x; rewrite !permE. Qed. + +Lemma afix_ract B : 'Fix_(to \ sAD)(B) = 'Fix_to(B). Proof. by []. Qed. + +Lemma astab_ract S : 'C(S | to \ sAD) = 'C_A(S | to). +Proof. by rewrite setIA (setIidPl sAD). Qed. + +Lemma astabs_ract S : 'N(S | to \ sAD) = 'N_A(S | to). +Proof. by rewrite setIA (setIidPl sAD). Qed. + +Lemma acts_ract (B : {set aT}) S : + [acts B, on S | to \ sAD] = (B \subset A) && [acts B, on S | to]. +Proof. by rewrite astabs_ract subsetI. Qed. + +End RestrictActionTheory. + +Section MorphAct. +(* Action induced by a morphism to permutations. *) + +Variables (aT : finGroupType) (D : {group aT}) (rT : finType). +Variable phi : {morphism D >-> {perm rT}}. + +Definition mact x a := phi a x. + +Lemma mact_is_action : is_action D mact. +Proof. +split=> [a x y | x a b Da Db]; first exact: perm_inj. +by rewrite /mact morphM //= permM. +Qed. + +Canonical morph_action := Action mact_is_action. + +Lemma mactE x a : morph_action x a = phi a x. Proof. by []. Qed. + +Lemma injm_faithful : 'injm phi -> [faithful D, on setT | morph_action]. +Proof. +move/injmP=> phi_inj; apply/subsetP=> a /setIP[Da /astab_act a1]. +apply/set1P/phi_inj => //; apply/permP=> x. +by rewrite morph1 perm1 -mactE a1 ?inE. +Qed. + +Lemma perm_mact a : actperm morph_action a = phi a. +Proof. by apply/permP=> x; rewrite permE. Qed. + +End MorphAct. + +Notation "<< phi >>" := (morph_action phi) : action_scope. + +Section CompAct. + +Variables (gT aT : finGroupType) (rT : finType). +Variables (D : {set aT}) (to : action D rT). +Variables (B : {set gT}) (f : {morphism B >-> aT}). + +Definition comp_act x e := to x (f e). +Lemma comp_is_action : is_action (f @*^-1 D) comp_act. +Proof. +split=> [e | x e1 e2]; first exact: act_inj. +case/morphpreP=> Be1 Dfe1; case/morphpreP=> Be2 Dfe2. +by rewrite /comp_act morphM ?actMin. +Qed. +Canonical comp_action := Action comp_is_action. + +Lemma comp_actE x e : comp_action x e = to x (f e). Proof. by []. Qed. + +Lemma afix_comp (A : {set gT}) : + A \subset B -> 'Fix_comp_action(A) = 'Fix_to(f @* A). +Proof. +move=> sAB; apply/setP=> x; rewrite !inE /morphim (setIidPr sAB). +apply/subsetP/subsetP=> [cAx _ /imsetP[a Aa ->] | cfAx a Aa]. + by move/cAx: Aa; rewrite !inE. +by rewrite inE; move/(_ (f a)): cfAx; rewrite inE mem_imset // => ->. +Qed. + +Lemma astab_comp S : 'C(S | comp_action) = f @*^-1 'C(S | to). +Proof. by apply/setP=> x; rewrite !inE -andbA. Qed. + +Lemma astabs_comp S : 'N(S | comp_action) = f @*^-1 'N(S | to). +Proof. by apply/setP=> x; rewrite !inE -andbA. Qed. + +End CompAct. + +Notation "to \o f" := (comp_action to f) : action_scope. + +Section PermAction. +(* Natural action of permutation groups. *) + +Variable rT : finType. +Local Notation gT := {perm rT}. +Implicit Types a b c : gT. + +Lemma aperm_is_action : is_action setT (@aperm rT). +Proof. +by apply: is_total_action => [x|x a b]; rewrite apermE (perm1, permM). +Qed. + +Canonical perm_action := Action aperm_is_action. + +Lemma pcycleE a : pcycle a = orbit perm_action <[a]>%g. +Proof. by []. Qed. + +Lemma perm_act1P a : reflect (forall x, aperm x a = x) (a == 1). +Proof. +apply: (iffP eqP) => [-> x | a1]; first exact: act1. +by apply/permP=> x; rewrite -apermE a1 perm1. +Qed. + +Lemma perm_faithful A : [faithful A, on setT | perm_action]. +Proof. +apply/subsetP=> a /setIP[Da crTa]. +by apply/set1P; apply/permP=> x; rewrite -apermE perm1 (astabP crTa) ?inE. +Qed. + +Lemma actperm_id p : actperm perm_action p = p. +Proof. by apply/permP=> x; rewrite permE. Qed. + +End PermAction. + +Implicit Arguments perm_act1P [rT a]. +Prenex Implicits perm_act1P. + +Notation "'P" := (perm_action _) (at level 8) : action_scope. + +Section ActpermOrbits. + +Variables (aT : finGroupType) (D : {group aT}) (rT : finType). +Variable to : action D rT. + +Lemma orbit_morphim_actperm (A : {set aT}) : + A \subset D -> orbit 'P (actperm to @* A) =1 orbit to A. +Proof. +move=> sAD x; rewrite morphimEsub // /orbit -imset_comp. +by apply: eq_imset => a //=; rewrite actpermK. +Qed. + +Lemma pcycle_actperm (a : aT) : + a \in D -> pcycle (actperm to a) =1 orbit to <[a]>. +Proof. +move=> Da x. +by rewrite pcycleE -orbit_morphim_actperm ?cycle_subG ?morphim_cycle. +Qed. + +End ActpermOrbits. + +Section RestrictPerm. + +Variables (T : finType) (S : {set T}). + +Definition restr_perm := actperm (<[subxx 'N(S | 'P)]>). +Canonical restr_perm_morphism := [morphism of restr_perm]. + +Lemma restr_perm_on p : perm_on S (restr_perm p). +Proof. +apply/subsetP=> x; apply: contraR => notSx. +by rewrite permE /= /actby (negPf notSx). +Qed. + +Lemma triv_restr_perm p : p \notin 'N(S | 'P) -> restr_perm p = 1. +Proof. +move=> not_nSp; apply/permP=> x. +by rewrite !permE /= /actby (negPf not_nSp) andbF. +Qed. + +Lemma restr_permE : {in 'N(S | 'P) & S, forall p, restr_perm p =1 p}. +Proof. by move=> y x nSp Sx; rewrite /= actpermE actbyE. Qed. + +Lemma ker_restr_perm : 'ker restr_perm = 'C(S | 'P). +Proof. by rewrite ker_actperm astab_actby setIT (setIidPr (astab_sub _ _)). Qed. + +Lemma im_restr_perm p : restr_perm p @: S = S. +Proof. exact: im_perm_on (restr_perm_on p). Qed. + +End RestrictPerm. + +Section AutIn. + +Variable gT : finGroupType. + +Definition Aut_in A (B : {set gT}) := 'N_A(B | 'P) / 'C_A(B | 'P). + +Variables G H : {group gT}. +Hypothesis sHG: H \subset G. + +Lemma Aut_restr_perm a : a \in Aut G -> restr_perm H a \in Aut H. +Proof. +move=> AutGa. +case nHa: (a \in 'N(H | 'P)); last by rewrite triv_restr_perm ?nHa ?group1. +rewrite inE restr_perm_on; apply/morphicP=> x y Hx Hy /=. +by rewrite !restr_permE ?groupM // -(autmE AutGa) morphM ?(subsetP sHG). +Qed. + +Lemma restr_perm_Aut : restr_perm H @* Aut G \subset Aut H. +Proof. +by apply/subsetP=> a'; case/morphimP=> a _ AutGa ->{a'}; exact: Aut_restr_perm. +Qed. + +Lemma Aut_in_isog : Aut_in (Aut G) H \isog restr_perm H @* Aut G. +Proof. +rewrite /Aut_in -ker_restr_perm kerE -morphpreIdom -morphimIdom -kerE /=. +by rewrite setIA (setIC _ (Aut G)) first_isog_loc ?subsetIr. +Qed. + +Lemma Aut_sub_fullP : + reflect (forall h : {morphism H >-> gT}, 'injm h -> h @* H = H -> + exists g : {morphism G >-> gT}, + [/\ 'injm g, g @* G = G & {in H, g =1 h}]) + (Aut_in (Aut G) H \isog Aut H). +Proof. +rewrite (isog_transl _ Aut_in_isog) /=; set rG := _ @* _. +apply: (iffP idP) => [iso_rG h injh hH| AutHinG]. + have: aut injh hH \in rG; last case/morphimP=> g nHg AutGg def_g. + suffices ->: rG = Aut H by exact: Aut_aut. + by apply/eqP; rewrite eqEcard restr_perm_Aut /= (card_isog iso_rG). + exists (autm_morphism AutGg); rewrite injm_autm im_autm; split=> // x Hx. + by rewrite -(autE injh hH Hx) def_g actpermE actbyE. +suffices ->: rG = Aut H by exact: isog_refl. +apply/eqP; rewrite eqEsubset restr_perm_Aut /=. +apply/subsetP=> h AutHh; have hH := im_autm AutHh. +have [g [injg gG eq_gh]] := AutHinG _ (injm_autm AutHh) hH. +have [Ng AutGg]: aut injg gG \in 'N(H | 'P) /\ aut injg gG \in Aut G. + rewrite Aut_aut !inE; split=> //; apply/subsetP=> x Hx. + by rewrite inE /= /aperm autE ?(subsetP sHG) // -hH eq_gh ?mem_morphim. +apply/morphimP; exists (aut injg gG) => //; apply: (eq_Aut AutHh) => [|x Hx]. + by rewrite (subsetP restr_perm_Aut) // mem_morphim. +by rewrite restr_permE //= /aperm autE ?eq_gh ?(subsetP sHG). +Qed. + +End AutIn. + +Arguments Scope Aut_in [_ group_scope group_scope]. + +Section InjmAutIn. + +Variables (gT rT : finGroupType) (D G H : {group gT}) (f : {morphism D >-> rT}). +Hypotheses (injf : 'injm f) (sGD : G \subset D) (sHG : H \subset G). +Let sHD := subset_trans sHG sGD. +Local Notation fGisom := (Aut_isom injf sGD). +Local Notation fHisom := (Aut_isom injf sHD). +Local Notation inH := (restr_perm H). +Local Notation infH := (restr_perm (f @* H)). + +Lemma astabs_Aut_isom a : + a \in Aut G -> (fGisom a \in 'N(f @* H | 'P)) = (a \in 'N(H | 'P)). +Proof. +move=> AutGa; rewrite !inE sub_morphim_pre // subsetI sHD /= /aperm. +rewrite !(sameP setIidPl eqP) !eqEsubset !subsetIl; apply: eq_subset_r => x. +rewrite !inE; apply: andb_id2l => Hx; have Gx: x \in G := subsetP sHG x Hx. +have Dax: a x \in D by rewrite (subsetP sGD) // Aut_closed. +by rewrite Aut_isomE // -!sub1set -morphim_set1 // injmSK ?sub1set. +Qed. + +Lemma isom_restr_perm a : a \in Aut G -> fHisom (inH a) = infH (fGisom a). +Proof. +move=> AutGa; case nHa: (a \in 'N(H | 'P)); last first. + by rewrite !triv_restr_perm ?astabs_Aut_isom ?nHa ?morph1. +apply: (eq_Aut (Aut_Aut_isom injf sHD _)) => [|fx Hfx /=]. + by rewrite (Aut_restr_perm (morphimS f sHG)) ?Aut_Aut_isom. +have [x Dx Hx def_fx] := morphimP Hfx; have Gx := subsetP sHG x Hx. +rewrite {1}def_fx Aut_isomE ?(Aut_restr_perm sHG) //. +by rewrite !restr_permE ?astabs_Aut_isom // def_fx Aut_isomE. +Qed. + +Lemma restr_perm_isom : isom (inH @* Aut G) (infH @* Aut (f @* G)) fHisom. +Proof. +apply: sub_isom; rewrite ?restr_perm_Aut ?injm_Aut_isom //=. +rewrite -(im_Aut_isom injf sGD) -!morphim_comp. +apply: eq_in_morphim; last exact: isom_restr_perm. +apply/setP=> a; rewrite 2!in_setI; apply: andb_id2r => AutGa. +rewrite /= inE andbC inE (Aut_restr_perm sHG) //=. +by symmetry; rewrite inE AutGa inE astabs_Aut_isom. +Qed. + +Lemma injm_Aut_sub : Aut_in (Aut (f @* G)) (f @* H) \isog Aut_in (Aut G) H. +Proof. +do 2!rewrite isog_sym (isog_transl _ (Aut_in_isog _ _)). +by rewrite isog_sym (isom_isog _ _ restr_perm_isom) // restr_perm_Aut. +Qed. + +Lemma injm_Aut_full : + (Aut_in (Aut (f @* G)) (f @* H) \isog Aut (f @* H)) + = (Aut_in (Aut G) H \isog Aut H). +Proof. +by rewrite (isog_transl _ injm_Aut_sub) (isog_transr _ (injm_Aut injf sHD)). +Qed. + +End InjmAutIn. + +Section GroupAction. + +Variables (aT rT : finGroupType) (D : {set aT}) (R : {set rT}). +Local Notation actT := (action D rT). + +Definition is_groupAction (to : actT) := + {in D, forall a, actperm to a \in Aut R}. + +Structure groupAction := GroupAction {gact :> actT; _ : is_groupAction gact}. + +Definition clone_groupAction to := + let: GroupAction _ toA := to return {type of GroupAction for to} -> _ in + fun k => k toA : groupAction. + +End GroupAction. + +Delimit Scope groupAction_scope with gact. +Bind Scope groupAction_scope with groupAction. + +Arguments Scope is_groupAction [_ _ group_scope group_scope action_scope]. +Arguments Scope groupAction [_ _ group_scope group_scope]. +Arguments Scope gact [_ _ group_scope group_scope groupAction_scope]. + +Notation "[ 'groupAction' 'of' to ]" := + (clone_groupAction (@GroupAction _ _ _ _ to)) + (at level 0, format "[ 'groupAction' 'of' to ]") : form_scope. + +Section GroupActionDefs. + +Variables (aT rT : finGroupType) (D : {set aT}) (R : {set rT}). +Implicit Type A : {set aT}. +Implicit Type S : {set rT}. +Implicit Type to : groupAction D R. + +Definition gact_range of groupAction D R := R. + +Definition gacent to A := 'Fix_(R | to)(D :&: A). + +Definition acts_on_group A S to := [acts A, on S | to] /\ S \subset R. + +Coercion actby_cond_group A S to : acts_on_group A S to -> actby_cond A S to := + @proj1 _ _. + +Definition acts_irreducibly A S to := + [min S of G | G :!=: 1 & [acts A, on G | to]]. + +End GroupActionDefs. + +Arguments Scope gacent + [_ _ group_scope group_scope groupAction_scope group_scope]. +Arguments Scope acts_on_group + [_ _ group_scope group_scope group_scope group_scope groupAction_scope]. +Arguments Scope acts_irreducibly + [_ _ group_scope group_scope group_scope group_scope groupAction_scope]. + +Notation "''C_' ( | to ) ( A )" := (gacent to A) + (at level 8, format "''C_' ( | to ) ( A )") : group_scope. +Notation "''C_' ( G | to ) ( A )" := (G :&: 'C_(|to)(A)) + (at level 8, format "''C_' ( G | to ) ( A )") : group_scope. +Notation "''C_' ( | to ) [ a ]" := 'C_(|to)([set a]) + (at level 8, format "''C_' ( | to ) [ a ]") : group_scope. +Notation "''C_' ( G | to ) [ a ]" := 'C_(G | to)([set a]) + (at level 8, format "''C_' ( G | to ) [ a ]") : group_scope. + +Notation "{ 'acts' A , 'on' 'group' G | to }" := (acts_on_group A G to) + (at level 0, format "{ 'acts' A , 'on' 'group' G | to }") : form_scope. + +Section RawGroupAction. + +Variables (aT rT : finGroupType) (D : {set aT}) (R : {set rT}). +Variable to : groupAction D R. + +Lemma actperm_Aut : is_groupAction R to. Proof. by case: to. Qed. + +Lemma im_actperm_Aut : actperm to @* D \subset Aut R. +Proof. by apply/subsetP=> _ /morphimP[a _ Da ->]; exact: actperm_Aut. Qed. + +Lemma gact_out x a : a \in D -> x \notin R -> to x a = x. +Proof. by move=> Da Rx; rewrite -actpermE (out_Aut _ Rx) ?actperm_Aut. Qed. + +Lemma gactM : {in D, forall a, {in R &, {morph to^~ a : x y / x * y}}}. +Proof. +move=> a Da /= x y; rewrite -!(actpermE to); apply: morphicP x y. +by rewrite Aut_morphic ?actperm_Aut. +Qed. + +Lemma actmM a : {in R &, {morph actm to a : x y / x * y}}. +Proof. rewrite /actm; case: ifP => //; exact: gactM. Qed. + +Canonical act_morphism a := Morphism (actmM a). + +Lemma morphim_actm : + {in D, forall a (S : {set rT}), S \subset R -> actm to a @* S = to^* S a}. +Proof. by move=> a Da /= S sSR; rewrite /morphim /= actmEfun ?(setIidPr _). Qed. + +Variables (a : aT) (A B : {set aT}) (S : {set rT}). + +Lemma gacentIdom : 'C_(|to)(D :&: A) = 'C_(|to)(A). +Proof. by rewrite /gacent setIA setIid. Qed. + +Lemma gacentIim : 'C_(R | to)(A) = 'C_(|to)(A). +Proof. by rewrite setIA setIid. Qed. + +Lemma gacentS : A \subset B -> 'C_(|to)(B) \subset 'C_(|to)(A). +Proof. by move=> sAB; rewrite !(setIS, afixS). Qed. + +Lemma gacentU : 'C_(|to)(A :|: B) = 'C_(|to)(A) :&: 'C_(|to)(B). +Proof. by rewrite -setIIr -afixU -setIUr. Qed. + +Hypotheses (Da : a \in D) (sAD : A \subset D) (sSR : S \subset R). + +Lemma gacentE : 'C_(|to)(A) = 'Fix_(R | to)(A). +Proof. by rewrite -{2}(setIidPr sAD). Qed. + +Lemma gacent1E : 'C_(|to)[a] = 'Fix_(R | to)[a]. +Proof. by rewrite /gacent [D :&: _](setIidPr _) ?sub1set. Qed. + +Lemma subgacentE : 'C_(S | to)(A) = 'Fix_(S | to)(A). +Proof. by rewrite gacentE setIA (setIidPl sSR). Qed. + +Lemma subgacent1E : 'C_(S | to)[a] = 'Fix_(S | to)[a]. +Proof. by rewrite gacent1E setIA (setIidPl sSR). Qed. + +End RawGroupAction. + +Section GroupActionTheory. + +Variables aT rT : finGroupType. +Variables (D : {group aT}) (R : {group rT}) (to : groupAction D R). +Implicit Type A B : {set aT}. +Implicit Types G H : {group aT}. +Implicit Type S : {set rT}. +Implicit Types M N : {group rT}. + +Lemma gact1 : {in D, forall a, to 1 a = 1}. +Proof. by move=> a Da; rewrite /= -actmE ?morph1. Qed. + +Lemma gactV : {in D, forall a, {in R, {morph to^~ a : x / x^-1}}}. +Proof. by move=> a Da /= x Rx; move; rewrite -!actmE ?morphV. Qed. + +Lemma gactX : {in D, forall a n, {in R, {morph to^~ a : x / x ^+ n}}}. +Proof. by move=> a Da /= n x Rx; rewrite -!actmE // morphX. Qed. + +Lemma gactJ : {in D, forall a, {in R &, {morph to^~ a : x y / x ^ y}}}. +Proof. by move=> a Da /= x Rx y Ry; rewrite -!actmE // morphJ. Qed. + +Lemma gactR : {in D, forall a, {in R &, {morph to^~ a : x y / [~ x, y]}}}. +Proof. by move=> a Da /= x Rx y Ry; rewrite -!actmE // morphR. Qed. + +Lemma gact_stable : {acts D, on R | to}. +Proof. +apply: acts_act; apply/subsetP=> a Da; rewrite !inE Da. +apply/subsetP=> x; rewrite inE; apply: contraLR => R'xa. +by rewrite -(actKin to Da x) gact_out ?groupV. +Qed. + +Lemma group_set_gacent A : group_set 'C_(|to)(A). +Proof. +apply/group_setP; split=> [|x y]. + by rewrite !inE group1; apply/subsetP=> a /setIP[Da _]; rewrite inE gact1. +case/setIP=> Rx /afixP cAx /setIP[Ry /afixP cAy]. +rewrite inE groupM //; apply/afixP=> a Aa. +by rewrite gactM ?cAx ?cAy //; case/setIP: Aa. +Qed. + +Canonical gacent_group A := Group (group_set_gacent A). + +Lemma gacent1 : 'C_(|to)(1) = R. +Proof. by rewrite /gacent (setIidPr (sub1G _)) afix1 setIT. Qed. + +Lemma gacent_gen A : A \subset D -> 'C_(|to)(<<A>>) = 'C_(|to)(A). +Proof. +by move=> sAD; rewrite /gacent  ?gen_subG ?afix_gen_in. +Qed. + +Lemma gacentD1 A : 'C_(|to)(A^#) = 'C_(|to)(A). +Proof. +rewrite -gacentIdom -gacent_gen ?subsetIl // setIDA genD1 ?group1 //. +by rewrite gacent_gen ?subsetIl // gacentIdom. +Qed. + +Lemma gacent_cycle a : a \in D -> 'C_(|to)(<[a]>) = 'C_(|to)[a]. +Proof. by move=> Da; rewrite gacent_gen ?sub1set. Qed. + +Lemma gacentY A B : + A \subset D -> B \subset D -> 'C_(|to)(A <*> B) = 'C_(|to)(A) :&: 'C_(|to)(B). +Proof. by move=> sAD sBD; rewrite gacent_gen ?gacentU // subUset sAD. Qed. + +Lemma gacentM G H : + G \subset D -> H \subset D -> 'C_(|to)(G * H) = 'C_(|to)(G) :&: 'C_(|to)(H). +Proof. +by move=> sGD sHB; rewrite -gacent_gen ?mul_subG // genM_join gacentY. +Qed. + +Lemma astab1 : 'C(1 | to) = D. +Proof. +by apply/setP=> x; rewrite ?(inE, sub1set) andb_idr //; move/gact1=> ->. +Qed. + +Lemma astab_range : 'C(R | to) = 'C(setT | to). +Proof. +apply/eqP; rewrite eqEsubset andbC astabS ?subsetT //=. +apply/subsetP=> a cRa; have Da := astab_dom cRa; rewrite !inE Da. +apply/subsetP=> x; rewrite -(setUCr R) !inE. +by case/orP=> ?; [rewrite (astab_act cRa) | rewrite gact_out]. +Qed. + +Lemma gacentC A S : + A \subset D -> S \subset R -> + (S \subset 'C_(|to)(A)) = (A \subset 'C(S | to)). +Proof. by move=> sAD sSR; rewrite subsetI sSR astabCin // (setIidPr sAD). Qed. + +Lemma astab_gen S : S \subset R -> 'C(<<S>> | to) = 'C(S | to). +Proof. +move=> sSR; apply/setP=> a; case Da: (a \in D); last by rewrite !inE Da. +by rewrite -!sub1set -!gacentC ?sub1set ?gen_subG. +Qed. + +Lemma astabM M N : + M \subset R -> N \subset R -> 'C(M * N | to) = 'C(M | to) :&: 'C(N | to). +Proof. +move=> sMR sNR; rewrite -astabU -astab_gen ?mul_subG // genM_join. +by rewrite astab_gen // subUset sMR. +Qed. + +Lemma astabs1 : 'N(1 | to) = D. +Proof. by rewrite astabs_set1 astab1. Qed. + +Lemma astabs_range : 'N(R | to) = D. +Proof. +apply/setIidPl; apply/subsetP=> a Da; rewrite inE. +by apply/subsetP=> x Rx; rewrite inE gact_stable. +Qed. + +Lemma astabsD1 S : 'N(S^# | to) = 'N(S | to). +Proof. +case S1: (1 \in S); last first. + by rewrite (setDidPl _) // disjoint_sym disjoints_subset sub1set inE S1. +apply/eqP; rewrite eqEsubset andbC -{1}astabsIdom -{1}astabs1 setIC astabsD /=. +by rewrite -{2}(setD1K S1) -astabsIdom -{1}astabs1 astabsU. +Qed. + +Lemma gacts_range A : A \subset D -> {acts A, on group R | to}. +Proof. by move=> sAD; split; rewrite ?astabs_range. Qed. + +Lemma acts_subnorm_gacent A : A \subset D -> + [acts 'N_D(A), on 'C_(| to)(A) | to]. +Proof. +move=> sAD; rewrite gacentE // actsI ?astabs_range ?subsetIl //. +by rewrite -{2}(setIidPr sAD) acts_subnorm_fix. +Qed. + +Lemma acts_subnorm_subgacent A B S : + A \subset D -> [acts B, on S | to] -> [acts 'N_B(A), on 'C_(S | to)(A) | to]. +Proof. +move=> sAD actsB; rewrite actsI //; first by rewrite subIset ?actsB. +by rewrite (subset_trans _ (acts_subnorm_gacent sAD)) ?setSI ?(acts_dom actsB). +Qed. + +Lemma acts_gen A S : + S \subset R -> [acts A, on S | to] -> [acts A, on <<S>> | to]. +Proof. +move=> sSR actsA; apply: {A}subset_trans actsA _. +apply/subsetP=> a nSa; have Da := astabs_dom nSa; rewrite !inE Da. +apply: subset_trans (_ : <<S>> \subset actm to a @*^-1 <<S>>) _. + rewrite gen_subG subsetI sSR; apply/subsetP=> x Sx. + by rewrite inE /= actmE ?mem_gen // astabs_act. +by apply/subsetP=> x; rewrite !inE; case/andP=> Rx; rewrite /= actmE. +Qed. + +Lemma acts_joing A M N : + M \subset R -> N \subset R -> [acts A, on M | to] -> [acts A, on N | to] -> + [acts A, on M <*> N | to]. +Proof. by move=> sMR sNR nMA nNA; rewrite acts_gen ?actsU // subUset sMR. Qed. + +Lemma injm_actm a : 'injm (actm to a). +Proof. +apply/injmP=> x y Rx Ry; rewrite /= /actm; case: ifP => Da //. +exact: act_inj. +Qed. + +Lemma im_actm a : actm to a @* R = R. +Proof. +apply/eqP; rewrite eqEcard (card_injm (injm_actm a)) // leqnn andbT. +apply/subsetP=> _ /morphimP[x Rx _ ->] /=. +by rewrite /actm; case: ifP => // Da; rewrite gact_stable. +Qed. + +Lemma acts_char G M : G \subset D -> M \char R -> [acts G, on M | to]. +Proof. +move=> sGD /charP[sMR charM]. +apply/subsetP=> a Ga; have Da := subsetP sGD a Ga; rewrite !inE Da. +apply/subsetP=> x Mx; have Rx := subsetP sMR x Mx. +by rewrite inE -(charM _ (injm_actm a) (im_actm a)) -actmE // mem_morphim. +Qed. + +Lemma gacts_char G M : + G \subset D -> M \char R -> {acts G, on group M | to}. +Proof. by move=> sGD charM; split; rewrite (acts_char, char_sub). Qed. + +Section Restrict. + +Variables (A : {group aT}) (sAD : A \subset D). + +Lemma ract_is_groupAction : is_groupAction R (to \ sAD). +Proof. by move=> a Aa /=; rewrite ractpermE actperm_Aut ?(subsetP sAD). Qed. + +Canonical ract_groupAction := GroupAction ract_is_groupAction. + +Lemma gacent_ract B : 'C_(|ract_groupAction)(B) = 'C_(|to)(A :&: B). +Proof. by rewrite /gacent afix_ract setIA (setIidPr sAD). Qed. + +End Restrict. + +Section ActBy. + +Variables (A : {group aT}) (G : {group rT}) (nGAg : {acts A, on group G | to}). + +Lemma actby_is_groupAction : is_groupAction G <[nGAg]>. +Proof. +move=> a Aa; rewrite /= inE; apply/andP; split. + apply/subsetP=> x; apply: contraR => Gx. + by rewrite actpermE /= /actby (negbTE Gx). +apply/morphicP=> x y Gx Gy; rewrite !actpermE /= /actby Aa groupM ?Gx ?Gy //=. +by case nGAg; move/acts_dom; do 2!move/subsetP=> ?; rewrite gactM; auto. +Qed. + +Canonical actby_groupAction := GroupAction actby_is_groupAction. + +Lemma gacent_actby B : + 'C_(|actby_groupAction)(B) = 'C_(G | to)(A :&: B). +Proof. +rewrite /gacent afix_actby !setIA setIid setIUr setICr set0U. +by have [nAG sGR] := nGAg; rewrite (setIidPr (acts_dom nAG)) (setIidPl sGR). +Qed. + +End ActBy. + +Section Quotient. + +Variable H : {group rT}. + +Lemma acts_qact_dom_norm : {acts qact_dom to H, on 'N(H) | to}. +Proof. +move=> a HDa /= x; rewrite {2}(('N(H) =P to^~ a @^-1: 'N(H)) _) ?inE {x}//. +rewrite eqEcard (card_preimset _ (act_inj _ _)) leqnn andbT. +apply/subsetP=> x Nx; rewrite inE; move/(astabs_act (H :* x)): HDa. +rewrite mem_rcosets mulSGid ?normG // Nx => /rcosetsP[y Ny defHy]. +suffices: to x a \in H :* y by apply: subsetP; rewrite mul_subG ?sub1set ?normG. +by rewrite -defHy; apply: mem_imset; exact: rcoset_refl. +Qed. + +Lemma qact_is_groupAction : is_groupAction (R / H) (to / H). +Proof. +move=> a HDa /=; have Da := astabs_dom HDa. +rewrite inE; apply/andP; split. + apply/subsetP=> Hx /=; case: (cosetP Hx) => x Nx ->{Hx}. + apply: contraR => R'Hx; rewrite actpermE qactE // gact_out //. + by apply: contra R'Hx; apply: mem_morphim. +apply/morphicP=> Hx Hy; rewrite !actpermE. +case/morphimP=> x Nx Gx ->{Hx}; case/morphimP=> y Ny Gy ->{Hy}. +by rewrite -morphM ?qactE ?groupM ?gactM // morphM ?acts_qact_dom_norm. +Qed. + +Canonical quotient_groupAction := GroupAction qact_is_groupAction. + +Lemma qact_domE : H \subset R -> qact_dom to H = 'N(H | to). +Proof. +move=> sHR; apply/setP=> a; apply/idP/idP=> nHa; have Da := astabs_dom nHa. + rewrite !inE Da; apply/subsetP=> x Hx; rewrite inE -(rcoset1 H). + have /rcosetsP[y Ny defHy]: to^~ a @: H \in rcosets H 'N(H). + by rewrite (astabs_act _ nHa) -{1}(mulg1 H) -rcosetE mem_imset ?group1. + by rewrite (@rcoset_transl _ H 1 y) -defHy -1?(gact1 Da) mem_setact. +rewrite !inE Da; apply/subsetP=> Hx; rewrite inE => /rcosetsP[x Nx ->{Hx}]. +apply/imsetP; exists (to x a). + case Rx: (x \in R); last by rewrite gact_out ?Rx. + rewrite inE; apply/subsetP=> _ /imsetP[y Hy ->]. + rewrite -(actKVin to Da y) -gactJ // ?(subsetP sHR, astabs_act, groupV) //. + by rewrite memJ_norm // astabs_act ?groupV. +apply/eqP; rewrite rcosetE eqEcard. +rewrite (card_imset _ (act_inj _ _)) !card_rcoset leqnn andbT. +apply/subsetP=> _ /imsetP[y Hxy ->]; rewrite !mem_rcoset in Hxy *. +have Rxy := subsetP sHR _ Hxy; rewrite -(mulgKV x y). +case Rx: (x \in R); last by rewrite !gact_out ?mulgK // 1?groupMl ?Rx. +by rewrite -gactV // -gactM 1?groupMr ?groupV // mulgK astabs_act. +Qed. + +End Quotient. + +Section Mod. + +Variable H : {group aT}. + +Lemma modact_is_groupAction : is_groupAction 'C_(|to)(H) (to %% H). +Proof. +move=> Ha /morphimP[a Na Da ->]; have NDa: a \in 'N_D(H) by exact/setIP. +rewrite inE; apply/andP; split. + apply/subsetP=> x; rewrite 2!inE andbC actpermE /= modactEcond //. + by apply: contraR; case: ifP => // E Rx; rewrite gact_out. +apply/morphicP=> x y /setIP[Rx cHx] /setIP[Ry cHy]. +rewrite /= !actpermE /= !modactE ?gactM //. +suffices: x * y \in 'C_(|to)(H) by case/setIP. +rewrite groupM //; exact/setIP. +Qed. + +Canonical mod_groupAction := GroupAction modact_is_groupAction. + +Lemma modgactE x a : + H \subset 'C(R | to) -> a \in 'N_D(H) -> (to %% H)%act x (coset H a) = to x a. +Proof. +move=> cRH NDa /=; have [Da Na] := setIP NDa. +have [Rx | notRx] := boolP (x \in R). + by rewrite modactE //; apply/afixP=> b /setIP[_ /(subsetP cRH)/astab_act->]. +rewrite gact_out //= /modact; case: ifP => // _; rewrite gact_out //. +suffices: a \in D :&: coset H a by case/mem_repr/setIP. +by rewrite inE Da val_coset // rcoset_refl. +Qed. + +Lemma gacent_mod G M : + H \subset 'C(M | to) -> G \subset 'N(H) -> + 'C_(M | mod_groupAction)(G / H) = 'C_(M | to)(G). +Proof. +move=> cMH nHG; rewrite -gacentIdom gacentE ?subsetIl // setICA. +have sHD: H \subset D by rewrite (subset_trans cMH) ?subsetIl. +rewrite -quotientGI // afix_mod ?setIS // setICA -gacentIim (setIC R) -setIA. +rewrite -gacentE ?subsetIl // gacentIdom setICA (setIidPr _) //. +by rewrite gacentC // ?(subset_trans cMH) ?astabS ?subsetIl // setICA subsetIl. +Qed. + +Lemma acts_irr_mod G M : + H \subset 'C(M | to) -> G \subset 'N(H) -> acts_irreducibly G M to -> + acts_irreducibly (G / H) M mod_groupAction. +Proof. +move=> cMH nHG /mingroupP[/andP[ntM nMG] minM]. +apply/mingroupP; rewrite ntM astabs_mod ?quotientS //; split=> // L modL ntL. +have cLH: H \subset 'C(L | to) by rewrite (subset_trans cMH) ?astabS //. +apply: minM => //; case/andP: modL => ->; rewrite astabs_mod ?quotientSGK //. +by rewrite (subset_trans cLH) ?astab_sub. +Qed. + +End Mod. + +Lemma modact_coset_astab x a : + a \in D -> (to %% 'C(R | to))%act x (coset _ a) = to x a. +Proof. +move=> Da; apply: modgactE => {x}//. +rewrite !inE Da; apply/subsetP=> _ /imsetP[c Cc ->]. +have Dc := astab_dom Cc; rewrite !inE groupJ //. +apply/subsetP=> x Rx; rewrite inE conjgE !actMin ?groupM ?groupV //. +by rewrite (astab_act Cc) ?actKVin // gact_stable ?groupV. +Qed. + +Lemma acts_irr_mod_astab G M : + acts_irreducibly G M to -> + acts_irreducibly (G / 'C_G(M | to)) M (mod_groupAction _). +Proof. +move=> irrG; have /andP[_ nMG] := mingroupp irrG. +apply: acts_irr_mod irrG; first exact: subsetIr. +by rewrite normsI ?normG // (subset_trans nMG) // astab_norm. +Qed. + +Section CompAct. + +Variables (gT : finGroupType) (G : {group gT}) (f : {morphism G >-> aT}). + +Lemma comp_is_groupAction : is_groupAction R (comp_action to f). +Proof. +move=> a /morphpreP[Ba Dfa]; apply: etrans (actperm_Aut to Dfa). +by congr (_ \in Aut R); apply/permP=> x; rewrite !actpermE. +Qed. +Canonical comp_groupAction := GroupAction comp_is_groupAction. + +Lemma gacent_comp U : 'C_(|comp_groupAction)(U) = 'C_(|to)(f @* U). +Proof. +rewrite /gacent afix_comp ?subIset ?subxx //. +by rewrite -(setIC U) (setIC D) morphim_setIpre. +Qed. + +End CompAct. + +End GroupActionTheory. + +Notation "''C_' ( | to ) ( A )" := (gacent_group to A) : Group_scope. +Notation "''C_' ( G | to ) ( A )" := + (setI_group G 'C_(|to)(A)) : Group_scope. +Notation "''C_' ( | to ) [ a ]" := (gacent_group to [set a%g]) : Group_scope. +Notation "''C_' ( G | to ) [ a ]" := + (setI_group G 'C_(|to)[a]) : Group_scope. + +Notation "to \ sAD" := (ract_groupAction to sAD) : groupAction_scope. +Notation "<[ nGA ] >" := (actby_groupAction nGA) : groupAction_scope. +Notation "to / H" := (quotient_groupAction to H) : groupAction_scope. +Notation "to %% H" := (mod_groupAction to H) : groupAction_scope. +Notation "to \o f" := (comp_groupAction to f) : groupAction_scope. + +(* Operator group isomorphism. *) +Section MorphAction. + +Variables (aT1 aT2 : finGroupType) (rT1 rT2 : finType). +Variables (D1 : {group aT1}) (D2 : {group aT2}). +Variables (to1 : action D1 rT1) (to2 : action D2 rT2). +Variables (A : {set aT1}) (R S : {set rT1}). +Variables (h : rT1 -> rT2) (f : {morphism D1 >-> aT2}). +Hypotheses (actsDR : {acts D1, on R | to1}) (injh : {in R &, injective h}). +Hypothesis defD2 : f @* D1 = D2. +Hypotheses (sSR : S \subset R) (sAD1 : A \subset D1). +Hypothesis hfJ : {in S & D1, morph_act to1 to2 h f}. + +Lemma morph_astabs : f @* 'N(S | to1) = 'N(h @: S | to2). +Proof. +apply/setP=> fx; apply/morphimP/idP=> [[x D1x nSx ->] | nSx]. + rewrite 2!inE -{1}defD2 mem_morphim //=; apply/subsetP=> _ /imsetP[u Su ->]. + by rewrite inE -hfJ ?mem_imset // (astabs_act _ nSx). +have [|x D1x _ def_fx] := morphimP (_ : fx \in f @* D1). + by rewrite defD2 (astabs_dom nSx). +exists x => //; rewrite !inE D1x; apply/subsetP=> u Su. +have /imsetP[u' Su' /injh def_u']: h (to1 u x) \in h @: S. + by rewrite hfJ // -def_fx (astabs_act _ nSx) mem_imset. +by rewrite inE def_u' ?actsDR ?(subsetP sSR). +Qed. + +Lemma morph_astab : f @* 'C(S | to1) = 'C(h @: S | to2). +Proof. +apply/setP=> fx; apply/morphimP/idP=> [[x D1x cSx ->] | cSx]. + rewrite 2!inE -{1}defD2 mem_morphim //=; apply/subsetP=> _ /imsetP[u Su ->]. + by rewrite inE -hfJ // (astab_act cSx). +have [|x D1x _ def_fx] := morphimP (_ : fx \in f @* D1). + by rewrite defD2 (astab_dom cSx). +exists x => //; rewrite !inE D1x; apply/subsetP=> u Su. +rewrite inE -(inj_in_eq injh) ?actsDR ?(subsetP sSR) ?hfJ //. +by rewrite -def_fx (astab_act cSx) ?mem_imset. +Qed. + +Lemma morph_afix : h @: 'Fix_(S | to1)(A) = 'Fix_(h @: S | to2)(f @* A). +Proof. +apply/setP=> hu; apply/imsetP/setIP=> [[u /setIP[Su cAu] ->]|]. + split; first by rewrite mem_imset. + by apply/afixP=> _ /morphimP[x D1x Ax ->]; rewrite -hfJ ?(afixP cAu). +case=> /imsetP[u Su ->] /afixP c_hu_fA; exists u; rewrite // inE Su. +apply/afixP=> x Ax; have Dx := subsetP sAD1 x Ax. +by apply: injh; rewrite ?actsDR ?(subsetP sSR) ?hfJ // c_hu_fA ?mem_morphim. +Qed. + +End MorphAction. + +Section MorphGroupAction. + +Variables (aT1 aT2 rT1 rT2 : finGroupType). +Variables (D1 : {group aT1}) (D2 : {group aT2}). +Variables (R1 : {group rT1}) (R2 : {group rT2}). +Variables (to1 : groupAction D1 R1) (to2 : groupAction D2 R2). +Variables (h : {morphism R1 >-> rT2}) (f : {morphism D1 >-> aT2}). +Hypotheses (iso_h : isom R1 R2 h) (iso_f : isom D1 D2 f). +Hypothesis hfJ : {in R1 & D1, morph_act to1 to2 h f}. +Implicit Types (A : {set aT1}) (S : {set rT1}) (M : {group rT1}). + +Lemma morph_gastabs S : S \subset R1 -> f @* 'N(S | to1) = 'N(h @* S | to2). +Proof. +have [[_ defD2] [injh _]] := (isomP iso_f, isomP iso_h). +move=> sSR1; rewrite (morphimEsub _ sSR1). +apply: (morph_astabs (gact_stable to1) (injmP injh)) => // u x. +by move/(subsetP sSR1); exact: hfJ. +Qed. + +Lemma morph_gastab S : S \subset R1 -> f @* 'C(S | to1) = 'C(h @* S | to2). +Proof. +have [[_ defD2] [injh _]] := (isomP iso_f, isomP iso_h). +move=> sSR1; rewrite (morphimEsub _ sSR1). +apply: (morph_astab (gact_stable to1) (injmP injh)) => // u x. +by move/(subsetP sSR1); exact: hfJ. +Qed. + +Lemma morph_gacent A : A \subset D1 -> h @* 'C_(|to1)(A) = 'C_(|to2)(f @* A). +Proof. +have [[_ defD2] [injh defR2]] := (isomP iso_f, isomP iso_h). +move=> sAD1; rewrite !gacentE //; last by rewrite -defD2 morphimS. +rewrite morphimEsub ?subsetIl // -{1}defR2 morphimEdom. +exact: (morph_afix (gact_stable to1) (injmP injh)). +Qed. + +Lemma morph_gact_irr A M : + A \subset D1 -> M \subset R1 -> + acts_irreducibly (f @* A) (h @* M) to2 = acts_irreducibly A M to1. +Proof. +move=> sAD1 sMR1. +have [[injf defD2] [injh defR2]] := (isomP iso_f, isomP iso_h). +have h_eq1 := morphim_injm_eq1 injh. +apply/mingroupP/mingroupP=> [] [/andP[ntM actAM] minM]. + split=> [|U]; first by rewrite -h_eq1 // ntM -(injmSK injf) ?morph_gastabs. + case/andP=> ntU acts_fAU sUM; have sUR1 := subset_trans sUM sMR1. + apply: (injm_morphim_inj injh) => //; apply: minM; last exact: morphimS. + by rewrite h_eq1 // ntU -morph_gastabs ?morphimS. +split=> [|U]; first by rewrite h_eq1 // ntM -morph_gastabs ?morphimS. +case/andP=> ntU acts_fAU sUhM. +have sUhR1 := subset_trans sUhM (morphimS h sMR1). +have sU'M: h @*^-1 U \subset M by rewrite sub_morphpre_injm. +rewrite /= -(minM _ _ sU'M) ?morphpreK // -h_eq1 ?subsetIl // -(injmSK injf) //. +by rewrite morph_gastabs ?(subset_trans sU'M) // morphpreK ?ntU. +Qed. + +End MorphGroupAction. + +(* Conjugation and right translation actions. *) +Section InternalActionDefs. + +Variable gT : finGroupType. +Implicit Type A : {set gT}. +Implicit Type G : {group gT}. + +(* This is not a Canonical action because it is seldom used, and it would *) +(* cause too many spurious matches (any group product would be viewed as an *) +(* action!). *) +Definition mulgr_action := TotalAction (@mulg1 gT) (@mulgA gT). + +Canonical conjg_action := TotalAction (@conjg1 gT) (@conjgM gT). + +Lemma conjg_is_groupAction : is_groupAction setT conjg_action. +Proof. +move=> a _; rewrite /= inE; apply/andP; split. + by apply/subsetP=> x _; rewrite inE. +by apply/morphicP=> x y _ _; rewrite !actpermE /= conjMg. +Qed. + +Canonical conjg_groupAction := GroupAction conjg_is_groupAction. + +Lemma rcoset_is_action : is_action setT (@rcoset gT). +Proof. +by apply: is_total_action => [A|A x y]; rewrite !rcosetE (mulg1, rcosetM). +Qed. + +Canonical rcoset_action := Action rcoset_is_action. + +Canonical conjsg_action := TotalAction (@conjsg1 gT) (@conjsgM gT). + +Lemma conjG_is_action : is_action setT (@conjG_group gT). +Proof. +apply: is_total_action => [G | G x y]; apply: val_inj; rewrite /= ?act1 //. +exact: actM. +Qed. + +Definition conjG_action := Action conjG_is_action. + +End InternalActionDefs. + +Notation "'R" := (@mulgr_action _) (at level 8) : action_scope. +Notation "'Rs" := (@rcoset_action _) (at level 8) : action_scope. +Notation "'J" := (@conjg_action _) (at level 8) : action_scope. +Notation "'J" := (@conjg_groupAction _) (at level 8) : groupAction_scope. +Notation "'Js" := (@conjsg_action _) (at level 8) : action_scope. +Notation "'JG" := (@conjG_action _) (at level 8) : action_scope. +Notation "'Q" := ('J / _)%act (at level 8) : action_scope. +Notation "'Q" := ('J / _)%gact (at level 8) : groupAction_scope. + +Section InternalGroupAction. + +Variable gT : finGroupType. +Implicit Types A B : {set gT}. +Implicit Types G H : {group gT}. +Implicit Type x : gT. + +(* Various identities for actions on groups. *) + +Lemma orbitR G x : orbit 'R G x = x *: G. +Proof. by rewrite -lcosetE. Qed. + +Lemma astab1R x : 'C[x | 'R] = 1. +Proof. +apply/trivgP/subsetP=> y cxy. +by rewrite -(mulKg x y) [x * y](astab1P cxy) mulVg set11. +Qed. + +Lemma astabR G : 'C(G | 'R) = 1. +Proof. +apply/trivgP/subsetP=> x cGx. +by rewrite -(mul1g x) [1 * x](astabP cGx) group1. +Qed. + +Lemma astabsR G : 'N(G | 'R) = G. +Proof. +apply/setP=> x; rewrite !inE -setactVin ?inE //=. +by rewrite -groupV -{1 3}(mulg1 G) rcoset_sym -sub1set -mulGS -!rcosetE. +Qed. + +Lemma atransR G : [transitive G, on G | 'R]. +Proof. by rewrite /atrans -{1}(mul1g G) -orbitR mem_imset. Qed. + +Lemma faithfulR G : [faithful G, on G | 'R]. +Proof. by rewrite /faithful astabR subsetIr. Qed. + +Definition Cayley_repr G := actperm <[atrans_acts (atransR G)]>. + +Theorem Cayley_isom G : isom G (Cayley_repr G @* G) (Cayley_repr G). +Proof. exact: faithful_isom (faithfulR G). Qed. + +Theorem Cayley_isog G : G \isog Cayley_repr G @* G. +Proof. exact: isom_isog (Cayley_isom G). Qed. + +Lemma orbitJ G x : orbit 'J G x = x ^: G. Proof. by []. Qed. + +Lemma afixJ A : 'Fix_('J)(A) = 'C(A). +Proof. +apply/setP=> x; apply/afixP/centP=> cAx y Ay /=. + by rewrite /commute conjgC cAx. +by rewrite conjgE cAx ?mulKg. +Qed. + +Lemma astabJ A : 'C(A |'J) = 'C(A). +Proof. +apply/setP=> x; apply/astabP/centP=> cAx y Ay /=. + by apply: esym; rewrite conjgC cAx. +by rewrite conjgE -cAx ?mulKg. +Qed. + +Lemma astab1J x : 'C[x |'J] = 'C[x]. +Proof. by rewrite astabJ cent_set1. Qed. + +Lemma astabsJ A : 'N(A | 'J) = 'N(A). +Proof. by apply/setP=> x; rewrite -2!groupV !inE -conjg_preim -sub_conjg. Qed. + +Lemma setactJ A x : 'J^*%act A x = A :^ x. Proof. by []. Qed. + +Lemma gacentJ A : 'C_(|'J)(A) = 'C(A). +Proof. by rewrite gacentE ?setTI ?subsetT ?afixJ. Qed. + +Lemma orbitRs G A : orbit 'Rs G A = rcosets A G. Proof. by []. Qed. + +Lemma sub_afixRs_norms G x A : (G :* x \in 'Fix_('Rs)(A)) = (A \subset G :^ x). +Proof. +rewrite inE /=; apply: eq_subset_r => a. +rewrite inE rcosetE -(can2_eq (rcosetKV x) (rcosetK x)) -!rcosetM. +rewrite eqEcard card_rcoset leqnn andbT mulgA (conjgCV x) mulgK. +by rewrite -{2 3}(mulGid G) mulGS sub1set -mem_conjg. +Qed. + +Lemma sub_afixRs_norm G x : (G :* x \in 'Fix_('Rs)(G)) = (x \in 'N(G)). +Proof. by rewrite sub_afixRs_norms -groupV inE sub_conjgV. Qed. + +Lemma afixRs_rcosets A G : 'Fix_(rcosets G A | 'Rs)(G) = rcosets G 'N_A(G). +Proof. +apply/setP=> Gx; apply/setIP/rcosetsP=> [[/rcosetsP[x Ax ->]]|[x]]. + by rewrite sub_afixRs_norm => Nx; exists x; rewrite // inE Ax. +by case/setIP=> Ax Nx ->; rewrite -{1}rcosetE mem_imset // sub_afixRs_norm. +Qed. + +Lemma astab1Rs G : 'C[G : {set gT} | 'Rs] = G. +Proof. +apply/setP=> x. +by apply/astab1P/idP=> /= [<- | Gx]; rewrite rcosetE ?rcoset_refl ?rcoset_id. +Qed. + +Lemma actsRs_rcosets H G : [acts G, on rcosets H G | 'Rs]. +Proof. by rewrite -orbitRs acts_orbit ?subsetT. Qed. + +Lemma transRs_rcosets H G : [transitive G, on rcosets H G | 'Rs]. +Proof. by rewrite -orbitRs atrans_orbit. Qed. + +(* This is the second part of Aschbacher (5.7) *) +Lemma astabRs_rcosets H G : 'C(rcosets H G | 'Rs) = gcore H G. +Proof. +have transGH := transRs_rcosets H G. +by rewrite (astab_trans_gcore transGH (orbit_refl _ G _)) astab1Rs. +Qed. + +Lemma orbitJs G A : orbit 'Js G A = A :^: G. Proof. by []. Qed. + +Lemma astab1Js A : 'C[A | 'Js] = 'N(A). +Proof. by apply/setP=> x; apply/astab1P/normP. Qed. + +Lemma card_conjugates A G : #|A :^: G| = #|G : 'N_G(A)|. +Proof. by rewrite card_orbit astab1Js. Qed. + +Lemma afixJG G A : (G \in 'Fix_('JG)(A)) = (A \subset 'N(G)). +Proof. by apply/afixP/normsP=> nG x Ax; apply/eqP; move/eqP: (nG x Ax). Qed. + +Lemma astab1JG G : 'C[G | 'JG] = 'N(G). +Proof. +by apply/setP=> x; apply/astab1P/normP=> [/congr_group | /group_inj]. +Qed. + +Lemma dom_qactJ H : qact_dom 'J H = 'N(H). +Proof. by rewrite qact_domE ?subsetT ?astabsJ. Qed. + +Lemma qactJ H (Hy : coset_of H) x : + 'Q%act Hy x = if x \in 'N(H) then Hy ^ coset H x else Hy. +Proof. +case: (cosetP Hy) => y Ny ->{Hy}. +by rewrite qactEcond // dom_qactJ; case Nx: (x \in 'N(H)); rewrite ?morphJ. +Qed. + +Lemma actsQ A B H : + A \subset 'N(H) -> A \subset 'N(B) -> [acts A, on B / H | 'Q]. +Proof. +by move=> nHA nBA; rewrite acts_quotient // subsetI dom_qactJ nHA astabsJ. +Qed. + +Lemma astabsQ G H : H <| G -> 'N(G / H | 'Q) = 'N(H) :&: 'N(G). +Proof. by move=> nsHG; rewrite astabs_quotient // dom_qactJ astabsJ. Qed. + +Lemma astabQ H Abar : 'C(Abar |'Q) = coset H @*^-1 'C(Abar). +Proof. +apply/setP=> x; rewrite inE /= dom_qactJ morphpreE in_setI /=. +apply: andb_id2l => Nx; rewrite !inE -sub1set centsC cent_set1. +apply: eq_subset_r => {Abar} Hy; rewrite inE qactJ Nx (sameP eqP conjg_fixP). +by rewrite (sameP cent1P eqP) (sameP commgP eqP). +Qed. + +Lemma sub_astabQ A H Bbar : + (A \subset 'C(Bbar | 'Q)) = (A \subset 'N(H)) && (A / H \subset 'C(Bbar)). +Proof. +rewrite astabQ -morphpreIdom subsetI; apply: andb_id2l => nHA. +by rewrite -sub_quotient_pre. +Qed. + +Lemma sub_astabQR A B H : + A \subset 'N(H) -> B \subset 'N(H) -> + (A \subset 'C(B / H | 'Q)) = ([~: A, B] \subset H). +Proof. +move=> nHA nHB; rewrite sub_astabQ nHA /= (sameP commG1P eqP). +by rewrite eqEsubset sub1G andbT -quotientR // quotient_sub1 // comm_subG. +Qed. + +Lemma astabQR A H : A \subset 'N(H) -> + 'C(A / H | 'Q) = [set x in 'N(H) | [~: [set x], A] \subset H]. +Proof. +move=> nHA; apply/setP=> x; rewrite astabQ -morphpreIdom 2!inE -astabQ. +by case nHx: (x \in _); rewrite //= -sub1set sub_astabQR ?sub1set. +Qed. + +Lemma quotient_astabQ H Abar : 'C(Abar | 'Q) / H = 'C(Abar). +Proof. by rewrite astabQ cosetpreK. Qed. + +Lemma conj_astabQ A H x : + x \in 'N(H) -> 'C(A / H | 'Q) :^ x = 'C(A :^ x / H | 'Q). +Proof. +move=> nHx; apply/setP=> y; rewrite !astabQ mem_conjg !in_setI -mem_conjg. +rewrite -normJ (normP nHx) quotientJ //; apply/andb_id2l => nHy. +by rewrite !inE centJ morphJ ?groupV ?morphV // -mem_conjg. +Qed. + +Section CardClass. + +Variable G : {group gT}. + +Lemma index_cent1 x : #|G : 'C_G[x]| = #|x ^: G|. +Proof. by rewrite -astab1J -card_orbit. Qed. + +Lemma classes_partition : partition (classes G) G. +Proof. by apply: orbit_partition; apply/actsP=> x Gx y; exact: groupJr. Qed. + +Lemma sum_card_class : \sum_(C in classes G) #|C| = #|G|. +Proof. by apply: acts_sum_card_orbit; apply/actsP=> x Gx y; exact: groupJr. Qed. + +Lemma class_formula : \sum_(C in classes G) #|G : 'C_G[repr C]| = #|G|. +Proof. +rewrite -sum_card_class; apply: eq_bigr => _ /imsetP[x Gx ->]. +have: x \in x ^: G by rewrite -{1}(conjg1 x) mem_imset. +by case/mem_repr/imsetP=> y Gy ->; rewrite index_cent1 classGidl. +Qed. + +Lemma abelian_classP : reflect {in G, forall x, x ^: G = [set x]} (abelian G). +Proof. +rewrite /abelian -astabJ astabC. +by apply: (iffP subsetP) => cGG x Gx; apply/orbit1P; exact: cGG. +Qed. + +Lemma card_classes_abelian : abelian G = (#|classes G| == #|G|). +Proof. +have cGgt0 C: C \in classes G -> 1 <= #|C| ?= iff (#|C| == 1)%N. + by case/imsetP=> x _ ->; rewrite eq_sym -index_cent1. +rewrite -sum_card_class -sum1_card (leqif_sum cGgt0). +apply/abelian_classP/forall_inP=> [cGG _ /imsetP[x Gx ->]| cGG x Gx]. + by rewrite cGG ?cards1. +apply/esym/eqP; rewrite eqEcard sub1set cards1 class_refl leq_eqVlt cGG //. +exact: mem_imset. +Qed. + +End CardClass. + +End InternalGroupAction. + +Lemma gacentQ (gT : finGroupType) (H : {group gT}) (A : {set gT}) : + 'C_(|'Q)(A) = 'C(A / H). +Proof. +apply/setP=> Hx; case: (cosetP Hx) => x Nx ->{Hx}. +rewrite -sub_cent1 -astab1J astabC sub1set -(quotientInorm H A). +have defD: qact_dom 'J H = 'N(H) by rewrite qact_domE ?subsetT ?astabsJ. +rewrite !(inE, mem_quotient) //= defD setIC. +apply/subsetP/subsetP=> [cAx _ /morphimP[a Na Aa ->] | cAx a Aa]. + by move/cAx: Aa; rewrite !inE qactE ?defD ?morphJ. +have [_ Na] := setIP Aa; move/implyP: (cAx (coset H a)); rewrite mem_morphim //. +by rewrite !inE qactE ?defD ?morphJ. +Qed. + +Section AutAct. + +Variable (gT : finGroupType) (G : {set gT}). + +Definition autact := act ('P \ subsetT (Aut G)). +Canonical aut_action := [action of autact]. + +Lemma autactK a : actperm aut_action a = a. +Proof. by apply/permP=> x; rewrite permE. Qed. + +Lemma autact_is_groupAction : is_groupAction G aut_action. +Proof. by move=> a Aa /=; rewrite autactK. Qed. +Canonical aut_groupAction := GroupAction autact_is_groupAction. + +End AutAct. + +Arguments Scope aut_action [_ group_scope]. +Arguments Scope aut_groupAction [_ group_scope]. +Notation "[ 'Aut' G ]" := (aut_action G) : action_scope. +Notation "[ 'Aut' G ]" := (aut_groupAction G) : groupAction_scope. + + |
