(* (c) Copyright 2006-2016 Microsoft Corporation and Inria.                  *)
(* Distributed under the terms of CeCILL-B.                                  *)
From mathcomp
From mathcomp
From mathcomp
From mathcomp
(******************************************************************************)
(* Constructions based on abelian groups and their structure, with some       *)
(* emphasis on elementary abelian p-groups.                                   *)
(*          'Ldiv_n() == the set of all x that satisfy x ^+ n = 1, or,        *)
(*                       equivalently the set of x whose order divides n.     *)
(*         'Ldiv_n(G) == the set of x in G that satisfy x ^+ n = 1.           *)
(*                    := G :&: 'Ldiv_n() (pure Notation)                      *)
(*         exponent G == the exponent of G: the least e such that x ^+ e = 1  *)
(*                       for all x in G (the LCM of the orders of x \in G).   *)
(*                       If G is nilpotent its exponent is reached. Note that *)
(*                       `exponent G %| m' reads as `G has exponent m'.       *)
(*              'm(G) == the generator rank of G: the size of a smallest      *)
(*                       generating set for G (this is a basis for G if G     *)
(*                       abelian).                                            *)
(*     abelian_type G == the abelian type of G : if G is abelian, a lexico-   *)
(*                       graphically maximal sequence of the orders of the    *)
(*                       elements of a minimal basis of G (if G is a p-group  *)
(*                       this is the sequence of orders for any basis of G,   *)
(*                       sorted in decending order).                          *)
(*       homocyclic G == G is the direct product of cycles of equal order,    *)
(*                       i.e., G is abelian with constant abelian type.       *)
(*        p.-abelem G == G is an elementary abelian p-group, i.e., it is      *)
(*                       an abelian p-group of exponent p, and thus of order  *)
(*                       p ^ 'm(G) and rank (logn p #|G|).                    *)
(*        is_abelem G == G is an elementary abelian p-group for some prime p. *)
(*            'E_p(G) == the set of elementary abelian p-subgroups of G.      *)
(*                    := [set E : {group _} | p.-abelem E & E \subset G]      *)
(*          'E_p^n(G) == the set of elementary abelian p-subgroups of G of    *)
(*                       order p ^ n (or, equivalently, of rank n).           *)
(*                    := [set E in 'E_p(G) | logn p #|E| == n]                *)
(*                    := [set E in 'E_p(G) | #|E| == p ^ n]%N if p is prime   *)
(*           'E*_p(G) == the set of maximal elementary abelian p-subgroups    *)
(*                       of G.                                                *)
(*                    := [set E | [max E | E \in 'E_p(G)]]                    *)
(*            'E^n(G) == the set of elementary abelian subgroups of G that    *)
(*                       have gerank n (i.e., p-rank n for some prime p).     *)
(*                    := \bigcup_(0 <= p < #|G|.+1) 'E_p^n(G)                 *)
(*            'r_p(G) == the p-rank of G: the maximal rank of an elementary   *)
(*                       subgroup of G.                                       *)
(*                    := \max_(E in 'E_p(G)) logn p #|E|.                     *)
(*              'r(G) == the rank of G.                                       *)
(*                    := \max_(0 <= p < #|G|.+1) 'm_p(G).                     *)
(* Note that 'r(G) coincides with 'r_p(G) if G is a p-group, and with 'm(G)   *)
(* if G is abelian, but is much more useful than 'm(G) in the proof of the    *)
(* Odd Order Theorem.                                                         *)
(*          'Ohm_n(G) == the group generated by the x in G with order p ^ m   *)
(*                       for some prime p and some m <= n. Usually, G will be *)
(*                       a p-group, so 'Ohm_n(G) will be generated by         *)
(*                       'Ldiv_(p ^ n)(G), set of elements of G of order at   *)
(*                       most p ^ n. If G is also abelian then 'Ohm_n(G)      *)
(*                       consists exactly of those element, and the abelian   *)
(*                       type of G can be computed from the orders of the     *)
(*                       'Ohm_n(G) subgroups.                                 *)
(*          'Mho^n(G) == the group generated by the x ^+ (p ^ n) for x a      *)
(*                       p-element of G for some prime p. Usually G is a      *)
(*                       p-group, and 'Mho^n(G) is generated by all such      *)
(*                       x ^+ (p ^ n); it consists of exactly these if G is   *)
(*                       also abelian.                                        *)
(******************************************************************************)
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Section AbelianDefs.
(* We defer the definition of the functors ('Omh_n(G), 'Mho^n(G)) because     *)
(* they must quantify over the finGroupType explicitly.                       *)
Variable gT : finGroupType.
Implicit Types (x : gT) (A B : {set gT}) (pi : nat_pred) (p n : nat).
Definition Ldiv n := [set x : gT | x ^+ n == 1].
Definition exponent A := \big[lcmn/1%N]_(x in A) #[x].
Definition abelem p A := [&& p.-group A, abelian A & exponent A %| p].
Definition is_abelem A := abelem (pdiv #|A|) A.
Definition pElem p A := [set E : {group gT} | E \subset A & abelem p E].
Definition pnElem p n A := [set E in pElem p A | logn p #|E| == n].
Definition nElem n A :=  \bigcup_(0 <= p < #|A|.+1) pnElem p n A.
Definition pmaxElem p A := [set E | [max E | E \in pElem p A]].
Definition p_rank p A := \max_(E in pElem p A) logn p #|E|.
Definition rank A := \max_(0 <= p < #|A|.+1) p_rank p A.
Definition gen_rank A := #|[arg min_(B < A | <<B>> == A) #|B|]|.
(* The definition of abelian_type depends on an existence lemma. *)
(* The definition of homocyclic depends on abelian_type. *)
End AbelianDefs.
Arguments exponent {gT} A%g.
Arguments abelem {gT} p%N A%g.
Arguments is_abelem {gT} A%g.
Arguments pElem {gT} p%N A%g.
Arguments pnElem {gT} p%N n%N A%g.
Arguments nElem {gT} n%N A%g.
Arguments pmaxElem {gT} p%N A%g.
Arguments p_rank {gT} p%N A%g.
Arguments rank {gT} A%g.
Arguments gen_rank {gT} A%g.
Notation "''Ldiv_' n ()" := (Ldiv _ n)
(at level 8, n at level 2, format "''Ldiv_' n ()") : group_scope.
Notation "''Ldiv_' n ( G )" := (G :&: 'Ldiv_n())
(at level 8, n at level 2, format "''Ldiv_' n ( G )") : group_scope.
Prenex Implicits exponent.
Notation "p .-abelem" := (abelem p)
(at level 2, format "p .-abelem") : group_scope.
Notation "''E_' p ( G )" := (pElem p G)
(at level 8, p at level 2, format "''E_' p ( G )") : group_scope.
Notation "''E_' p ^ n ( G )" := (pnElem p n G)
(at level 8, p, n at level 2, format "''E_' p ^ n ( G )") : group_scope.
Notation "''E' ^ n ( G )" := (nElem n G)
(at level 8, n at level 2, format "''E' ^ n ( G )") : group_scope.
Notation "''E*_' p ( G )" := (pmaxElem p G)
(at level 8, p at level 2, format "''E*_' p ( G )") : group_scope.
Notation "''m' ( A )" := (gen_rank A)
(at level 8, format "''m' ( A )") : group_scope.
Notation "''r' ( A )" := (rank A)
(at level 8, format "''r' ( A )") : group_scope.
Notation "''r_' p ( A )" := (p_rank p A)
(at level 8, p at level 2, format "''r_' p ( A )") : group_scope.
Section Functors.
(* A functor needs to quantify over the finGroupType just beore the set. *)
Variables (n : nat) (gT : finGroupType) (A : {set gT}).
Definition Ohm := <<[set x in A | x ^+ (pdiv #[x] ^ n) == 1]>>.
Definition Mho := <<[set x ^+ (pdiv #[x] ^ n) | x in A & (pdiv #[x]).-elt x]>>.
Canonical Ohm_group : {group gT} := Eval hnf in [group of Ohm].
Canonical Mho_group : {group gT} := Eval hnf in [group of Mho].

Lemma OhmPredP (x : gT) :
reflect (exists2 p, prime p & x ^+ (p ^ n) = 1) (x ^+ (pdiv #[x] ^ n) == 1).