aboutsummaryrefslogtreecommitdiff
path: root/mathcomp/solvable/extremal.v
diff options
context:
space:
mode:
authorEnrico Tassi2015-03-09 11:07:53 +0100
committerEnrico Tassi2015-03-09 11:24:38 +0100
commitfc84c27eac260dffd8f2fb1cb56d599f1e3486d9 (patch)
treec16205f1637c80833a4c4598993c29fa0fd8c373 /mathcomp/solvable/extremal.v
Initial commit
Diffstat (limited to 'mathcomp/solvable/extremal.v')
-rw-r--r--mathcomp/solvable/extremal.v2331
1 files changed, 2331 insertions, 0 deletions
diff --git a/mathcomp/solvable/extremal.v b/mathcomp/solvable/extremal.v
new file mode 100644
index 0000000..b8cb69d
--- /dev/null
+++ b/mathcomp/solvable/extremal.v
@@ -0,0 +1,2331 @@
+(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *)
+Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype.
+Require Import bigop finset prime binomial fingroup morphism perm automorphism.
+Require Import presentation quotient action commutator gproduct gfunctor.
+Require Import ssralg finalg zmodp cyclic pgroup center gseries.
+Require Import nilpotent sylow abelian finmodule matrix maximal.
+
+(******************************************************************************)
+(* This file contains the definition and properties of extremal p-groups; *)
+(* it covers and is mostly based on the beginning of Aschbacher, section 23, *)
+(* as well as several exercises of this section. *)
+(* We define canonical representatives for the group classes that cover the *)
+(* extremal p-groups (non-abelian p-groups with a cyclic maximal subgroup): *)
+(* 'Mod_m == the modular group of order m, for m = p ^ n, p prime and n >= 3. *)
+(* 'D_m == the dihedral group of order m, for m = 2n >= 4. *)
+(* 'Q_m == the generalized quaternion group of order m, for m = 2 ^ n >= 8. *)
+(* 'SD_m == the semi-dihedral group of order m, for m = 2 ^ n >= 16. *)
+(* In each case the notation is defined in the %type, %g and %G scopes, where *)
+(* it denotes a finGroupType, a full gset and the full group for that type. *)
+(* However each notation is only meaningful under the given conditions, in *)
+(* 'D_m is only an extremal group for m = 2 ^ n >= 8, and 'D_8 = 'Mod_8 (they *)
+(* are, in fact, beta-convertible). *)
+(* We also define *)
+(* extremal_generators G p n (x, y) <-> G has order p ^ n, x in G has order *)
+(* p ^ n.-1, and y is in G \ <[x]>: thus <[x]> has index p in G, *)
+(* so if p is prime, <[x]> is maximal in G, G is generated by x *)
+(* and y, and G is extremal or abelian. *)
+(* extremal_class G == the class of extremal groups G belongs to: one of *)
+(* ModularGroup, Dihedral, Quaternion, SemiDihedral or NotExtremal. *)
+(* extremal2 G <=> extremal_class G is one of Dihedral, Quaternion, or *)
+(* SemiDihedral; this allows 'D_4 and 'D_8, but excludes 'Mod_(2^n) *)
+(* for n > 3. *)
+(* modular_group_generators p n (x, y) <-> y has order p and acts on x via *)
+(* x ^ y = x ^+ (p ^ n.-2).+1. This is the complement to *)
+(* extremal_generators G p n (x, y) for modular groups. *)
+(* We provide cardinality, presentation, generator and structure theorems for *)
+(* each class of extremal group. The extremal_generators predicate is used to *)
+(* supply structure theorems with all the required data about G; this is *)
+(* completed by an isomorphism assumption (e.g., G \isog 'D_(2 ^ n)), and *)
+(* sometimes other properties (e.g., #[y] == 2 in the semidihedral case). The *)
+(* generators assumption can be deduced generically from the isomorphism *)
+(* assumption, or it can be proved manually for a specific choice of x and y. *)
+(* The extremal_class function is used to formulate synthetic theorems that *)
+(* cover several classes of extremal groups (e.g., Aschbacher ex. 8.3). *)
+(******************************************************************************)
+
+Set Implicit Arguments.
+Unset Strict Implicit.
+Unset Printing Implicit Defensive.
+
+Local Open Scope ring_scope.
+Import GroupScope GRing.Theory.
+
+Reserved Notation "''Mod_' m" (at level 8, m at level 2, format "''Mod_' m").
+Reserved Notation "''D_' m" (at level 8, m at level 2, format "''D_' m").
+Reserved Notation "''SD_' m" (at level 8, m at level 2, format "''SD_' m").
+Reserved Notation "''Q_' m" (at level 8, m at level 2, format "''Q_' m").
+
+Module Extremal.
+
+Section Construction.
+
+Variables q p e : nat.
+(* Construct the semi-direct product of 'Z_q by 'Z_p with 1%R ^ 1%R = e%R, *)
+(* if possible, i.e., if p, q > 1 and there is s \in Aut 'Z_p such that *)
+(* #[s] %| p and s 1%R = 1%R ^+ e. *)
+
+Let a : 'Z_p := Zp1.
+Let b : 'Z_q := Zp1.
+Local Notation B := <[b]>.
+
+Definition aut_of :=
+ odflt 1 [pick s in Aut B | p > 1 & (#[s] %| p) && (s b == b ^+ e)].
+
+Lemma aut_dvdn : #[aut_of] %| #[a].
+Proof.
+rewrite order_Zp1 /aut_of; case: pickP => [s | _]; last by rewrite order1.
+by case/and4P=> _ p_gt1 p_s _; rewrite Zp_cast.
+Qed.
+
+Definition act_morphism := eltm_morphism aut_dvdn.
+
+Definition base_act := ([Aut B] \o act_morphism)%gact.
+
+Lemma act_dom : <[a]> \subset act_dom base_act.
+Proof.
+rewrite cycle_subG 2!inE cycle_id /= eltm_id /aut_of.
+by case: pickP => [op /andP[] | _] //=; rewrite group1.
+Qed.
+
+Definition gact := (base_act \ act_dom)%gact.
+Fact gtype_key : unit. Proof. by []. Qed.
+Definition gtype := locked_with gtype_key (sdprod_groupType gact).
+
+Hypotheses (p_gt1 : p > 1) (q_gt1 : q > 1).
+
+Lemma card : #|[set: gtype]| = (p * q)%N.
+Proof.
+rewrite [gtype]unlock -(sdprod_card (sdprod_sdpair _)).
+rewrite !card_injm ?injm_sdpair1 ?injm_sdpair2 //.
+by rewrite mulnC -!orderE !order_Zp1 !Zp_cast.
+Qed.
+
+Lemma Grp : (exists s, [/\ s \in Aut B, #[s] %| p & s b = b ^+ e]) ->
+ [set: gtype] \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x ^+ e)).
+Proof.
+rewrite [gtype]unlock => [[s [AutBs dvd_s_p sb]]].
+have memB: _ \in B by move=> c; rewrite -Zp_cycle inE.
+have Aa: a \in <[a]> by rewrite !cycle_id.
+have [oa ob]: #[a] = p /\ #[b] = q by rewrite !order_Zp1 !Zp_cast.
+have def_s: aut_of = s.
+ rewrite /aut_of; case: pickP => /= [t | ]; last first.
+ by move/(_ s); case/and4P; rewrite sb.
+ case/and4P=> AutBt _ _ tb; apply: (eq_Aut AutBt) => // b_i.
+ case/cycleP=> i ->; rewrite -(autmE AutBt) -(autmE AutBs) !morphX //=.
+ by rewrite !autmE // sb (eqP tb).
+apply: intro_isoGrp => [|gT G].
+ apply/existsP; exists (sdpair1 _ b, sdpair2 _ a); rewrite /= !xpair_eqE.
+ rewrite -!morphim_cycle ?norm_joinEr ?im_sdpair ?im_sdpair_norm ?eqxx //=.
+ rewrite -!order_dvdn !order_injm ?injm_sdpair1 ?injm_sdpair2 // oa ob !dvdnn.
+ by rewrite -sdpair_act // [act _ _ _]apermE /= eltm_id -morphX // -sb -def_s.
+case/existsP=> -[x y] /= /eqP[defG xq1 yp1 xy].
+have fxP: #[x] %| #[b] by rewrite order_dvdn ob xq1.
+have fyP: #[y] %| #[a] by rewrite order_dvdn oa yp1.
+have fP: {in <[b]> & <[a]>, morph_act gact 'J (eltm fxP) (eltm fyP)}.
+ move=> bj ai; case/cycleP=> j ->{bj}; case/cycleP=> i ->{ai}.
+ rewrite /= !eltmE def_s gactX ?groupX // conjXg morphX //=; congr (_ ^+ j).
+ rewrite /autact /= apermE; elim: i {j} => /= [|i IHi].
+ by rewrite perm1 eltm_id conjg1.
+ rewrite !expgS permM sb -(autmE (groupX i AutBs)) !morphX //= {}IHi.
+ by rewrite -conjXg -xy -conjgM.
+apply/homgP; exists (xsdprod_morphism fP).
+rewrite im_xsdprodm !morphim_cycle //= !eltm_id -norm_joinEr //.
+by rewrite norms_cycle xy mem_cycle.
+Qed.
+
+End Construction.
+
+End Extremal.
+
+Section SpecializeExtremals.
+
+Import Extremal.
+
+Variable m : nat.
+Let p := pdiv m.
+Let q := m %/ p.
+
+Definition modular_gtype := gtype q p (q %/ p).+1.
+Definition dihedral_gtype := gtype q 2 q.-1.
+Definition semidihedral_gtype := gtype q 2 (q %/ p).-1.
+Definition quaternion_kernel :=
+ <<[set u | u ^+ 2 == 1] :\: [set u ^+ 2 | u in [set: gtype q 4 q.-1]]>>.
+Definition quaternion_gtype :=
+ locked_with gtype_key (coset_groupType quaternion_kernel).
+
+End SpecializeExtremals.
+
+Notation "''Mod_' m" := (modular_gtype m) : type_scope.
+Notation "''Mod_' m" := [set: gsort 'Mod_m] : group_scope.
+Notation "''Mod_' m" := [set: gsort 'Mod_m]%G : Group_scope.
+
+Notation "''D_' m" := (dihedral_gtype m) : type_scope.
+Notation "''D_' m" := [set: gsort 'D_m] : group_scope.
+Notation "''D_' m" := [set: gsort 'D_m]%G : Group_scope.
+
+Notation "''SD_' m" := (semidihedral_gtype m) : type_scope.
+Notation "''SD_' m" := [set: gsort 'SD_m] : group_scope.
+Notation "''SD_' m" := [set: gsort 'SD_m]%G : Group_scope.
+
+Notation "''Q_' m" := (quaternion_gtype m) : type_scope.
+Notation "''Q_' m" := [set: gsort 'Q_m] : group_scope.
+Notation "''Q_' m" := [set: gsort 'Q_m]%G : Group_scope.
+
+Section ExtremalTheory.
+
+Implicit Types (gT : finGroupType) (p q m n : nat).
+
+(* This is Aschbacher (23.3), with the isomorphism made explicit, and a *)
+(* slightly reworked case analysis on the prime and exponent; in particular *)
+(* the inverting involution is available for all non-trivial p-cycles. *)
+Lemma cyclic_pgroup_Aut_structure gT p (G : {group gT}) :
+ p.-group G -> cyclic G -> G :!=: 1 ->
+ let q := #|G| in let n := (logn p q).-1 in
+ let A := Aut G in let P := 'O_p(A) in let F := 'O_p^'(A) in
+ exists m : {perm gT} -> 'Z_q,
+ [/\ [/\ {in A & G, forall a x, x ^+ m a = a x},
+ m 1 = 1%R /\ {in A &, {morph m : a b / a * b >-> (a * b)%R}},
+ {in A &, injective m} /\ image m A =i GRing.unit,
+ forall k, {in A, {morph m : a / a ^+ k >-> (a ^+ k)%R}}
+ & {in A, {morph m : a / a^-1 >-> (a^-1)%R}}],
+ [/\ abelian A, cyclic F, #|F| = p.-1
+ & [faithful F, on 'Ohm_1(G) | [Aut G]]]
+ & if n == 0%N then A = F else
+ exists t, [/\ t \in A, #[t] = 2, m t = - 1%R
+ & if odd p then
+ [/\ cyclic A /\ cyclic P,
+ exists s, [/\ s \in A, #[s] = (p ^ n)%N, m s = p.+1%:R & P = <[s]>]
+ & exists s0, [/\ s0 \in A, #[s0] = p, m s0 = (p ^ n).+1%:R
+ & 'Ohm_1(P) = <[s0]>]]
+ else if n == 1%N then A = <[t]>
+ else exists s,
+ [/\ s \in A, #[s] = (2 ^ n.-1)%N, m s = 5%:R, <[s]> \x <[t]> = A
+ & exists s0, [/\ s0 \in A, #[s0] = 2, m s0 = (2 ^ n).+1%:R,
+ m (s0 * t) = (2 ^ n).-1%:R & 'Ohm_1(<[s]>) = <[s0]>]]]].
+Proof.
+move=> pG cycG ntG q n0 A P F; have [p_pr p_dvd_G [n oG]] := pgroup_pdiv pG ntG.
+have [x0 defG] := cyclicP cycG; have Gx0: x0 \in G by rewrite defG cycle_id.
+rewrite {1}/q oG pfactorK //= in n0 *; rewrite {}/n0.
+have [p_gt1 min_p] := primeP p_pr; have p_gt0 := ltnW p_gt1.
+have q_gt1: q > 1 by rewrite cardG_gt1.
+have cAA: abelian A := Aut_cyclic_abelian cycG; have nilA := abelian_nil cAA.
+have oA: #|A| = (p.-1 * p ^ n)%N.
+ by rewrite card_Aut_cyclic // oG totient_pfactor.
+have [sylP hallF]: p.-Sylow(A) P /\ p^'.-Hall(A) F.
+ by rewrite !nilpotent_pcore_Hall.
+have [defPF tiPF]: P * F = A /\ P :&: F = 1.
+ by case/dprodP: (nilpotent_pcoreC p nilA).
+have oP: #|P| = (p ^ n)%N.
+ by rewrite (card_Hall sylP) oA p_part logn_Gauss ?coprimenP ?pfactorK.
+have oF: #|F| = p.-1.
+ apply/eqP; rewrite -(@eqn_pmul2l #|P|) ?cardG_gt0 // -TI_cardMg // defPF.
+ by rewrite oA oP mulnC.
+have [m' [inj_m' defA def_m']]: exists m' : {morphism units_Zp q >-> {perm gT}},
+ [/\ 'injm m', m' @* setT = A & {in G, forall x u, m' u x = x ^+ val u}].
+- rewrite /A /q defG; exists (Zp_unit_morphism x0).
+ by have [->]:= isomP (Zp_unit_isom x0); split=> // y Gy u; rewrite permE Gy.
+pose m (a : {perm gT}) : 'Z_q := val (invm inj_m' a).
+have{def_m'} def_m: {in A & G, forall a x, x ^+ m a = a x}.
+ by move=> a x Aa Gx /=; rewrite -{2}[a](invmK inj_m') ?defA ?def_m'.
+have m1: m 1 = 1%R by rewrite /m morph1.
+have mM: {in A &, {morph m : a b / a * b >-> (a * b)%R}}.
+ by move=> a b Aa Ab; rewrite /m morphM ?defA.
+have mX k: {in A, {morph m : a / a ^+ k >-> (a ^+ k)%R}}.
+ by elim: k => // k IHk a Aa; rewrite expgS exprS mM ?groupX ?IHk.
+have inj_m: {in A &, injective m}.
+ apply: can_in_inj (fun u => m' (insubd (1 : {unit 'Z_q}) u)) _ => a Aa.
+ by rewrite valKd invmK ?defA.
+have{defA} im_m: image m A =i GRing.unit.
+ move=> u; apply/imageP/idP=> [[a Aa ->]| Uu]; first exact: valP.
+ exists (m' (Sub u Uu)) => /=; first by rewrite -defA mem_morphim ?inE.
+ by rewrite /m invmE ?inE.
+have mV: {in A, {morph m : a / a^-1 >-> (a^-1)%R}}.
+ move=> a Aa /=; rewrite -div1r; apply: canRL (mulrK (valP _)) _.
+ by rewrite -mM ?groupV ?mulVg.
+have inv_m (u : 'Z_q) : coprime q u -> {a | a \in A & m a = u}.
+ rewrite -?unitZpE // natr_Zp -im_m => m_u.
+ by exists (iinv m_u); [exact: mem_iinv | rewrite f_iinv].
+have [cycF ffulF]: cyclic F /\ [faithful F, on 'Ohm_1(G) | [Aut G]].
+ have Um0 a: ((m a)%:R : 'F_p) \in GRing.unit.
+ have: m a \in GRing.unit by exact: valP.
+ by rewrite -{1}[m a]natr_Zp unitFpE ?unitZpE // {1}/q oG coprime_pexpl.
+ pose fm0 a := FinRing.unit 'F_p (Um0 a).
+ have natZqp u: (u%:R : 'Z_q)%:R = u %:R :> 'F_p.
+ by rewrite val_Zp_nat // -Fp_nat_mod // modn_dvdm ?Fp_nat_mod.
+ have m0M: {in A &, {morph fm0 : a b / a * b}}.
+ move=> a b Aa Ab; apply: val_inj; rewrite /= -natrM mM //.
+ by rewrite -[(_ * _)%R]Zp_nat natZqp.
+ pose m0 : {morphism A >-> {unit 'F_p}} := Morphism m0M.
+ have im_m0: m0 @* A = [set: {unit 'F_p}].
+ apply/setP=> [[/= u Uu]]; rewrite in_setT morphimEdom; apply/imsetP.
+ have [|a Aa m_a] := inv_m u%:R.
+ by rewrite {1}[q]oG coprime_pexpl // -unitFpE // natZqp natr_Zp.
+ by exists a => //; apply: val_inj; rewrite /= m_a natZqp natr_Zp.
+ have [x1 defG1]: exists x1, 'Ohm_1(G) = <[x1]>.
+ by apply/cyclicP; exact: cyclicS (Ohm_sub _ _) cycG.
+ have ox1: #[x1] = p by rewrite orderE -defG1 (Ohm1_cyclic_pgroup_prime _ pG).
+ have Gx1: x1 \in G by rewrite -cycle_subG -defG1 Ohm_sub.
+ have ker_m0: 'ker m0 = 'C('Ohm_1(G) | [Aut G]).
+ apply/setP=> a; rewrite inE in_setI; apply: andb_id2l => Aa.
+ rewrite 3!inE /= -2!val_eqE /= val_Fp_nat // [1 %% _]modn_small // defG1.
+ apply/idP/subsetP=> [ma1 x1i | ma1].
+ case/cycleP=> i ->{x1i}; rewrite inE gactX // -[_ a]def_m //.
+ by rewrite -(expg_mod_order x1) ox1 (eqP ma1).
+ have:= ma1 x1 (cycle_id x1); rewrite inE -[_ a]def_m //.
+ by rewrite (eq_expg_mod_order x1 _ 1) ox1 (modn_small p_gt1).
+ have card_units_Fp: #|[set: {unit 'F_p}]| = p.-1.
+ by rewrite card_units_Zp // pdiv_id // (@totient_pfactor p 1) ?muln1.
+ have ker_m0_P: 'ker m0 = P.
+ apply: nilpotent_Hall_pcore nilA _.
+ rewrite pHallE -(card_Hall sylP) oP subsetIl /=.
+ rewrite -(@eqn_pmul2r #|m0 @* A|) ?cardG_gt0 //; apply/eqP.
+ rewrite -{1}(card_isog (first_isog _)) card_quotient ?ker_norm //.
+ by rewrite Lagrange ?subsetIl // oA im_m0 mulnC card_units_Fp.
+ have inj_m0: 'ker_F m0 \subset [1] by rewrite setIC ker_m0_P tiPF.
+ split; last by rewrite /faithful -ker_m0.
+ have isogF: F \isog [set: {unit 'F_p}].
+ have sFA: F \subset A by exact: pcore_sub.
+ apply/isogP; exists (restrm_morphism sFA m0); first by rewrite ker_restrm.
+ apply/eqP; rewrite eqEcard subsetT card_injm ?ker_restrm //= oF.
+ by rewrite card_units_Fp.
+ rewrite (isog_cyclic isogF) pdiv_id // -ox1 (isog_cyclic (Zp_unit_isog x1)).
+ by rewrite Aut_prime_cyclic // -orderE ox1.
+exists m; split=> {im_m mV}//; have [n0 | n_gt0] := posnP n.
+ by apply/eqP; rewrite eq_sym eqEcard pcore_sub oF oA n0 muln1 /=.
+have [t At mt]: {t | t \in A & m t = -1}.
+ apply: inv_m; rewrite /= Zp_cast // coprime_modr modn_small // subn1.
+ by rewrite coprimenP // ltnW.
+have ot: #[t] = 2.
+ apply/eqP; rewrite eqn_leq order_gt1 dvdn_leq ?order_dvdn //=.
+ apply/eqP; move/(congr1 m); apply/eqP; rewrite mt m1 eq_sym -subr_eq0.
+ rewrite opprK -val_eqE /= Zp_cast ?modn_small // /q oG ltnW //.
+ by rewrite (leq_trans (_ : 2 ^ 2 <= p ^ 2)) ?leq_sqr ?leq_exp2l.
+ by apply/eqP; apply: inj_m; rewrite ?groupX ?group1 ?mX // mt -signr_odd.
+exists t; split=> //.
+case G4: (~~ odd p && (n == 1%N)).
+ case: (even_prime p_pr) G4 => [p2 | -> //]; rewrite p2 /=; move/eqP=> n1.
+ rewrite n1 /=; apply/eqP; rewrite eq_sym eqEcard cycle_subG At /=.
+ by rewrite -orderE oA ot p2 n1.
+pose e0 : nat := ~~ odd p.
+have{inv_m} [s As ms]: {s | s \in A & m s = (p ^ e0.+1).+1%:R}.
+ apply: inv_m; rewrite val_Zp_nat // coprime_modr /q oG coprime_pexpl //.
+ by rewrite -(@coprime_pexpl e0.+1) // coprimenS.
+have lt_e0_n: e0 < n.
+ by rewrite /e0; case: (~~ _) G4 => //=; rewrite ltn_neqAle eq_sym => ->.
+pose s0 := s ^+ (p ^ (n - e0.+1)).
+have [ms0 os0]: m s0 = (p ^ n).+1%:R /\ #[s0] = p.
+ have m_se e:
+ exists2 k, k = 1 %[mod p] & m (s ^+ (p ^ e)) = (k * p ^ (e + e0.+1)).+1%:R.
+ - elim: e => [|e [k k1 IHe]]; first by exists 1%N; rewrite ?mul1n.
+ rewrite expnSr expgM mX ?groupX // {}IHe -natrX -(add1n (k * _)).
+ rewrite expnDn -(prednK p_gt0) 2!big_ord_recl /= prednK // !exp1n bin1.
+ rewrite bin0 muln1 mul1n mulnCA -expnS (addSn e).
+ set f := (e + _)%N; set sum := (\sum_i _)%N.
+ exists (sum %/ p ^ f.+2 * p + k)%N; first by rewrite modnMDl.
+ rewrite -(addnC k) mulnDl -mulnA -expnS divnK // {}/sum.
+ apply big_ind => [||[i _] /= _]; [exact: dvdn0 | exact: dvdn_add |].
+ rewrite exp1n mul1n /bump !add1n expnMn mulnCA dvdn_mull // -expnM.
+ case: (ltnP f.+1 (f * i.+2)) => [le_f_fi|].
+ by rewrite dvdn_mull ?dvdn_exp2l.
+ rewrite {1}mulnS -(addn1 f) leq_add2l {}/f addnS /e0.
+ case: i e => [] // [] //; case odd_p: (odd p) => //= _.
+ by rewrite bin2odd // mulnAC dvdn_mulr.
+ have [[|d]] := m_se (n - e0.+1)%N; first by rewrite mod0n modn_small.
+ move/eqP; rewrite -/s0 eqn_mod_dvd ?subn1 //=; case/dvdnP=> f -> {d}.
+ rewrite subnK // mulSn -mulnA -expnS -addSn natrD natrM -oG char_Zp //.
+ rewrite mulr0 addr0 => m_s0; split => //.
+ have [d _] := m_se (n - e0)%N; rewrite -subnSK // expnSr expgM -/s0.
+ rewrite addSn subnK // -oG mulrS natrM char_Zp // {d}mulr0 addr0.
+ move/eqP; rewrite -m1 (inj_in_eq inj_m) ?group1 ?groupX // -order_dvdn.
+ move/min_p; rewrite order_eq1; case/predU1P=> [s0_1 | ]; last by move/eqP.
+ move/eqP: m_s0; rewrite eq_sym s0_1 m1 -subr_eq0 mulrSr addrK -val_eqE /=.
+ have pf_gt0: p ^ _ > 0 by move=> e; rewrite expn_gt0 p_gt0.
+ by rewrite val_Zp_nat // /q oG [_ == _]pfactor_dvdn // pfactorK ?ltnn.
+have os: #[s] = (p ^ (n - e0))%N.
+ have: #[s] %| p ^ (n - e0).
+ by rewrite order_dvdn -subnSK // expnSr expgM -order_dvdn os0.
+ case/dvdn_pfactor=> // d; rewrite leq_eqVlt.
+ case/predU1P=> [-> // | lt_d os]; case/idPn: (p_gt1); rewrite -os0.
+ by rewrite order_gt1 negbK -order_dvdn os dvdn_exp2l // -ltnS -subSn.
+have p_s: p.-elt s by rewrite /p_elt os pnat_exp ?pnat_id.
+have defS1: 'Ohm_1(<[s]>) = <[s0]>.
+ apply/eqP; rewrite eq_sym eqEcard cycle_subG -orderE os0.
+ rewrite (Ohm1_cyclic_pgroup_prime _ p_s) ?cycle_cyclic ?leqnn ?cycle_eq1 //=.
+ rewrite (OhmE _ p_s) mem_gen ?groupX //= !inE mem_cycle //.
+ by rewrite -order_dvdn os0 ?dvdnn.
+ by apply/eqP=> s1; rewrite -os0 /s0 s1 expg1n order1 in p_gt1.
+case: (even_prime p_pr) => [p2 | oddp]; last first.
+ rewrite {+}/e0 oddp subn0 in s0 os0 ms0 os ms defS1 *.
+ have [f defF] := cyclicP cycF; have defP: P = <[s]>.
+ apply/eqP; rewrite eq_sym eqEcard -orderE oP os leqnn andbT.
+ by rewrite cycle_subG (mem_normal_Hall sylP) ?pcore_normal.
+ rewrite defP; split; last 1 [by exists s | by exists s0; rewrite ?groupX].
+ rewrite -defPF defP defF -cycleM ?cycle_cyclic // /order.
+ by red; rewrite (centsP cAA) // -cycle_subG -defF pcore_sub.
+ by rewrite -defF -defP (pnat_coprime (pcore_pgroup _ _) (pcore_pgroup _ _)).
+rewrite {+}/e0 p2 subn1 /= in s0 os0 ms0 os ms G4 defS1 lt_e0_n *.
+rewrite G4; exists s; split=> //; last first.
+ exists s0; split; rewrite ?groupX //; apply/eqP; rewrite mM ?groupX //.
+ rewrite ms0 mt eq_sym mulrN1 -subr_eq0 opprK -natrD -addSnnS.
+ by rewrite prednK ?expn_gt0 // addnn -mul2n -expnS -p2 -oG char_Zp.
+suffices TIst: <[s]> :&: <[t]> = 1.
+ rewrite dprodE //; last by rewrite (sub_abelian_cent2 cAA) ?cycle_subG.
+ apply/eqP; rewrite eqEcard mulG_subG !cycle_subG As At oA.
+ by rewrite TI_cardMg // -!orderE os ot p2 mul1n /= -expnSr prednK.
+rewrite setIC; apply: prime_TIg; first by rewrite -orderE ot.
+rewrite cycle_subG; apply/negP=> St.
+have: t \in <[s0]>.
+ by rewrite -defS1 (OhmE _ p_s) mem_gen // !inE St -order_dvdn ot p2.
+have ->: <[s0]> = [set 1; s0].
+ apply/eqP; rewrite eq_sym eqEcard subUset !sub1set group1 cycle_id /=.
+ by rewrite -orderE cards2 eq_sym -order_gt1 os0.
+rewrite !inE -order_eq1 ot /=; move/eqP; move/(congr1 m); move/eqP.
+rewrite mt ms0 eq_sym -subr_eq0 opprK -mulrSr.
+rewrite -val_eqE [val _]val_Zp_nat //= /q oG p2 modn_small //.
+by rewrite -addn3 expnS mul2n -addnn leq_add2l (ltn_exp2l 1).
+Qed.
+
+Definition extremal_generators gT (A : {set gT}) p n xy :=
+ let: (x, y) := xy in
+ [/\ #|A| = (p ^ n)%N, x \in A, #[x] = (p ^ n.-1)%N & y \in A :\: <[x]>].
+
+Lemma extremal_generators_facts gT (G : {group gT}) p n x y :
+ prime p -> extremal_generators G p n (x, y) ->
+ [/\ p.-group G, maximal <[x]> G, <[x]> <| G,
+ <[x]> * <[y]> = G & <[y]> \subset 'N(<[x]>)].
+Proof.
+move=> p_pr [oG Gx ox] /setDP[Gy notXy].
+have pG: p.-group G by rewrite /pgroup oG pnat_exp pnat_id.
+have maxX: maximal <[x]> G.
+ rewrite p_index_maximal -?divgS ?cycle_subG // -orderE oG ox.
+ case: (n) oG => [|n' _]; last by rewrite -expnB ?subSnn ?leqnSn ?prime_gt0.
+ move/eqP; rewrite -trivg_card1; case/trivgPn.
+ by exists y; rewrite // (group1_contra notXy).
+have nsXG := p_maximal_normal pG maxX; split=> //.
+ by apply: mulg_normal_maximal; rewrite ?cycle_subG.
+by rewrite cycle_subG (subsetP (normal_norm nsXG)).
+Qed.
+
+Section ModularGroup.
+
+Variables p n : nat.
+Let m := (p ^ n)%N.
+Let q := (p ^ n.-1)%N.
+Let r := (p ^ n.-2)%N.
+
+Hypotheses (p_pr : prime p) (n_gt2 : n > 2).
+Let p_gt1 := prime_gt1 p_pr.
+Let p_gt0 := ltnW p_gt1.
+Let def_n := esym (subnKC n_gt2).
+Let def_p : pdiv m = p. Proof. by rewrite /m def_n pdiv_pfactor. Qed.
+Let def_q : m %/ p = q. Proof. by rewrite /m /q def_n expnS mulKn. Qed.
+Let def_r : q %/ p = r. Proof. by rewrite /r /q def_n expnS mulKn. Qed.
+Let ltqm : q < m. Proof. by rewrite ltn_exp2l // def_n. Qed.
+Let ltrq : r < q. Proof. by rewrite ltn_exp2l // def_n. Qed.
+Let r_gt0 : 0 < r. Proof. by rewrite expn_gt0 ?p_gt0. Qed.
+Let q_gt1 : q > 1. Proof. exact: leq_ltn_trans r_gt0 ltrq. Qed.
+
+Lemma card_modular_group : #|'Mod_(p ^ n)| = (p ^ n)%N.
+Proof. by rewrite Extremal.card def_p ?def_q // -expnS def_n. Qed.
+
+Lemma Grp_modular_group :
+ 'Mod_(p ^ n) \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x ^+ r.+1)).
+Proof.
+rewrite /modular_gtype def_p def_q def_r; apply: Extremal.Grp => //.
+set B := <[_]>; have Bb: Zp1 \in B by exact: cycle_id.
+have oB: #|B| = q by rewrite -orderE order_Zp1 Zp_cast.
+have cycB: cyclic B by rewrite cycle_cyclic.
+have pB: p.-group B by rewrite /pgroup oB pnat_exp ?pnat_id.
+have ntB: B != 1 by rewrite -cardG_gt1 oB.
+have [] := cyclic_pgroup_Aut_structure pB cycB ntB.
+rewrite oB pfactorK //= -/B -(expg_znat r.+1 Bb) oB => mB [[def_mB _ _ _ _] _].
+rewrite {1}def_n /= => [[t [At ot mBt]]].
+have [p2 | ->] := even_prime p_pr; last first.
+ by case=> _ _ [s [As os mBs _]]; exists s; rewrite os -mBs def_mB.
+rewrite {1}p2 /= -2!eqSS -addn2 -2!{1}subn1 -subnDA subnK 1?ltnW //.
+case: eqP => [n3 _ | _ [_ [_ _ _ _ [s [As os mBs _ _]{t At ot mBt}]]]].
+ by exists t; rewrite At ot -def_mB // mBt /q /r p2 n3.
+by exists s; rewrite As os -def_mB // mBs /r p2.
+Qed.
+
+Definition modular_group_generators gT (xy : gT * gT) :=
+ let: (x, y) := xy in #[y] = p /\ x ^ y = x ^+ r.+1.
+
+Lemma generators_modular_group gT (G : {group gT}) :
+ G \isog 'Mod_m ->
+ exists2 xy, extremal_generators G p n xy & modular_group_generators xy.
+Proof.
+case/(isoGrpP _ Grp_modular_group); rewrite card_modular_group // -/m => oG.
+case/existsP=> -[x y] /= /eqP[defG xq yp xy].
+rewrite norm_joinEr ?norms_cycle ?xy ?mem_cycle // in defG.
+have [Gx Gy]: x \in G /\ y \in G.
+ by apply/andP; rewrite -!cycle_subG -mulG_subG defG.
+have notXy: y \notin <[x]>.
+ apply: contraL ltqm; rewrite -cycle_subG -oG -defG; move/mulGidPl->.
+ by rewrite -leqNgt dvdn_leq ?(ltnW q_gt1) // order_dvdn xq.
+have oy: #[y] = p by exact: nt_prime_order (group1_contra notXy).
+exists (x, y) => //=; split; rewrite ?inE ?notXy //.
+apply/eqP; rewrite -(eqn_pmul2r p_gt0) -expnSr -{1}oy (ltn_predK n_gt2) -/m.
+by rewrite -TI_cardMg ?defG ?oG // setIC prime_TIg ?cycle_subG // -orderE oy.
+Qed.
+
+(* This is an adaptation of Aschbacher, exercise 8.2: *)
+(* - We allow an alternative to the #[x] = p ^ n.-1 condition that meshes *)
+(* better with the modular_Grp lemma above. *)
+(* - We state explicitly some "obvious" properties of G, namely that G is *)
+(* the non-abelian semi-direct product <[x]> ><| <[y]> and that y ^+ j *)
+(* acts on <[x]> via z |-> z ^+ (j * p ^ n.-2).+1 *)
+(* - We also give the values of the 'Mho^k(G). *)
+(* - We corrected a pair of typos. *)
+Lemma modular_group_structure gT (G : {group gT}) x y :
+ extremal_generators G p n (x, y) ->
+ G \isog 'Mod_m -> modular_group_generators (x, y) ->
+ let X := <[x]> in
+ [/\ [/\ X ><| <[y]> = G, ~~ abelian G
+ & {in X, forall z j, z ^ (y ^+ j) = z ^+ (j * r).+1}],
+ [/\ 'Z(G) = <[x ^+ p]>, 'Phi(G) = 'Z(G) & #|'Z(G)| = r],
+ [/\ G^`(1) = <[x ^+ r]>, #|G^`(1)| = p & nil_class G = 2],
+ forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (p ^ k)]>
+ & if (p, n) == (2, 3) then 'Ohm_1(G) = G else
+ forall k, 0 < k < n.-1 ->
+ <[x ^+ (p ^ (n - k.+1))]> \x <[y]> = 'Ohm_k(G)
+ /\ #|'Ohm_k(G)| = (p ^ k.+1)%N].
+Proof.
+move=> genG isoG [oy xy] X.
+have [oG Gx ox /setDP[Gy notXy]] := genG; rewrite -/m -/q in ox oG.
+have [pG _ nsXG defXY nXY] := extremal_generators_facts p_pr genG.
+have [sXG nXG] := andP nsXG; have sYG: <[y]> \subset G by rewrite cycle_subG.
+have n1_gt1: n.-1 > 1 by [rewrite def_n]; have n1_gt0 := ltnW n1_gt1.
+have def_n1 := prednK n1_gt0.
+have def_m: (q * p)%N = m by rewrite -expnSr /m def_n.
+have notcxy: y \notin 'C[x].
+ apply: contraL (introT eqP xy); move/cent1P=> cxy.
+ rewrite /conjg -cxy // eq_mulVg1 expgS !mulKg -order_dvdn ox.
+ by rewrite pfactor_dvdn ?expn_gt0 ?p_gt0 // pfactorK // -ltnNge prednK.
+have tiXY: <[x]> :&: <[y]> = 1.
+ rewrite setIC prime_TIg -?orderE ?oy //; apply: contra notcxy.
+ by rewrite cycle_subG; apply: subsetP; rewrite cycle_subG cent1id.
+have notcGG: ~~ abelian G.
+ by rewrite -defXY abelianM !cycle_abelian cent_cycle cycle_subG.
+have cXpY: <[y]> \subset 'C(<[x ^+ p]>).
+ rewrite cent_cycle cycle_subG cent1C (sameP cent1P commgP) /commg conjXg xy.
+ by rewrite -expgM mulSn expgD mulKg -expnSr def_n1 -/q -ox expg_order.
+have oxp: #[x ^+ p] = r by rewrite orderXdiv ox ?dvdn_exp //.
+have [sZG nZG] := andP (center_normal G).
+have defZ: 'Z(G) = <[x ^+ p]>.
+ apply/eqP; rewrite eq_sym eqEcard subsetI -{2}defXY centM subsetI cent_cycle.
+ rewrite 2!cycle_subG !groupX ?cent1id //= centsC cXpY /= -orderE oxp leqNgt.
+ apply: contra notcGG => gtZr; apply: cyclic_center_factor_abelian.
+ rewrite (dvdn_prime_cyclic p_pr) // card_quotient //.
+ rewrite -(dvdn_pmul2l (cardG_gt0 'Z(G))) Lagrange // oG -def_m dvdn_pmul2r //.
+ case/p_natP: (pgroupS sZG pG) gtZr => k ->.
+ by rewrite ltn_exp2l // def_n1; exact: dvdn_exp2l.
+have Zxr: x ^+ r \in 'Z(G) by rewrite /r def_n expnS expgM defZ mem_cycle.
+have rxy: [~ x, y] = x ^+ r by rewrite /commg xy expgS mulKg.
+have defG': G^`(1) = <[x ^+ r]>.
+ case/setIP: Zxr => _; rewrite -rxy -defXY -(norm_joinEr nXY).
+ exact: der1_joing_cycles.
+have oG': #|G^`(1)| = p.
+ by rewrite defG' -orderE orderXdiv ox /q -def_n1 ?dvdn_exp2l // expnS mulnK.
+have sG'Z: G^`(1) \subset 'Z(G) by rewrite defG' cycle_subG.
+have nil2_G: nil_class G = 2.
+ by apply/eqP; rewrite eqn_leq andbC ltnNge nil_class1 notcGG nil_class2.
+have XYp: {in X & <[y]>, forall z t,
+ (z * t) ^+ p \in z ^+ p *: <[x ^+ r ^+ 'C(p, 2)]>}.
+- move=> z t Xz Yt; have Gz := subsetP sXG z Xz; have Gt := subsetP sYG t Yt.
+ have Rtz: [~ t, z] \in G^`(1) by exact: mem_commg.
+ have cGtz: [~ t, z] \in 'C(G) by case/setIP: (subsetP sG'Z _ Rtz).
+ rewrite expMg_Rmul /commute ?(centP cGtz) //.
+ have ->: t ^+ p = 1 by apply/eqP; rewrite -order_dvdn -oy order_dvdG.
+ rewrite defG' in Rtz; case/cycleP: Rtz => i ->.
+ by rewrite mem_lcoset mulg1 mulKg expgAC mem_cycle.
+have defMho: 'Mho^1(G) = <[x ^+ p]>.
+ apply/eqP; rewrite eqEsubset cycle_subG (Mho_p_elt 1) ?(mem_p_elt pG) //.
+ rewrite andbT (MhoE 1 pG) gen_subG -defXY; apply/subsetP=> ztp.
+ case/imsetP=> zt; case/imset2P=> z t Xz Yt -> -> {zt ztp}.
+ apply: subsetP (XYp z t Xz Yt); case/cycleP: Xz => i ->.
+ by rewrite expgAC mul_subG ?sub1set ?mem_cycle //= -defZ cycle_subG groupX.
+split=> //; try exact: extend_cyclic_Mho.
+- rewrite sdprodE //; split=> // z; case/cycleP=> i ->{z} j.
+ rewrite conjXg -expgM mulnC expgM actX; congr (_ ^+ i).
+ elim: j {i} => //= j ->; rewrite conjXg xy -!expgM mulnS mulSn addSn.
+ rewrite addnA -mulSn -addSn expgD mulnCA (mulnC j).
+ rewrite {3}/r def_n expnS mulnA -expnSr def_n1 -/q -ox -mulnA expgM.
+ by rewrite expg_order expg1n mulg1.
+- by rewrite (Phi_joing pG) defMho -defZ (joing_idPr _) ?defZ.
+have G1y: y \in 'Ohm_1(G).
+ by rewrite (OhmE _ pG) mem_gen // !inE Gy -order_dvdn oy /=.
+case: eqP => [[p2 n3] | notG8 k]; last case/andP=> k_gt0 lt_k_n1.
+ apply/eqP; rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG.
+ rewrite G1y -(groupMr _ G1y) /= (OhmE _ pG) mem_gen // !inE groupM //.
+ rewrite /q /r p2 n3 in oy ox xy *.
+ by rewrite expgS -mulgA -{1}(invg2id oy) -conjgE xy -expgS -order_dvdn ox.
+have le_k_n2: k <= n.-2 by rewrite -def_n1 in lt_k_n1.
+suffices{lt_k_n1} defGk: <[x ^+ (p ^ (n - k.+1))]> \x <[y]> = 'Ohm_k(G).
+ split=> //; case/dprodP: defGk => _ <- _ tiXkY; rewrite expnSr TI_cardMg //.
+ rewrite -!orderE oy (subnDA 1) subn1 orderXdiv ox ?dvdn_exp2l ?leq_subr //.
+ by rewrite /q -{1}(subnK (ltnW lt_k_n1)) expnD mulKn // expn_gt0 p_gt0.
+suffices{k k_gt0 le_k_n2} defGn2: <[x ^+ p]> \x <[y]> = 'Ohm_(n.-2)(G).
+ have:= Ohm_dprod k defGn2; have p_xp := mem_p_elt pG (groupX p Gx).
+ rewrite (Ohm_p_cycle _ p_xp) (Ohm_p_cycle _ (mem_p_elt pG Gy)) oxp oy.
+ rewrite pfactorK ?(pfactorK 1) // (eqnP k_gt0) expg1 -expgM -expnS.
+ rewrite -subSn // -subSS def_n1 def_n => -> /=; rewrite subnSK // subn2.
+ by apply/eqP; rewrite eqEsubset OhmS ?Ohm_sub //= -{1}Ohm_id OhmS ?Ohm_leq.
+rewrite dprodEY //=; last by apply/trivgP; rewrite -tiXY setSI ?cycleX.
+apply/eqP; rewrite eqEsubset join_subG !cycle_subG /= {-2}(OhmE _ pG) -/r.
+rewrite def_n (subsetP (Ohm_leq G (ltn0Sn _))) // mem_gen /=; last first.
+ by rewrite !inE -order_dvdn oxp groupX /=.
+rewrite gen_subG /= cent_joinEr // -defXY; apply/subsetP=> uv; case/setIP.
+case/imset2P=> u v Xu Yv ->{uv}; rewrite /r inE def_n expnS expgM.
+case/lcosetP: (XYp u v Xu Yv) => _ /cycleP[j ->] ->.
+case/cycleP: Xu => i ->{u}; rewrite -!(expgM, expgD) -order_dvdn ox.
+rewrite (mulnC r) /r {1}def_n expnSr mulnA -mulnDl -mulnA -expnS.
+rewrite subnSK // subn2 /q -def_n1 expnS dvdn_pmul2r // dvdn_addl.
+ by case/dvdnP=> k ->; rewrite mulnC expgM mem_mulg ?mem_cycle.
+case: (ltngtP n 3) => [|n_gt3|n3]; first by rewrite ltnNge n_gt2.
+ by rewrite -subnSK // expnSr mulnA dvdn_mull.
+case: (even_prime p_pr) notG8 => [-> | oddp _]; first by rewrite n3.
+by rewrite bin2odd // -!mulnA dvdn_mulr.
+Qed.
+
+End ModularGroup.
+
+(* Basic properties of dihedral groups; these will be refined for dihedral *)
+(* 2-groups in the section on extremal 2-groups. *)
+Section DihedralGroup.
+
+Variable q : nat.
+Hypothesis q_gt1 : q > 1.
+Let m := q.*2.
+
+Let def2 : pdiv m = 2.
+Proof.
+apply/eqP; rewrite /m -mul2n eqn_leq pdiv_min_dvd ?dvdn_mulr //.
+by rewrite prime_gt1 // pdiv_prime // (@leq_pmul2l 2 1) ltnW.
+Qed.
+
+Let def_q : m %/ pdiv m = q. Proof. by rewrite def2 divn2 half_double. Qed.
+
+Section Dihedral_extension.
+
+Variable p : nat.
+Hypotheses (p_gt1 : p > 1) (even_p : 2 %| p).
+Local Notation ED := [set: gsort (Extremal.gtype q p q.-1)].
+
+Lemma card_ext_dihedral : #|ED| = (p./2 * m)%N.
+Proof. by rewrite Extremal.card // /m -mul2n -divn2 mulnA divnK. Qed.
+
+Lemma Grp_ext_dihedral : ED \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x^-1)).
+Proof.
+suffices isoED: ED \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x ^+ q.-1)).
+ move=> gT G; rewrite isoED.
+ apply: eq_existsb => [[x y]] /=; rewrite !xpair_eqE.
+ congr (_ && _); apply: andb_id2l; move/eqP=> xq1; congr (_ && (_ == _)).
+ by apply/eqP; rewrite eq_sym eq_invg_mul -expgS (ltn_predK q_gt1) xq1.
+have unitrN1 : - 1 \in GRing.unit by move=> R; rewrite unitrN unitr1.
+pose uN1 := FinRing.unit ('Z_#[Zp1 : 'Z_q]) (unitrN1 _).
+apply: Extremal.Grp => //; exists (Zp_unitm uN1).
+rewrite Aut_aut order_injm ?injm_Zp_unitm ?in_setT //; split=> //.
+ by rewrite (dvdn_trans _ even_p) // order_dvdn -val_eqE /= mulrNN.
+apply/eqP; rewrite autE ?cycle_id // eq_expg_mod_order /=.
+by rewrite order_Zp1 !Zp_cast // !modn_mod (modn_small q_gt1) subn1.
+Qed.
+
+End Dihedral_extension.
+
+Lemma card_dihedral : #|'D_m| = m.
+Proof. by rewrite /('D_m)%type def_q card_ext_dihedral ?mul1n. Qed.
+
+Lemma Grp_dihedral : 'D_m \isog Grp (x : y : (x ^+ q, y ^+ 2, x ^ y = x^-1)).
+Proof. by rewrite /('D_m)%type def_q; exact: Grp_ext_dihedral. Qed.
+
+Lemma Grp'_dihedral : 'D_m \isog Grp (x : y : (x ^+ 2, y ^+ 2, (x * y) ^+ q)).
+Proof.
+move=> gT G; rewrite Grp_dihedral; apply/existsP/existsP=> [] [[x y]] /=.
+ case/eqP=> <- xq1 y2 xy; exists (x * y, y); rewrite !xpair_eqE /= eqEsubset.
+ rewrite !join_subG !joing_subr !cycle_subG -{3}(mulgK y x) /=.
+ rewrite 2?groupM ?groupV ?mem_gen ?inE ?cycle_id ?orbT //= -mulgA expgS.
+ by rewrite {1}(conjgC x) xy -mulgA mulKg -(expgS y 1) y2 mulg1 xq1 !eqxx.
+case/eqP=> <- x2 y2 xyq; exists (x * y, y); rewrite !xpair_eqE /= eqEsubset.
+rewrite !join_subG !joing_subr !cycle_subG -{3}(mulgK y x) /=.
+rewrite 2?groupM ?groupV ?mem_gen ?inE ?cycle_id ?orbT //= xyq y2 !eqxx /=.
+by rewrite eq_sym eq_invg_mul !mulgA mulgK -mulgA -!(expgS _ 1) x2 y2 mulg1.
+Qed.
+
+End DihedralGroup.
+
+Lemma involutions_gen_dihedral gT (x y : gT) :
+ let G := <<[set x; y]>> in
+ #[x] = 2 -> #[y] = 2 -> x != y -> G \isog 'D_#|G|.
+Proof.
+move=> G ox oy ne_x_y; pose q := #[x * y].
+have q_gt1: q > 1 by rewrite order_gt1 -eq_invg_mul invg_expg ox.
+have homG: G \homg 'D_q.*2.
+ rewrite Grp'_dihedral //; apply/existsP; exists (x, y); rewrite /= !xpair_eqE.
+ by rewrite joing_idl joing_idr -{1}ox -oy !expg_order !eqxx.
+suff oG: #|G| = q.*2 by rewrite oG isogEcard oG card_dihedral ?leqnn ?andbT.
+have: #|G| %| q.*2 by rewrite -card_dihedral ?card_homg.
+have Gxy: <[x * y]> \subset G.
+ by rewrite cycle_subG groupM ?mem_gen ?set21 ?set22.
+have[k oG]: exists k, #|G| = (k * q)%N by apply/dvdnP; rewrite cardSg.
+rewrite oG -mul2n dvdn_pmul2r ?order_gt0 ?dvdn_divisors // !inE /=.
+case/pred2P=> [k1 | -> //]; case/negP: ne_x_y.
+have cycG: cyclic G.
+ apply/cyclicP; exists (x * y); apply/eqP.
+ by rewrite eq_sym eqEcard Gxy oG k1 mul1n leqnn.
+have: <[x]> == <[y]>.
+ by rewrite (eq_subG_cyclic cycG) ?genS ?subsetUl ?subsetUr -?orderE ?ox ?oy.
+by rewrite eqEcard cycle_subG /= cycle2g // !inE -order_eq1 ox; case/andP.
+Qed.
+
+Lemma Grp_2dihedral n : n > 1 ->
+ 'D_(2 ^ n) \isog Grp (x : y : (x ^+ (2 ^ n.-1), y ^+ 2, x ^ y = x^-1)).
+Proof.
+move=> n_gt1; rewrite -(ltn_predK n_gt1) expnS mul2n /=.
+by apply: Grp_dihedral; rewrite (ltn_exp2l 0) // -(subnKC n_gt1).
+Qed.
+
+Lemma card_2dihedral n : n > 1 -> #|'D_(2 ^ n)| = (2 ^ n)%N.
+Proof.
+move=> n_gt1; rewrite -(ltn_predK n_gt1) expnS mul2n /= card_dihedral //.
+by rewrite (ltn_exp2l 0) // -(subnKC n_gt1).
+Qed.
+
+Lemma card_semidihedral n : n > 3 -> #|'SD_(2 ^ n)| = (2 ^ n)%N.
+Proof.
+move=> n_gt3.
+rewrite /('SD__)%type -(subnKC (ltnW (ltnW n_gt3))) pdiv_pfactor //.
+by rewrite // !expnS !mulKn -?expnS ?Extremal.card //= (ltn_exp2l 0).
+Qed.
+
+Lemma Grp_semidihedral n : n > 3 ->
+ 'SD_(2 ^ n) \isog
+ Grp (x : y : (x ^+ (2 ^ n.-1), y ^+ 2, x ^ y = x ^+ (2 ^ n.-2).-1)).
+Proof.
+move=> n_gt3.
+rewrite /('SD__)%type -(subnKC (ltnW (ltnW n_gt3))) pdiv_pfactor //.
+rewrite !expnS !mulKn // -!expnS /=; set q := (2 ^ _)%N.
+have q_gt1: q > 1 by rewrite (ltn_exp2l 0).
+apply: Extremal.Grp => //; set B := <[_]>.
+have oB: #|B| = q by rewrite -orderE order_Zp1 Zp_cast.
+have pB: 2.-group B by rewrite /pgroup oB pnat_exp.
+have ntB: B != 1 by rewrite -cardG_gt1 oB.
+have [] := cyclic_pgroup_Aut_structure pB (cycle_cyclic _) ntB.
+rewrite oB /= pfactorK //= -/B => m [[def_m _ _ _ _] _].
+rewrite -{1 2}(subnKC n_gt3) => [[t [At ot _ [s [_ _ _ defA]]]]].
+case/dprodP: defA => _ defA cst _.
+have{cst defA} cAt: t \in 'C(Aut B).
+ rewrite -defA centM inE -sub_cent1 -cent_cycle centsC cst /=.
+ by rewrite cent_cycle cent1id.
+case=> s0 [As0 os0 _ def_s0t _]; exists (s0 * t).
+rewrite -def_m ?groupM ?cycle_id // def_s0t !Zp_expg !mul1n valZpK Zp_nat.
+rewrite order_dvdn expgMn /commute 1?(centP cAt) // -{1}os0 -{1}ot.
+by rewrite !expg_order mul1g.
+Qed.
+
+Section Quaternion.
+
+Variable n : nat.
+Hypothesis n_gt2 : n > 2.
+Let m := (2 ^ n)%N.
+Let q := (2 ^ n.-1)%N.
+Let r := (2 ^ n.-2)%N.
+Let GrpQ := 'Q_m \isog Grp (x : y : (x ^+ q, y ^+ 2 = x ^+ r, x ^ y = x^-1)).
+Let defQ : #|'Q_m| = m /\ GrpQ.
+Proof.
+have q_gt1 : q > 1 by rewrite (ltn_exp2l 0) // -(subnKC n_gt2).
+have def_m : (2 * q)%N = m by rewrite -expnS (ltn_predK n_gt2).
+have def_q : m %/ pdiv m = q
+ by rewrite /m -(ltn_predK n_gt2) pdiv_pfactor // expnS mulKn.
+have r_gt1 : r > 1 by rewrite (ltn_exp2l 0) // -(subnKC n_gt2).
+have def2r : (2 * r)%N = q by rewrite -expnS /q -(subnKC n_gt2).
+rewrite /GrpQ [@quaternion_gtype _]unlock /quaternion_kernel {}def_q.
+set B := [set: _]; have: B \homg Grp (u : v : (u ^+ q, v ^+ 4, u ^ v = u^-1)).
+ by rewrite -Grp_ext_dihedral ?homg_refl.
+have: #|B| = (q * 4)%N by rewrite card_ext_dihedral // mulnC -muln2 -mulnA.
+rewrite {}/B; move: (Extremal.gtype q 4 _) => gT.
+set B := [set: gT] => oB; set K := _ :\: _.
+case/existsP=> -[u v] /= /eqP[defB uq v4 uv].
+have nUV: <[v]> \subset 'N(<[u]>) by rewrite norms_cycle uv groupV cycle_id.
+rewrite norm_joinEr // in defB.
+have le_ou: #[u] <= q by rewrite dvdn_leq ?expn_gt0 // order_dvdn uq.
+have le_ov: #[v] <= 4 by rewrite dvdn_leq // order_dvdn v4.
+have tiUV: <[u]> :&: <[v]> = 1 by rewrite cardMg_TI // defB oB leq_mul.
+have{le_ou le_ov} [ou ov]: #[u] = q /\ #[v] = 4.
+ have:= esym (leqif_mul (leqif_eq le_ou) (leqif_eq le_ov)).2.
+ by rewrite -TI_cardMg // defB -oB eqxx eqn0Ngt cardG_gt0; do 2!case: eqP=> //.
+have sdB: <[u]> ><| <[v]> = B by rewrite sdprodE.
+have uvj j: u ^ (v ^+ j) = (if odd j then u^-1 else u).
+ elim: j => [|j IHj]; first by rewrite conjg1.
+ by rewrite expgS conjgM uv conjVg IHj (fun_if invg) invgK if_neg.
+have sqrB i j: (u ^+ i * v ^+ j) ^+ 2 = (if odd j then v ^+ 2 else u ^+ i.*2).
+ rewrite expgS; case: ifP => odd_j.
+ rewrite {1}(conjgC (u ^+ i)) conjXg uvj odd_j expgVn -mulgA mulKg.
+ rewrite -expgD addnn -(odd_double_half j) odd_j doubleD addnC /=.
+ by rewrite -(expg_mod _ v4) -!muln2 -mulnA modnMDl.
+ rewrite {2}(conjgC (u ^+ i)) conjXg uvj odd_j mulgA -(mulgA (u ^+ i)).
+ rewrite -expgD addnn -(odd_double_half j) odd_j -2!mul2n mulnA.
+ by rewrite expgM v4 expg1n mulg1 -expgD addnn.
+pose w := u ^+ r * v ^+ 2.
+have Kw: w \in K.
+ rewrite !inE sqrB /= -mul2n def2r uq eqxx andbT -defB.
+ apply/imsetP=> [[_]] /imset2P[_ _ /cycleP[i ->] /cycleP[j ->] ->].
+ apply/eqP; rewrite sqrB; case: ifP => _.
+ rewrite eq_mulgV1 mulgK -order_dvdn ou pfactor_dvdn ?expn_gt0 ?pfactorK //.
+ by rewrite -ltnNge -(subnKC n_gt2).
+ rewrite (canF_eq (mulKg _)); apply/eqP=> def_v2.
+ suffices: v ^+ 2 \in <[u]> :&: <[v]> by rewrite tiUV inE -order_dvdn ov.
+ by rewrite inE {1}def_v2 groupM ?groupV !mem_cycle.
+have ow: #[w] = 2.
+ case/setDP: Kw; rewrite inE -order_dvdn dvdn_divisors // !inE /= order_eq1.
+ by case/orP=> /eqP-> // /imsetP[]; exists 1; rewrite ?inE ?expg1n.
+have defK: K = [set w].
+ apply/eqP; rewrite eqEsubset sub1set Kw andbT subDset setUC.
+ apply/subsetP=> uivj; have: uivj \in B by rewrite inE.
+ rewrite -{1}defB => /imset2P[_ _ /cycleP[i ->] /cycleP[j ->] ->] {uivj}.
+ rewrite !inE sqrB -{-1}[j]odd_double_half.
+ case: (odd j); rewrite -order_dvdn ?ov // ou -def2r -mul2n dvdn_pmul2l //.
+ case/dvdnP=> k ->{i}; apply/orP.
+ rewrite add0n -[j./2]odd_double_half addnC doubleD -!muln2 -mulnA.
+ rewrite -(expg_mod_order v) ov modnMDl; case: (odd _); last first.
+ right; rewrite mulg1 /r -(subnKC n_gt2) expnSr mulnA expgM.
+ by apply: mem_imset; rewrite inE.
+ rewrite (inj_eq (mulIg _)) -expg_mod_order ou -[k]odd_double_half.
+ rewrite addnC -muln2 mulnDl -mulnA def2r modnMDl -ou expg_mod_order.
+ case: (odd k); [left | right]; rewrite ?mul1n ?mul1g //.
+ by apply/imsetP; exists v; rewrite ?inE.
+have nKB: 'N(<<K>>) = B.
+ apply/setP=> b; rewrite !inE -genJ genS // {1}defK conjg_set1 sub1set.
+ have:= Kw; rewrite !inE -!order_dvdn orderJ ow !andbT; apply: contra.
+ case/imsetP=> z _ def_wb; apply/imsetP; exists (z ^ b^-1); rewrite ?inE //.
+ by rewrite -conjXg -def_wb conjgK.
+rewrite -im_quotient card_quotient // nKB -divgS ?subsetT //.
+split; first by rewrite oB defK -orderE ow (mulnA q 2 2) mulnK // mulnC.
+apply: intro_isoGrp => [|rT H].
+ apply/existsP; exists (coset _ u, coset _ v); rewrite /= !xpair_eqE.
+ rewrite -!morphX -?morphJ -?morphV /= ?nKB ?in_setT // uq uv morph1 !eqxx.
+ rewrite -/B -defB -norm_joinEr // quotientY ?nKB ?subsetT //= andbT.
+ rewrite !quotient_cycle /= ?nKB ?in_setT ?eqxx //=.
+ by rewrite -(coset_kerl _ (mem_gen Kw)) -mulgA -expgD v4 mulg1.
+case/existsP=> -[x y] /= /eqP[defH xq y2 xy].
+have ox: #[x] %| #[u] by rewrite ou order_dvdn xq.
+have oy: #[y] %| #[v].
+ by rewrite ov order_dvdn (expgM y 2 2) y2 -expgM mulnC def2r xq.
+have actB: {in <[u]> & <[v]>, morph_act 'J 'J (eltm ox) (eltm oy)}.
+ move=> _ _ /cycleP[i ->] /cycleP[j ->] /=.
+ rewrite conjXg uvj fun_if if_arg fun_if expgVn morphV ?mem_cycle //= !eltmE.
+ rewrite -expgVn -if_arg -fun_if conjXg; congr (_ ^+ i).
+ rewrite -{2}[j]odd_double_half addnC expgD -mul2n expgM y2.
+ rewrite -expgM conjgM (conjgE x) commuteX // mulKg.
+ by case: (odd j); rewrite ?conjg1.
+pose f := sdprodm sdB actB.
+have Kf: 'ker (coset <<K>>) \subset 'ker f.
+ rewrite ker_coset defK cycle_subG /= ker_sdprodm.
+ apply/imset2P; exists (u ^+ r) (v ^+ 2); first exact: mem_cycle.
+ by rewrite inE mem_cycle /= !eltmE y2.
+ by apply: canRL (mulgK _) _; rewrite -mulgA -expgD v4 mulg1.
+have Df: 'dom f \subset 'dom (coset <<K>>) by rewrite /dom nKB subsetT.
+apply/homgP; exists (factm_morphism Kf Df); rewrite morphim_factm /= -/B.
+rewrite -{2}defB morphim_sdprodm // !morphim_cycle ?cycle_id //= !eltm_id.
+by rewrite -norm_joinEr // norms_cycle xy groupV cycle_id.
+Qed.
+
+Lemma card_quaternion : #|'Q_m| = m. Proof. by case defQ. Qed.
+Lemma Grp_quaternion : GrpQ. Proof. by case defQ. Qed.
+
+End Quaternion.
+
+Lemma eq_Mod8_D8 : 'Mod_8 = 'D_8. Proof. by []. Qed.
+
+Section ExtremalStructure.
+
+Variables (gT : finGroupType) (G : {group gT}) (n : nat).
+Implicit Type H : {group gT}.
+
+Let m := (2 ^ n)%N.
+Let q := (2 ^ n.-1)%N.
+Let q_gt0: q > 0. Proof. by rewrite expn_gt0. Qed.
+Let r := (2 ^ n.-2)%N.
+Let r_gt0: r > 0. Proof. by rewrite expn_gt0. Qed.
+
+Let def2qr : n > 1 -> [/\ 2 * q = m, 2 * r = q, q < m & r < q]%N.
+Proof. by rewrite /q /m /r; move/subnKC=> <-; rewrite !ltn_exp2l ?expnS. Qed.
+
+Lemma generators_2dihedral :
+ n > 1 -> G \isog 'D_m ->
+ exists2 xy, extremal_generators G 2 n xy
+ & let: (x, y) := xy in #[y] = 2 /\ x ^ y = x^-1.
+Proof.
+move=> n_gt1; have [def2q _ ltqm _] := def2qr n_gt1.
+case/(isoGrpP _ (Grp_2dihedral n_gt1)); rewrite card_2dihedral // -/ m => oG.
+case/existsP=> -[x y] /=; rewrite -/q => /eqP[defG xq y2 xy].
+have{defG} defG: <[x]> * <[y]> = G.
+ by rewrite -norm_joinEr // norms_cycle xy groupV cycle_id.
+have notXy: y \notin <[x]>.
+ apply: contraL ltqm => Xy; rewrite -leqNgt -oG -defG mulGSid ?cycle_subG //.
+ by rewrite dvdn_leq // order_dvdn xq.
+have oy: #[y] = 2 by exact: nt_prime_order (group1_contra notXy).
+have ox: #[x] = q.
+ apply: double_inj; rewrite -muln2 -oy -mul2n def2q -oG -defG TI_cardMg //.
+ by rewrite setIC prime_TIg ?cycle_subG // -orderE oy.
+exists (x, y) => //=.
+by rewrite oG ox !inE notXy -!cycle_subG /= -defG mulG_subl mulG_subr.
+Qed.
+
+Lemma generators_semidihedral :
+ n > 3 -> G \isog 'SD_m ->
+ exists2 xy, extremal_generators G 2 n xy
+ & let: (x, y) := xy in #[y] = 2 /\ x ^ y = x ^+ r.-1.
+Proof.
+move=> n_gt3; have [def2q _ ltqm _] := def2qr (ltnW (ltnW n_gt3)).
+case/(isoGrpP _ (Grp_semidihedral n_gt3)).
+rewrite card_semidihedral // -/m => oG.
+case/existsP=> -[x y] /=; rewrite -/q -/r => /eqP[defG xq y2 xy].
+have{defG} defG: <[x]> * <[y]> = G.
+ by rewrite -norm_joinEr // norms_cycle xy mem_cycle.
+have notXy: y \notin <[x]>.
+ apply: contraL ltqm => Xy; rewrite -leqNgt -oG -defG mulGSid ?cycle_subG //.
+ by rewrite dvdn_leq // order_dvdn xq.
+have oy: #[y] = 2 by exact: nt_prime_order (group1_contra notXy).
+have ox: #[x] = q.
+ apply: double_inj; rewrite -muln2 -oy -mul2n def2q -oG -defG TI_cardMg //.
+ by rewrite setIC prime_TIg ?cycle_subG // -orderE oy.
+exists (x, y) => //=.
+by rewrite oG ox !inE notXy -!cycle_subG /= -defG mulG_subl mulG_subr.
+Qed.
+
+Lemma generators_quaternion :
+ n > 2 -> G \isog 'Q_m ->
+ exists2 xy, extremal_generators G 2 n xy
+ & let: (x, y) := xy in [/\ #[y] = 4, y ^+ 2 = x ^+ r & x ^ y = x^-1].
+Proof.
+move=> n_gt2; have [def2q def2r ltqm _] := def2qr (ltnW n_gt2).
+case/(isoGrpP _ (Grp_quaternion n_gt2)); rewrite card_quaternion // -/m => oG.
+case/existsP=> -[x y] /=; rewrite -/q -/r => /eqP[defG xq y2 xy].
+have{defG} defG: <[x]> * <[y]> = G.
+ by rewrite -norm_joinEr // norms_cycle xy groupV cycle_id.
+have notXy: y \notin <[x]>.
+ apply: contraL ltqm => Xy; rewrite -leqNgt -oG -defG mulGSid ?cycle_subG //.
+ by rewrite dvdn_leq // order_dvdn xq.
+have ox: #[x] = q.
+ apply/eqP; rewrite eqn_leq dvdn_leq ?order_dvdn ?xq //=.
+ rewrite -(leq_pmul2r (order_gt0 y)) mul_cardG defG oG -def2q mulnAC mulnC.
+ rewrite leq_pmul2r // dvdn_leq ?muln_gt0 ?cardG_gt0 // order_dvdn expgM.
+ by rewrite -order_dvdn order_dvdG //= inE {1}y2 !mem_cycle.
+have oy2: #[y ^+ 2] = 2 by rewrite y2 orderXdiv ox -def2r ?dvdn_mull ?mulnK.
+exists (x, y) => /=; last by rewrite (orderXprime oy2).
+by rewrite oG !inE notXy -!cycle_subG /= -defG mulG_subl mulG_subr.
+Qed.
+
+Variables x y : gT.
+Implicit Type M : {group gT}.
+
+Let X := <[x]>.
+Let Y := <[y]>.
+Let yG := y ^: G.
+Let xyG := (x * y) ^: G.
+Let My := <<yG>>.
+Let Mxy := <<xyG>>.
+
+
+Theorem dihedral2_structure :
+ n > 1 -> extremal_generators G 2 n (x, y) -> G \isog 'D_m ->
+ [/\ [/\ X ><| Y = G, {in G :\: X, forall t, #[t] = 2}
+ & {in X & G :\: X, forall z t, z ^ t = z^-1}],
+ [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r
+ & nil_class G = n.-1],
+ 'Ohm_1(G) = G /\ (forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>),
+ [/\ yG :|: xyG = G :\: X, [disjoint yG & xyG]
+ & forall M, maximal M G = pred3 X My Mxy M]
+ & if n == 2 then (2.-abelem G : Prop) else
+ [/\ 'Z(G) = <[x ^+ r]>, #|'Z(G)| = 2,
+ My \isog 'D_q, Mxy \isog 'D_q
+ & forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X]].
+Proof.
+move=> n_gt1 genG isoG; have [def2q def2r ltqm ltrq] := def2qr n_gt1.
+have [oG Gx ox X'y] := genG; rewrite -/m -/q -/X in oG ox X'y.
+case/extremal_generators_facts: genG; rewrite -/X // => pG maxX nsXG defXY nXY.
+have [sXG nXG]:= andP nsXG; have [Gy notXy]:= setDP X'y.
+have ox2: #[x ^+ 2] = r by rewrite orderXdiv ox -def2r ?dvdn_mulr ?mulKn.
+have oxr: #[x ^+ r] = 2 by rewrite orderXdiv ox -def2r ?dvdn_mull ?mulnK.
+have [[u v] [_ Gu ou U'v] [ov uv]] := generators_2dihedral n_gt1 isoG.
+have defUv: <[u]> :* v = G :\: <[u]>.
+ apply: rcoset_index2; rewrite -?divgS ?cycle_subG //.
+ by rewrite oG -orderE ou -def2q mulnK.
+have invUV: {in <[u]> & <[u]> :* v, forall z t, z ^ t = z^-1}.
+ move=> z t; case/cycleP=> i ->; case/rcosetP=> z'; case/cycleP=> j -> ->{z t}.
+ by rewrite conjgM {2}/conjg commuteX2 // mulKg conjXg uv expgVn.
+have oU': {in <[u]> :* v, forall t, #[t] = 2}.
+ move=> t Uvt; apply: nt_prime_order => //; last first.
+ by case: eqP Uvt => // ->; rewrite defUv !inE group1.
+ case/rcosetP: Uvt => z Uz ->{t}; rewrite expgS {1}(conjgC z) -mulgA.
+ by rewrite invUV ?rcoset_refl // mulKg -(expgS v 1) -ov expg_order.
+have defU: n > 2 -> {in G, forall z, #[z] = q -> <[z]> = <[u]>}.
+ move=> n_gt2 z Gz oz; apply/eqP; rewrite eqEcard -!orderE oz cycle_subG.
+ apply: contraLR n_gt2; rewrite ou leqnn andbT -(ltn_predK n_gt1) => notUz.
+ by rewrite ltnS -(@ltn_exp2l 2) // -/q -oz oU' // defUv inE notUz.
+have n2_abelG: (n > 2) || 2.-abelem G.
+ rewrite ltn_neqAle eq_sym n_gt1; case: eqP => //= n2.
+ apply/abelemP=> //; split=> [|z Gz].
+ by apply: (p2group_abelian pG); rewrite oG pfactorK ?n2.
+ case Uz: (z \in <[u]>); last by rewrite -expg_mod_order oU' // defUv inE Uz.
+ apply/eqP; rewrite -order_dvdn (dvdn_trans (order_dvdG Uz)) // -orderE.
+ by rewrite ou /q n2.
+have{oU'} oX': {in G :\: X, forall t, #[t] = 2}.
+ have [n_gt2 | abelG] := orP n2_abelG; first by rewrite [X]defU // -defUv.
+ move=> t /setDP[Gt notXt]; apply: nt_prime_order (group1_contra notXt) => //.
+ by case/abelemP: abelG => // _ ->.
+have{invUV} invXX': {in X & G :\: X, forall z t, z ^ t = z^-1}.
+ have [n_gt2 | abelG] := orP n2_abelG; first by rewrite [X]defU // -defUv.
+ have [//|cGG oG2] := abelemP _ abelG.
+ move=> t z Xt /setDP[Gz _]; apply/eqP; rewrite eq_sym eq_invg_mul.
+ by rewrite /conjg -(centsP cGG z) // ?mulKg ?[t * t]oG2 ?(subsetP sXG).
+have nXiG k: G \subset 'N(<[x ^+ k]>).
+ apply: char_norm_trans nXG.
+ by rewrite cycle_subgroup_char // cycle_subG mem_cycle.
+have memL i: x ^+ (2 ^ i) \in 'L_i.+1(G).
+ elim: i => // i IHi; rewrite -groupV expnSr expgM invMg.
+ by rewrite -{2}(invXX' _ y) ?mem_cycle ?cycle_id ?mem_commg.
+have defG': G^`(1) = <[x ^+ 2]>.
+ apply/eqP; rewrite eqEsubset cycle_subG (memL 1%N) ?der1_min //=.
+ rewrite (p2group_abelian (quotient_pgroup _ pG)) ?card_quotient //=.
+ rewrite -divgS ?cycle_subG ?groupX // oG -orderE ox2.
+ by rewrite -def2q -def2r mulnA mulnK.
+have defG1: 'Mho^1(G) = <[x ^+ 2]>.
+ apply/eqP; rewrite (MhoE _ pG) eqEsubset !gen_subG sub1set andbC.
+ rewrite mem_gen; last exact: mem_imset.
+ apply/subsetP=> z2; case/imsetP=> z Gz ->{z2}.
+ case Xz: (z \in X); last by rewrite -{1}(oX' z) ?expg_order ?group1 // inE Xz.
+ by case/cycleP: Xz => i ->; rewrite expgAC mem_cycle.
+have defPhi: 'Phi(G) = <[x ^+ 2]>.
+ by rewrite (Phi_joing pG) defG' defG1 (joing_idPl _).
+have def_tG: {in G :\: X, forall t, t ^: G = <[x ^+ 2]> :* t}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ have defJt: {in X, forall z, t ^ z = z ^- 2 * t}.
+ move=> z Xz; rewrite /= invMg -mulgA (conjgC _ t).
+ by rewrite (invXX' _ t) ?groupV ?invgK.
+ have defGt: X * <[t]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG.
+ apply/setP=> tz; apply/imsetP/rcosetP=> [[t'z] | [z]].
+ rewrite -defGt -normC ?cycle_subG ?(subsetP nXG) //.
+ case/imset2P=> _ z /cycleP[j ->] Xz -> -> {tz t'z}.
+ exists (z ^- 2); last by rewrite conjgM {2}/conjg commuteX // mulKg defJt.
+ case/cycleP: Xz => i ->{z}.
+ by rewrite groupV -expgM mulnC expgM mem_cycle.
+ case/cycleP=> i -> -> {z tz}; exists (x ^- i); first by rewrite groupV groupX.
+ by rewrite defJt ?groupV ?mem_cycle // expgVn invgK expgAC.
+have defMt: {in G :\: X, forall t, <[x ^+ 2]> ><| <[t]> = <<t ^: G>>}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ rewrite sdprodEY ?cycle_subG ?(subsetP (nXiG 2)) //; first 1 last.
+ rewrite setIC prime_TIg -?orderE ?oX' // cycle_subG.
+ by apply: contra notXt; apply: subsetP; rewrite cycleX.
+ apply/eqP; have: t \in <<t ^: G>> by rewrite mem_gen ?class_refl.
+ rewrite def_tG // eqEsubset join_subG !cycle_subG !gen_subG => tGt.
+ rewrite tGt -(groupMr _ tGt) mem_gen ?mem_mulg ?cycle_id ?set11 //=.
+ by rewrite mul_subG ?joing_subl // -gen_subG joing_subr.
+have oMt: {in G :\: X, forall t, #|<<t ^: G>>| = q}.
+ move=> t X't /=; rewrite -(sdprod_card (defMt t X't)) -!orderE ox2 oX' //.
+ by rewrite mulnC.
+have sMtG: {in G :\: X, forall t, <<t ^: G>> \subset G}.
+ by move=> t; case/setDP=> Gt _; rewrite gen_subG class_subG.
+have maxMt: {in G :\: X, forall t, maximal <<t ^: G>> G}.
+ move=> t X't /=; rewrite p_index_maximal -?divgS ?sMtG ?oMt //.
+ by rewrite oG -def2q mulnK.
+have X'xy: x * y \in G :\: X by rewrite !inE !groupMl ?cycle_id ?notXy.
+have ti_yG_xyG: [disjoint yG & xyG].
+ apply/pred0P=> t; rewrite /= /yG /xyG !def_tG //; apply/andP=> [[yGt]].
+ rewrite rcoset_sym (rcoset_transl yGt) mem_rcoset mulgK; move/order_dvdG.
+ by rewrite -orderE ox2 ox gtnNdvd.
+have s_tG_X': {in G :\: X, forall t, t ^: G \subset G :\: X}.
+ by move=> t X't /=; rewrite class_sub_norm // normsD ?normG.
+have defX': yG :|: xyG = G :\: X.
+ apply/eqP; rewrite eqEcard subUset !s_tG_X' //= -(leq_add2l q) -{1}ox orderE.
+ rewrite -/X -{1}(setIidPr sXG) cardsID oG -def2q mul2n -addnn leq_add2l.
+ rewrite -(leq_add2r #|yG :&: xyG|) cardsUI disjoint_setI0 // cards0 addn0.
+ by rewrite /yG /xyG !def_tG // !card_rcoset addnn -mul2n -orderE ox2 def2r.
+split.
+- by rewrite ?sdprodE // setIC // prime_TIg ?cycle_subG // -orderE ?oX'.
+- rewrite defG'; split=> //.
+ apply/eqP; rewrite eqn_leq (leq_trans (nil_class_pgroup pG)); last first.
+ by rewrite oG pfactorK // geq_max leqnn -(subnKC n_gt1).
+ rewrite -(subnKC n_gt1) subn2 ltnNge.
+ rewrite (sameP (lcn_nil_classP _ (pgroup_nil pG)) eqP).
+ by apply/trivgPn; exists (x ^+ r); rewrite ?memL // -order_gt1 oxr.
+- split; last exact: extend_cyclic_Mho.
+ have sX'G1: {subset G :\: X <= 'Ohm_1(G)}.
+ move=> t X't; have [Gt _] := setDP X't.
+ by rewrite (OhmE 1 pG) mem_gen // !inE Gt -(oX' t) //= expg_order.
+ apply/eqP; rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG.
+ by rewrite -(groupMr _ (sX'G1 y X'y)) !sX'G1.
+- split=> //= H; apply/idP/idP=> [maxH |]; last first.
+ by case/or3P; move/eqP->; rewrite ?maxMt.
+ have [sHG nHG]:= andP (p_maximal_normal pG maxH).
+ have oH: #|H| = q.
+ apply: double_inj; rewrite -muln2 -(p_maximal_index pG maxH) Lagrange //.
+ by rewrite oG -mul2n.
+ rewrite !(eq_sym (gval H)) -eq_sym !eqEcard oH -orderE ox !oMt // !leqnn.
+ case sHX: (H \subset X) => //=; case/subsetPn: sHX => t Ht notXt.
+ have: t \in yG :|: xyG by rewrite defX' inE notXt (subsetP sHG).
+ rewrite !andbT !gen_subG /yG /xyG.
+ by case/setUP; move/class_transr <-; rewrite !class_sub_norm ?Ht ?orbT.
+rewrite eqn_leq n_gt1; case: leqP n2_abelG => //= n_gt2 _.
+have ->: 'Z(G) = <[x ^+ r]>.
+ apply/eqP; rewrite eqEcard andbC -orderE oxr -{1}(setIidPr (center_sub G)).
+ rewrite cardG_gt1 /= meet_center_nil ?(pgroup_nil pG) //; last first.
+ by rewrite -cardG_gt1 oG (leq_trans _ ltqm).
+ apply/subsetP=> t; case/setIP=> Gt cGt.
+ case X't: (t \in G :\: X).
+ move/eqP: (invXX' _ _ (cycle_id x) X't).
+ rewrite /conjg -(centP cGt) // mulKg eq_sym eq_invg_mul -order_eq1 ox2.
+ by rewrite (eqn_exp2l _ 0) // -(subnKC n_gt2).
+ move/idPn: X't; rewrite inE Gt andbT negbK => Xt.
+ have:= Ohm_p_cycle 1 (mem_p_elt pG Gx); rewrite ox pfactorK // subn1 => <-.
+ rewrite (OhmE _ (pgroupS sXG pG)) mem_gen // !inE Xt /=.
+ by rewrite -eq_invg_mul -(invXX' _ y) // /conjg (centP cGt) // mulKg.
+have isoMt: {in G :\: X, forall t, <<t ^: G>> \isog 'D_q}.
+ have n1_gt1: n.-1 > 1 by rewrite -(subnKC n_gt2).
+ move=> t X't /=; rewrite isogEcard card_2dihedral ?oMt // leqnn andbT.
+ rewrite Grp_2dihedral //; apply/existsP; exists (x ^+ 2, t) => /=.
+ have [_ <- nX2T _] := sdprodP (defMt t X't); rewrite norm_joinEr //.
+ rewrite -/q -/r !xpair_eqE eqxx -expgM def2r -ox -{1}(oX' t X't).
+ by rewrite !expg_order !eqxx /= invXX' ?mem_cycle.
+rewrite !isoMt //; split=> // C; case/cyclicP=> z ->{C} sCG iCG.
+rewrite [X]defU // defU -?cycle_subG //.
+by apply: double_inj; rewrite -muln2 -iCG Lagrange // oG -mul2n.
+Qed.
+
+Theorem quaternion_structure :
+ n > 2 -> extremal_generators G 2 n (x, y) -> G \isog 'Q_m ->
+ [/\ [/\ pprod X Y = G, {in G :\: X, forall t, #[t] = 4}
+ & {in X & G :\: X, forall z t, z ^ t = z^-1}],
+ [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r
+ & nil_class G = n.-1],
+ [/\ 'Z(G) = <[x ^+ r]>, #|'Z(G)| = 2,
+ forall u, u \in G -> #[u] = 2 -> u = x ^+ r,
+ 'Ohm_1(G) = <[x ^+ r]> /\ 'Ohm_2(G) = G
+ & forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>],
+ [/\ yG :|: xyG = G :\: X /\ [disjoint yG & xyG]
+ & forall M, maximal M G = pred3 X My Mxy M]
+ & n > 3 ->
+ [/\ My \isog 'Q_q, Mxy \isog 'Q_q
+ & forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X]].
+Proof.
+move=> n_gt2 genG isoG; have [def2q def2r ltqm ltrq] := def2qr (ltnW n_gt2).
+have [oG Gx ox X'y] := genG; rewrite -/m -/q -/X in oG ox X'y.
+case/extremal_generators_facts: genG; rewrite -/X // => pG maxX nsXG defXY nXY.
+have [sXG nXG]:= andP nsXG; have [Gy notXy]:= setDP X'y.
+have oxr: #[x ^+ r] = 2 by rewrite orderXdiv ox -def2r ?dvdn_mull ?mulnK.
+have ox2: #[x ^+ 2] = r by rewrite orderXdiv ox -def2r ?dvdn_mulr ?mulKn.
+have [[u v] [_ Gu ou U'v] [ov v2 uv]] := generators_quaternion n_gt2 isoG.
+have defUv: <[u]> :* v = G :\: <[u]>.
+ apply: rcoset_index2; rewrite -?divgS ?cycle_subG //.
+ by rewrite oG -orderE ou -def2q mulnK.
+have invUV: {in <[u]> & <[u]> :* v, forall z t, z ^ t = z^-1}.
+ move=> z t; case/cycleP=> i ->; case/rcosetP=> ?; case/cycleP=> j -> ->{z t}.
+ by rewrite conjgM {2}/conjg commuteX2 // mulKg conjXg uv expgVn.
+have U'2: {in <[u]> :* v, forall t, t ^+ 2 = u ^+ r}.
+ move=> t; case/rcosetP=> z Uz ->; rewrite expgS {1}(conjgC z) -mulgA.
+ by rewrite invUV ?rcoset_refl // mulKg -(expgS v 1) v2.
+have our: #[u ^+ r] = 2 by rewrite orderXdiv ou -/q -def2r ?dvdn_mull ?mulnK.
+have def_ur: {in G, forall t, #[t] = 2 -> t = u ^+ r}.
+ move=> t Gt /= ot; case Ut: (t \in <[u]>); last first.
+ move/eqP: ot; rewrite eqn_dvd order_dvdn -order_eq1 U'2 ?our //.
+ by rewrite defUv inE Ut.
+ have p2u: 2.-elt u by rewrite /p_elt ou pnat_exp.
+ have: t \in 'Ohm_1(<[u]>).
+ by rewrite (OhmE _ p2u) mem_gen // !inE Ut -order_dvdn ot.
+ rewrite (Ohm_p_cycle _ p2u) ou pfactorK // subn1 -/r cycle_traject our !inE.
+ by rewrite -order_eq1 ot /= mulg1; move/eqP.
+have defU: n > 3 -> {in G, forall z, #[z] = q -> <[z]> = <[u]>}.
+ move=> n_gt3 z Gz oz; apply/eqP; rewrite eqEcard -!orderE oz cycle_subG.
+ rewrite ou leqnn andbT; apply: contraLR n_gt3 => notUz.
+ rewrite -(ltn_predK n_gt2) ltnS -(@ltn_exp2l 2) // -/q -oz.
+ by rewrite (@orderXprime _ 2 2) // U'2 // defUv inE notUz.
+have def_xr: x ^+ r = u ^+ r by apply: def_ur; rewrite ?groupX.
+have X'2: {in G :\: X, forall t, t ^+ 2 = u ^+ r}.
+ case: (ltngtP n 3) => [|n_gt3|n3 t]; first by rewrite ltnNge n_gt2.
+ by rewrite /X defU // -defUv.
+ case/setDP=> Gt notXt.
+ case Ut: (t \in <[u]>); last by rewrite U'2 // defUv inE Ut.
+ rewrite [t ^+ 2]def_ur ?groupX //.
+ have:= order_dvdG Ut; rewrite -orderE ou /q n3 dvdn_divisors ?inE //=.
+ rewrite order_eq1 (negbTE (group1_contra notXt)) /=.
+ case/pred2P=> oz; last by rewrite orderXdiv oz.
+ by rewrite [t]def_ur // -def_xr mem_cycle in notXt.
+have oX': {in G :\: X, forall z, #[z] = 4}.
+ by move=> t X't /=; rewrite (@orderXprime _ 2 2) // X'2.
+have defZ: 'Z(G) = <[x ^+ r]>.
+ apply/eqP; rewrite eqEcard andbC -orderE oxr -{1}(setIidPr (center_sub G)).
+ rewrite cardG_gt1 /= meet_center_nil ?(pgroup_nil pG) //; last first.
+ by rewrite -cardG_gt1 oG (leq_trans _ ltqm).
+ apply/subsetP=> z; case/setIP=> Gz cGz; have [Gv _]:= setDP U'v.
+ case Uvz: (z \in <[u]> :* v).
+ move/eqP: (invUV _ _ (cycle_id u) Uvz).
+ rewrite /conjg -(centP cGz) // mulKg eq_sym eq_invg_mul -(order_dvdn _ 2).
+ by rewrite ou pfactor_dvdn // -(subnKC n_gt2).
+ move/idPn: Uvz; rewrite defUv inE Gz andbT negbK def_xr => Uz.
+ have p_u: 2.-elt u := mem_p_elt pG Gu.
+ suff: z \in 'Ohm_1(<[u]>) by rewrite (Ohm_p_cycle 1 p_u) ou pfactorK // subn1.
+ rewrite (OhmE _ p_u) mem_gen // !inE Uz /= -eq_invg_mul.
+ by rewrite -(invUV _ v) ?rcoset_refl // /conjg (centP cGz) ?mulKg.
+have{invUV} invXX': {in X & G :\: X, forall z t, z ^ t = z^-1}.
+ case: (ltngtP n 3) => [|n_gt3|n3 t z Xt]; first by rewrite ltnNge n_gt2.
+ by rewrite /X defU // -defUv.
+ case/setDP=> Gz notXz; rewrite /q /r n3 /= in oxr ox.
+ suff xz: x ^ z = x^-1 by case/cycleP: Xt => i ->; rewrite conjXg xz expgVn.
+ have: x ^ z \in X by rewrite memJ_norm ?cycle_id ?(subsetP nXG).
+ rewrite invg_expg /X cycle_traject ox !inE /= !mulg1 -order_eq1 orderJ ox /=.
+ case/or3P; move/eqP=> //; last by move/(congr1 order); rewrite orderJ ox oxr.
+ move/conjg_fixP; rewrite (sameP commgP cent1P) cent1C -cent_cycle -/X => cXz.
+ have defXz: X * <[z]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG.
+ have: z \in 'Z(G) by rewrite inE Gz -defXz centM inE cXz cent_cycle cent1id.
+ by rewrite defZ => Xr_z; rewrite (subsetP (cycleX x r)) in notXz.
+have nXiG k: G \subset 'N(<[x ^+ k]>).
+ apply: char_norm_trans nXG.
+ by rewrite cycle_subgroup_char // cycle_subG mem_cycle.
+have memL i: x ^+ (2 ^ i) \in 'L_i.+1(G).
+ elim: i => // i IHi; rewrite -groupV expnSr expgM invMg.
+ by rewrite -{2}(invXX' _ y) ?mem_cycle ?cycle_id ?mem_commg.
+have defG': G^`(1) = <[x ^+ 2]>.
+ apply/eqP; rewrite eqEsubset cycle_subG (memL 1%N) ?der1_min //=.
+ rewrite (p2group_abelian (quotient_pgroup _ pG)) ?card_quotient //=.
+ rewrite -divgS ?cycle_subG ?groupX // oG -orderE ox2.
+ by rewrite -def2q -def2r mulnA mulnK.
+have defG1: 'Mho^1(G) = <[x ^+ 2]>.
+ apply/eqP; rewrite (MhoE _ pG) eqEsubset !gen_subG sub1set andbC.
+ rewrite mem_gen; last exact: mem_imset.
+ apply/subsetP=> z2; case/imsetP=> z Gz ->{z2}.
+ case Xz: (z \in X).
+ by case/cycleP: Xz => i ->; rewrite -expgM mulnC expgM mem_cycle.
+ rewrite (X'2 z) ?inE ?Xz // -def_xr.
+ by rewrite /r -(subnKC n_gt2) expnS expgM mem_cycle.
+have defPhi: 'Phi(G) = <[x ^+ 2]>.
+ by rewrite (Phi_joing pG) defG' defG1 (joing_idPl _).
+have def_tG: {in G :\: X, forall t, t ^: G = <[x ^+ 2]> :* t}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ have defJt: {in X, forall z, t ^ z = z ^- 2 * t}.
+ move=> z Xz; rewrite /= invMg -mulgA (conjgC _ t).
+ by rewrite (invXX' _ t) ?groupV ?invgK.
+ have defGt: X * <[t]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG.
+ apply/setP=> tz; apply/imsetP/rcosetP=> [[t'z] | [z]].
+ rewrite -defGt -normC ?cycle_subG ?(subsetP nXG) //.
+ case/imset2P=> t' z; case/cycleP=> j -> Xz -> -> {tz t'z t'}.
+ exists (z ^- 2); last by rewrite conjgM {2}/conjg commuteX // mulKg defJt.
+ case/cycleP: Xz => i ->{z}.
+ by rewrite groupV -expgM mulnC expgM mem_cycle.
+ case/cycleP=> i -> -> {z tz}; exists (x ^- i); first by rewrite groupV groupX.
+ by rewrite defJt ?groupV ?mem_cycle // expgVn invgK -!expgM mulnC.
+have defMt: {in G :\: X, forall t, <[x ^+ 2]> <*> <[t]> = <<t ^: G>>}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ apply/eqP; have: t \in <<t ^: G>> by rewrite mem_gen ?class_refl.
+ rewrite def_tG // eqEsubset join_subG !cycle_subG !gen_subG => tGt.
+ rewrite tGt -(groupMr _ tGt) mem_gen ?mem_mulg ?cycle_id ?set11 //=.
+ by rewrite mul_subG ?joing_subl // -gen_subG joing_subr.
+have sMtG: {in G :\: X, forall t, <<t ^: G>> \subset G}.
+ by move=> t; case/setDP=> Gt _; rewrite gen_subG class_subG.
+have oMt: {in G :\: X, forall t, #|<<t ^: G>>| = q}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ rewrite -defMt // -(Lagrange (joing_subl _ _)) -orderE ox2 -def2r mulnC.
+ congr (_ * r)%N; rewrite -card_quotient /=; last first.
+ by rewrite defMt // (subset_trans _ (nXiG 2)) ?sMtG.
+ rewrite joingC quotientYidr ?(subset_trans _ (nXiG 2)) ?cycle_subG //.
+ rewrite quotient_cycle ?(subsetP (nXiG 2)) //= -defPhi.
+ rewrite -orderE (abelem_order_p (Phi_quotient_abelem pG)) ?mem_quotient //.
+ apply: contraNneq notXt; move/coset_idr; move/implyP=> /=.
+ by rewrite defPhi ?(subsetP (nXiG 2)) //; apply: subsetP; exact: cycleX.
+have maxMt: {in G :\: X, forall t, maximal <<t ^: G>> G}.
+ move=> t X't; rewrite /= p_index_maximal -?divgS ?sMtG ?oMt //.
+ by rewrite oG -def2q mulnK.
+have X'xy: x * y \in G :\: X by rewrite !inE !groupMl ?cycle_id ?notXy.
+have ti_yG_xyG: [disjoint yG & xyG].
+ apply/pred0P=> t; rewrite /= /yG /xyG !def_tG //; apply/andP=> [[yGt]].
+ rewrite rcoset_sym (rcoset_transl yGt) mem_rcoset mulgK; move/order_dvdG.
+ by rewrite -orderE ox2 ox gtnNdvd.
+have s_tG_X': {in G :\: X, forall t, t ^: G \subset G :\: X}.
+ by move=> t X't /=; rewrite class_sub_norm // normsD ?normG.
+have defX': yG :|: xyG = G :\: X.
+ apply/eqP; rewrite eqEcard subUset !s_tG_X' //= -(leq_add2l q) -{1}ox orderE.
+ rewrite -/X -{1}(setIidPr sXG) cardsID oG -def2q mul2n -addnn leq_add2l.
+ rewrite -(leq_add2r #|yG :&: xyG|) cardsUI disjoint_setI0 // cards0 addn0.
+ by rewrite /yG /xyG !def_tG // !card_rcoset addnn -mul2n -orderE ox2 def2r.
+rewrite pprodE //; split=> // [|||n_gt3].
+- rewrite defG'; split=> //; apply/eqP; rewrite eqn_leq.
+ rewrite (leq_trans (nil_class_pgroup pG)); last first.
+ by rewrite oG pfactorK // -(subnKC n_gt2).
+ rewrite -(subnKC (ltnW n_gt2)) subn2 ltnNge.
+ rewrite (sameP (lcn_nil_classP _ (pgroup_nil pG)) eqP).
+ by apply/trivgPn; exists (x ^+ r); rewrite ?memL // -order_gt1 oxr.
+- rewrite {2}def_xr defZ; split=> //; last exact: extend_cyclic_Mho.
+ split; apply/eqP; last first.
+ have sX'G2: {subset G :\: X <= 'Ohm_2(G)}.
+ move=> z X'z; have [Gz _] := setDP X'z.
+ by rewrite (OhmE 2 pG) mem_gen // !inE Gz -order_dvdn oX'.
+ rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG.
+ by rewrite -(groupMr _ (sX'G2 y X'y)) !sX'G2.
+ rewrite eqEsubset (OhmE 1 pG) cycle_subG gen_subG andbC.
+ rewrite mem_gen ?inE ?groupX -?order_dvdn ?oxr //=.
+ apply/subsetP=> t; case/setIP=> Gt; rewrite inE -order_dvdn /=.
+ rewrite dvdn_divisors ?inE //= order_eq1.
+ case/pred2P=> [->|]; first exact: group1.
+ by move/def_ur=> -> //; rewrite def_xr cycle_id.
+- split=> //= H; apply/idP/idP=> [maxH |]; last first.
+ by case/or3P=> /eqP->; rewrite ?maxMt.
+ have [sHG nHG]:= andP (p_maximal_normal pG maxH).
+ have oH: #|H| = q.
+ apply: double_inj; rewrite -muln2 -(p_maximal_index pG maxH) Lagrange //.
+ by rewrite oG -mul2n.
+ rewrite !(eq_sym (gval H)) -eq_sym !eqEcard oH -orderE ox !oMt // !leqnn.
+ case sHX: (H \subset X) => //=; case/subsetPn: sHX => z Hz notXz.
+ have: z \in yG :|: xyG by rewrite defX' inE notXz (subsetP sHG).
+ rewrite !andbT !gen_subG /yG /xyG.
+ by case/setUP=> /class_transr <-; rewrite !class_sub_norm ?Hz ?orbT.
+have isoMt: {in G :\: X, forall z, <<z ^: G>> \isog 'Q_q}.
+ have n1_gt2: n.-1 > 2 by rewrite -(subnKC n_gt3).
+ move=> z X'z /=; rewrite isogEcard card_quaternion ?oMt // leqnn andbT.
+ rewrite Grp_quaternion //; apply/existsP; exists (x ^+ 2, z) => /=.
+ rewrite defMt // -/q -/r !xpair_eqE -!expgM def2r -order_dvdn ox dvdnn.
+ rewrite -expnS prednK; last by rewrite -subn2 subn_gt0.
+ by rewrite X'2 // def_xr !eqxx /= invXX' ?mem_cycle.
+rewrite !isoMt //; split=> // C; case/cyclicP=> z ->{C} sCG iCG.
+rewrite [X]defU // defU -?cycle_subG //.
+by apply: double_inj; rewrite -muln2 -iCG Lagrange // oG -mul2n.
+Qed.
+
+Theorem semidihedral_structure :
+ n > 3 -> extremal_generators G 2 n (x, y) -> G \isog 'SD_m -> #[y] = 2 ->
+ [/\ [/\ X ><| Y = G, #[x * y] = 4
+ & {in X & G :\: X, forall z t, z ^ t = z ^+ r.-1}],
+ [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r
+ & nil_class G = n.-1],
+ [/\ 'Z(G) = <[x ^+ r]>, #|'Z(G)| = 2,
+ 'Ohm_1(G) = My /\ 'Ohm_2(G) = G
+ & forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>],
+ [/\ yG :|: xyG = G :\: X /\ [disjoint yG & xyG]
+ & forall H, maximal H G = pred3 X My Mxy H]
+ & [/\ My \isog 'D_q, Mxy \isog 'Q_q
+ & forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X]].
+Proof.
+move=> n_gt3 genG isoG oy.
+have [def2q def2r ltqm ltrq] := def2qr (ltnW (ltnW n_gt3)).
+have [oG Gx ox X'y] := genG; rewrite -/m -/q -/X in oG ox X'y.
+case/extremal_generators_facts: genG; rewrite -/X // => pG maxX nsXG defXY nXY.
+have [sXG nXG]:= andP nsXG; have [Gy notXy]:= setDP X'y.
+have ox2: #[x ^+ 2] = r by rewrite orderXdiv ox -def2r ?dvdn_mulr ?mulKn.
+have oxr: #[x ^+ r] = 2 by rewrite orderXdiv ox -def2r ?dvdn_mull ?mulnK.
+have [[u v] [_ Gu ou U'v] [ov uv]] := generators_semidihedral n_gt3 isoG.
+have defUv: <[u]> :* v = G :\: <[u]>.
+ apply: rcoset_index2; rewrite -?divgS ?cycle_subG //.
+ by rewrite oG -orderE ou -def2q mulnK.
+have invUV: {in <[u]> & <[u]> :* v, forall z t, z ^ t = z ^+ r.-1}.
+ move=> z t; case/cycleP=> i ->; case/rcosetP=> ?; case/cycleP=> j -> ->{z t}.
+ by rewrite conjgM {2}/conjg commuteX2 // mulKg conjXg uv -!expgM mulnC.
+have [vV yV]: v^-1 = v /\ y^-1 = y by rewrite !invg_expg ov oy.
+have defU: {in G, forall z, #[z] = q -> <[z]> = <[u]>}.
+ move=> z Gz /= oz; apply/eqP; rewrite eqEcard -!orderE oz ou leqnn andbT.
+ apply: contraLR (n_gt3) => notUz; rewrite -leqNgt -(ltn_predK n_gt3) ltnS.
+ rewrite -(@dvdn_Pexp2l 2) // -/q -{}oz order_dvdn expgM (expgS z).
+ have{Gz notUz} [z' Uz' ->{z}]: exists2 z', z' \in <[u]> & z = z' * v.
+ by apply/rcosetP; rewrite defUv inE -cycle_subG notUz Gz.
+ rewrite {2}(conjgC z') invUV ?rcoset_refl // mulgA -{2}vV mulgK -expgS.
+ by rewrite prednK // -expgM mulnC def2r -order_dvdn /q -ou order_dvdG.
+have{invUV} invXX': {in X & G :\: X, forall z t, z ^ t = z ^+ r.-1}.
+ by rewrite /X defU -?defUv.
+have xy2: (x * y) ^+ 2 = x ^+ r.
+ rewrite expgS {2}(conjgC x) invXX' ?cycle_id // mulgA -{2}yV mulgK -expgS.
+ by rewrite prednK.
+have oxy: #[x * y] = 4 by rewrite (@orderXprime _ 2 2) ?xy2.
+have r_gt2: r > 2 by rewrite (ltn_exp2l 1) // -(subnKC n_gt3).
+have coXr1: coprime #[x] (2 ^ (n - 3)).-1.
+ rewrite ox coprime_expl // -(@coprime_pexpl (n - 3)) ?coprimenP ?subn_gt0 //.
+ by rewrite expn_gt0.
+have def2r1: (2 * (2 ^ (n - 3)).-1).+1 = r.-1.
+ rewrite -!subn1 mulnBr -expnS [_.+1]subnSK ?(ltn_exp2l 0) //.
+ by rewrite /r -(subnKC n_gt3).
+have defZ: 'Z(G) = <[x ^+ r]>.
+ apply/eqP; rewrite eqEcard andbC -orderE oxr -{1}(setIidPr (center_sub G)).
+ rewrite cardG_gt1 /= meet_center_nil ?(pgroup_nil pG) //; last first.
+ by rewrite -cardG_gt1 oG (leq_trans _ ltqm).
+ apply/subsetP=> z /setIP[Gz cGz].
+ case X'z: (z \in G :\: X).
+ move/eqP: (invXX' _ _ (cycle_id x) X'z).
+ rewrite /conjg -(centP cGz) // mulKg -def2r1 eq_mulVg1 expgS mulKg mulnC.
+ rewrite -order_dvdn Gauss_dvdr // order_dvdn -order_eq1.
+ by rewrite ox2 -(subnKC r_gt2).
+ move/idPn: X'z; rewrite inE Gz andbT negbK => Xz.
+ have:= Ohm_p_cycle 1 (mem_p_elt pG Gx); rewrite ox pfactorK // subn1 => <-.
+ rewrite (OhmE _ (mem_p_elt pG Gx)) mem_gen // !inE Xz /=.
+ rewrite -(expgK coXr1 Xz) -!expgM mulnCA -order_dvdn dvdn_mull //.
+ rewrite mulnC order_dvdn -(inj_eq (mulgI z)) -expgS mulg1 def2r1.
+ by rewrite -(invXX' z y) // /conjg (centP cGz) ?mulKg.
+have nXiG k: G \subset 'N(<[x ^+ k]>).
+ apply: char_norm_trans nXG.
+ by rewrite cycle_subgroup_char // cycle_subG mem_cycle.
+have memL i: x ^+ (2 ^ i) \in 'L_i.+1(G).
+ elim: i => // i IHi; rewrite -(expgK coXr1 (mem_cycle _ _)) groupX //.
+ rewrite -expgM expnSr -mulnA expgM -(mulKg (x ^+ (2 ^ i)) (_ ^+ _)).
+ by rewrite -expgS def2r1 -(invXX' _ y) ?mem_cycle ?mem_commg.
+have defG': G^`(1) = <[x ^+ 2]>.
+ apply/eqP; rewrite eqEsubset cycle_subG (memL 1%N) ?der1_min //=.
+ rewrite (p2group_abelian (quotient_pgroup _ pG)) ?card_quotient //=.
+ rewrite -divgS ?cycle_subG ?groupX // oG -orderE ox2.
+ by rewrite -def2q -def2r mulnA mulnK.
+have defG1: 'Mho^1(G) = <[x ^+ 2]>.
+ apply/eqP; rewrite (MhoE _ pG) eqEsubset !gen_subG sub1set andbC.
+ rewrite mem_gen; last exact: mem_imset.
+ apply/subsetP=> z2; case/imsetP=> z Gz ->{z2}.
+ case Xz: (z \in X).
+ by case/cycleP: Xz => i ->; rewrite -expgM mulnC expgM mem_cycle.
+ have{Xz Gz} [xi Xxi ->{z}]: exists2 xi, xi \in X & z = xi * y.
+ have Uvy: y \in <[u]> :* v by rewrite defUv -(defU x).
+ apply/rcosetP; rewrite /X defU // (rcoset_transl Uvy) defUv.
+ by rewrite inE -(defU x) ?Xz.
+ rewrite expn1 expgS {2}(conjgC xi) -{2}[y]/(y ^+ 2.-1) -{1}oy -invg_expg.
+ rewrite mulgA mulgK invXX' // -expgS prednK // /r -(subnKC n_gt3) expnS.
+ by case/cycleP: Xxi => i ->; rewrite -expgM mulnCA expgM mem_cycle.
+have defPhi: 'Phi(G) = <[x ^+ 2]>.
+ by rewrite (Phi_joing pG) defG' defG1 (joing_idPl _).
+have def_tG: {in G :\: X, forall t, t ^: G = <[x ^+ 2]> :* t}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ have defJt: {in X, forall z, t ^ z = z ^+ r.-2 * t}.
+ move=> z Xz /=; rewrite -(mulKg z (z ^+ _)) -expgS -subn2.
+ have X'tV: t^-1 \in G :\: X by rewrite inE !groupV notXt.
+ by rewrite subnSK 1?ltnW // subn1 -(invXX' _ t^-1) // -mulgA -conjgCV.
+ have defGt: X * <[t]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG.
+ apply/setP=> tz; apply/imsetP/rcosetP=> [[t'z] | [z]].
+ rewrite -defGt -normC ?cycle_subG ?(subsetP nXG) //.
+ case/imset2P=> t' z; case/cycleP=> j -> Xz -> -> {t' t'z tz}.
+ exists (z ^+ r.-2); last first.
+ by rewrite conjgM {2}/conjg commuteX // mulKg defJt.
+ case/cycleP: Xz => i ->{z}.
+ by rewrite -def2r1 -expgM mulnCA expgM mem_cycle.
+ case/cycleP=> i -> -> {z tz}.
+ exists (x ^+ (i * expg_invn X (2 ^ (n - 3)).-1)); first by rewrite groupX.
+ rewrite defJt ?mem_cycle // -def2r1 -!expgM.
+ by rewrite mulnAC mulnA mulnC muln2 !expgM expgK ?mem_cycle.
+have defMt: {in G :\: X, forall t, <[x ^+ 2]> <*> <[t]> = <<t ^: G>>}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ apply/eqP; have: t \in <<t ^: G>> by rewrite mem_gen ?class_refl.
+ rewrite def_tG // eqEsubset join_subG !cycle_subG !gen_subG => tGt.
+ rewrite tGt -(groupMr _ tGt) mem_gen ?mem_mulg ?cycle_id ?set11 //=.
+ by rewrite mul_subG ?joing_subl // -gen_subG joing_subr.
+have sMtG: {in G :\: X, forall t, <<t ^: G>> \subset G}.
+ by move=> t; case/setDP=> Gt _; rewrite gen_subG class_subG.
+have oMt: {in G :\: X, forall t, #|<<t ^: G>>| = q}.
+ move=> t X't; have [Gt notXt] := setDP X't.
+ rewrite -defMt // -(Lagrange (joing_subl _ _)) -orderE ox2 -def2r mulnC.
+ congr (_ * r)%N; rewrite -card_quotient /=; last first.
+ by rewrite defMt // (subset_trans _ (nXiG 2)) ?sMtG.
+ rewrite joingC quotientYidr ?(subset_trans _ (nXiG 2)) ?cycle_subG //.
+ rewrite quotient_cycle ?(subsetP (nXiG 2)) //= -defPhi -orderE.
+ rewrite (abelem_order_p (Phi_quotient_abelem pG)) ?mem_quotient //.
+ apply: contraNneq notXt; move/coset_idr; move/implyP=> /=.
+ by rewrite /= defPhi (subsetP (nXiG 2)) //; apply: subsetP; exact: cycleX.
+have maxMt: {in G :\: X, forall t, maximal <<t ^: G>> G}.
+ move=> t X't /=; rewrite p_index_maximal -?divgS ?sMtG ?oMt //.
+ by rewrite oG -def2q mulnK.
+have X'xy: x * y \in G :\: X by rewrite !inE !groupMl ?cycle_id ?notXy.
+have ti_yG_xyG: [disjoint yG & xyG].
+ apply/pred0P=> t; rewrite /= /yG /xyG !def_tG //; apply/andP=> [[yGt]].
+ rewrite rcoset_sym (rcoset_transl yGt) mem_rcoset mulgK; move/order_dvdG.
+ by rewrite -orderE ox2 ox gtnNdvd.
+have s_tG_X': {in G :\: X, forall t, t ^: G \subset G :\: X}.
+ by move=> t X't /=; rewrite class_sub_norm // normsD ?normG.
+have defX': yG :|: xyG = G :\: X.
+ apply/eqP; rewrite eqEcard subUset !s_tG_X' //= -(leq_add2l q) -{1}ox orderE.
+ rewrite -/X -{1}(setIidPr sXG) cardsID oG -def2q mul2n -addnn leq_add2l.
+ rewrite -(leq_add2r #|yG :&: xyG|) cardsUI disjoint_setI0 // cards0 addn0.
+ by rewrite /yG /xyG !def_tG // !card_rcoset addnn -mul2n -orderE ox2 def2r.
+split.
+- by rewrite sdprodE // setIC prime_TIg ?cycle_subG // -orderE oy.
+- rewrite defG'; split=> //.
+ apply/eqP; rewrite eqn_leq (leq_trans (nil_class_pgroup pG)); last first.
+ by rewrite oG pfactorK // -(subnKC n_gt3).
+ rewrite -(subnKC (ltnW (ltnW n_gt3))) subn2 ltnNge.
+ rewrite (sameP (lcn_nil_classP _ (pgroup_nil pG)) eqP).
+ by apply/trivgPn; exists (x ^+ r); rewrite ?memL // -order_gt1 oxr.
+- rewrite defZ; split=> //; last exact: extend_cyclic_Mho.
+ split; apply/eqP; last first.
+ have sX'G2: {subset G :\: X <= 'Ohm_2(G)}.
+ move=> t X't; have [Gt _] := setDP X't; rewrite -defX' in X't.
+ rewrite (OhmE 2 pG) mem_gen // !inE Gt -order_dvdn.
+ by case/setUP: X't; case/imsetP=> z _ ->; rewrite orderJ ?oy ?oxy.
+ rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG.
+ by rewrite -(groupMr _ (sX'G2 y X'y)) !sX'G2.
+ rewrite eqEsubset andbC gen_subG class_sub_norm ?gFnorm //.
+ rewrite (OhmE 1 pG) mem_gen ?inE ?Gy -?order_dvdn ?oy // gen_subG /= -/My.
+ apply/subsetP=> t; rewrite !inE; case/andP=> Gt t2.
+ have pX := pgroupS sXG pG.
+ case Xt: (t \in X).
+ have: t \in 'Ohm_1(X) by rewrite (OhmE 1 pX) mem_gen // !inE Xt.
+ apply: subsetP; rewrite (Ohm_p_cycle 1 pX) ox pfactorK //.
+ rewrite -(subnKC n_gt3) expgM (subset_trans (cycleX _ _)) //.
+ by rewrite /My -defMt ?joing_subl.
+ have{Xt}: t \in yG :|: xyG by rewrite defX' inE Xt.
+ case/setUP; first exact: mem_gen.
+ by case/imsetP=> z _ def_t; rewrite -order_dvdn def_t orderJ oxy in t2.
+- split=> //= H; apply/idP/idP=> [maxH |]; last first.
+ by case/or3P=> /eqP->; rewrite ?maxMt.
+ have [sHG nHG]:= andP (p_maximal_normal pG maxH).
+ have oH: #|H| = q.
+ apply: double_inj; rewrite -muln2 -(p_maximal_index pG maxH) Lagrange //.
+ by rewrite oG -mul2n.
+ rewrite !(eq_sym (gval H)) -eq_sym !eqEcard oH -orderE ox !oMt // !leqnn.
+ case sHX: (H \subset X) => //=; case/subsetPn: sHX => t Ht notXt.
+ have: t \in yG :|: xyG by rewrite defX' inE notXt (subsetP sHG).
+ rewrite !andbT !gen_subG /yG /xyG.
+ by case/setUP=> /class_transr <-; rewrite !class_sub_norm ?Ht ?orbT.
+have n1_gt2: n.-1 > 2 by [rewrite -(subnKC n_gt3)]; have n1_gt1 := ltnW n1_gt2.
+rewrite !isogEcard card_2dihedral ?card_quaternion ?oMt // leqnn !andbT.
+have invX2X': {in G :\: X, forall t, x ^+ 2 ^ t == x ^- 2}.
+ move=> t X't; rewrite /= invXX' ?mem_cycle // eq_sym eq_invg_mul -expgS.
+ by rewrite prednK // -order_dvdn ox2.
+ rewrite Grp_2dihedral ?Grp_quaternion //; split=> [||C].
+- apply/existsP; exists (x ^+ 2, y); rewrite /= defMt // !xpair_eqE.
+ by rewrite -!expgM def2r -!order_dvdn ox oy dvdnn eqxx /= invX2X'.
+- apply/existsP; exists (x ^+ 2, x * y); rewrite /= defMt // !xpair_eqE.
+ rewrite -!expgM def2r -order_dvdn ox xy2 dvdnn eqxx invX2X' //=.
+ by rewrite andbT /r -(subnKC n_gt3).
+case/cyclicP=> z ->{C} sCG iCG; rewrite [X]defU // defU -?cycle_subG //.
+by apply: double_inj; rewrite -muln2 -iCG Lagrange // oG -mul2n.
+Qed.
+
+End ExtremalStructure.
+
+Section ExtremalClass.
+
+Variables (gT : finGroupType) (G : {group gT}).
+
+Inductive extremal_group_type :=
+ ModularGroup | Dihedral | SemiDihedral | Quaternion | NotExtremal.
+
+Definition index_extremal_group_type c :=
+ match c with
+ | ModularGroup => 0
+ | Dihedral => 1
+ | SemiDihedral => 2
+ | Quaternion => 3
+ | NotExtremal => 4
+ end%N.
+
+Definition enum_extremal_groups :=
+ [:: ModularGroup; Dihedral; SemiDihedral; Quaternion].
+
+Lemma cancel_index_extremal_groups :
+ cancel index_extremal_group_type (nth NotExtremal enum_extremal_groups).
+Proof. by case. Qed.
+Local Notation extgK := cancel_index_extremal_groups.
+
+Import choice.
+
+Definition extremal_group_eqMixin := CanEqMixin extgK.
+Canonical extremal_group_eqType := EqType _ extremal_group_eqMixin.
+Definition extremal_group_choiceMixin := CanChoiceMixin extgK.
+Canonical extremal_group_choiceType := ChoiceType _ extremal_group_choiceMixin.
+Definition extremal_group_countMixin := CanCountMixin extgK.
+Canonical extremal_group_countType := CountType _ extremal_group_countMixin.
+Lemma bound_extremal_groups (c : extremal_group_type) : pickle c < 6.
+Proof. by case: c. Qed.
+Definition extremal_group_finMixin := Finite.CountMixin bound_extremal_groups.
+Canonical extremal_group_finType := FinType _ extremal_group_finMixin.
+
+Definition extremal_class (A : {set gT}) :=
+ let m := #|A| in let p := pdiv m in let n := logn p m in
+ if (n > 1) && (A \isog 'D_(2 ^ n)) then Dihedral else
+ if (n > 2) && (A \isog 'Q_(2 ^ n)) then Quaternion else
+ if (n > 3) && (A \isog 'SD_(2 ^ n)) then SemiDihedral else
+ if (n > 2) && (A \isog 'Mod_(p ^ n)) then ModularGroup else
+ NotExtremal.
+
+Definition extremal2 A := extremal_class A \in behead enum_extremal_groups.
+
+Lemma dihedral_classP :
+ extremal_class G = Dihedral <-> (exists2 n, n > 1 & G \isog 'D_(2 ^ n)).
+Proof.
+rewrite /extremal_class; split=> [ | [n n_gt1 isoG]].
+ by move: (logn _ _) => n; do 4?case: ifP => //; case/andP; exists n.
+rewrite (card_isog isoG) card_2dihedral // -(ltn_predK n_gt1) pdiv_pfactor //.
+by rewrite pfactorK // (ltn_predK n_gt1) n_gt1 isoG.
+Qed.
+
+Lemma quaternion_classP :
+ extremal_class G = Quaternion <-> (exists2 n, n > 2 & G \isog 'Q_(2 ^ n)).
+Proof.
+rewrite /extremal_class; split=> [ | [n n_gt2 isoG]].
+ by move: (logn _ _) => n; do 4?case: ifP => //; case/andP; exists n.
+rewrite (card_isog isoG) card_quaternion // -(ltn_predK n_gt2) pdiv_pfactor //.
+rewrite pfactorK // (ltn_predK n_gt2) n_gt2 isoG.
+case: andP => // [[n_gt1 isoGD]].
+have [[x y] genG [oy _ _]]:= generators_quaternion n_gt2 isoG.
+have [_ _ _ X'y] := genG.
+by case/dihedral2_structure: genG oy => // [[_ ->]].
+Qed.
+
+Lemma semidihedral_classP :
+ extremal_class G = SemiDihedral <-> (exists2 n, n > 3 & G \isog 'SD_(2 ^ n)).
+Proof.
+rewrite /extremal_class; split=> [ | [n n_gt3 isoG]].
+ by move: (logn _ _) => n; do 4?case: ifP => //; case/andP; exists n.
+rewrite (card_isog isoG) card_semidihedral //.
+rewrite -(ltn_predK n_gt3) pdiv_pfactor // pfactorK // (ltn_predK n_gt3) n_gt3.
+have [[x y] genG [oy _]]:= generators_semidihedral n_gt3 isoG.
+have [_ Gx _ X'y]:= genG.
+case: andP => [[n_gt1 isoGD]|_].
+ have [[_ oxy _ _] _ _ _]:= semidihedral_structure n_gt3 genG isoG oy.
+ case: (dihedral2_structure n_gt1 genG isoGD) oxy => [[_ ->]] //.
+ by rewrite !inE !groupMl ?cycle_id in X'y *.
+case: andP => // [[n_gt2 isoGQ]|]; last by rewrite isoG.
+by case: (quaternion_structure n_gt2 genG isoGQ) oy => [[_ ->]].
+Qed.
+
+Lemma odd_not_extremal2 : odd #|G| -> ~~ extremal2 G.
+Proof.
+rewrite /extremal2 /extremal_class; case: logn => // n'.
+case: andP => [[n_gt1 isoG] | _].
+ by rewrite (card_isog isoG) card_2dihedral ?odd_exp.
+case: andP => [[n_gt2 isoG] | _].
+ by rewrite (card_isog isoG) card_quaternion ?odd_exp.
+case: andP => [[n_gt3 isoG] | _].
+ by rewrite (card_isog isoG) card_semidihedral ?odd_exp.
+by case: ifP.
+Qed.
+
+Lemma modular_group_classP :
+ extremal_class G = ModularGroup
+ <-> (exists2 p, prime p &
+ exists2 n, n >= (p == 2) + 3 & G \isog 'Mod_(p ^ n)).
+Proof.
+rewrite /extremal_class; split=> [ | [p p_pr [n n_gt23 isoG]]].
+ move: (pdiv _) => p; set n := logn p _; do 4?case: ifP => //.
+ case/andP=> n_gt2 isoG _ _; rewrite ltnW //= => not_isoG _.
+ exists p; first by move: n_gt2; rewrite /n lognE; case (prime p).
+ exists n => //; case: eqP => // p2; rewrite ltn_neqAle; case: eqP => // n3.
+ by case/idP: not_isoG; rewrite p2 -n3 in isoG *.
+have n_gt2 := leq_trans (leq_addl _ _) n_gt23; have n_gt1 := ltnW n_gt2.
+have n_gt0 := ltnW n_gt1; have def_n := prednK n_gt0.
+have [[x y] genG mod_xy] := generators_modular_group p_pr n_gt2 isoG.
+case/modular_group_structure: (genG) => // _ _ [_ _ nil2G] _ _.
+have [oG _ _ _] := genG; have [oy _] := mod_xy.
+rewrite oG -def_n pdiv_pfactor // def_n pfactorK // n_gt1 n_gt2 {}isoG /=.
+case: (ltngtP p 2) => [|p_gt2|p2]; first by rewrite ltnNge prime_gt1.
+ rewrite !(isog_sym G) !isogEcard card_2dihedral ?card_quaternion //= oG.
+ rewrite leq_exp2r // leqNgt p_gt2 !andbF; case: and3P=> // [[n_gt3 _]].
+ by rewrite card_semidihedral // leq_exp2r // leqNgt p_gt2.
+rewrite p2 in genG oy n_gt23; rewrite n_gt23.
+have: nil_class G <> n.-1.
+ by apply/eqP; rewrite neq_ltn -ltnS nil2G def_n n_gt23.
+case: ifP => [isoG | _]; first by case/dihedral2_structure: genG => // _ [].
+case: ifP => [isoG | _]; first by case/quaternion_structure: genG => // _ [].
+by case: ifP => // isoG; case/semidihedral_structure: genG => // _ [].
+Qed.
+
+End ExtremalClass.
+
+Theorem extremal2_structure (gT : finGroupType) (G : {group gT}) n x y :
+ let cG := extremal_class G in
+ let m := (2 ^ n)%N in let q := (2 ^ n.-1)%N in let r := (2 ^ n.-2)%N in
+ let X := <[x]> in let yG := y ^: G in let xyG := (x * y) ^: G in
+ let My := <<yG>> in let Mxy := <<xyG>> in
+ extremal_generators G 2 n (x, y) ->
+ extremal2 G -> (cG == SemiDihedral) ==> (#[y] == 2) ->
+ [/\ [/\ (if cG == Quaternion then pprod X <[y]> else X ><| <[y]>) = G,
+ if cG == SemiDihedral then #[x * y] = 4 else
+ {in G :\: X, forall z, #[z] = (if cG == Dihedral then 2 else 4)},
+ if cG != Quaternion then True else
+ {in G, forall z, #[z] = 2 -> z = x ^+ r}
+ & {in X & G :\: X, forall t z,
+ t ^ z = (if cG == SemiDihedral then t ^+ r.-1 else t^-1)}],
+ [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r
+ & nil_class G = n.-1],
+ [/\ if n > 2 then 'Z(G) = <[x ^+ r]> /\ #|'Z(G)| = 2 else 2.-abelem G,
+ 'Ohm_1(G) = (if cG == Quaternion then <[x ^+ r]> else
+ if cG == SemiDihedral then My else G),
+ 'Ohm_2(G) = G
+ & forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>],
+ [/\ yG :|: xyG = G :\: X, [disjoint yG & xyG]
+ & forall H : {group gT}, maximal H G = (gval H \in pred3 X My Mxy)]
+ & if n <= (cG == Quaternion) + 2 then True else
+ [/\ forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X,
+ if cG == Quaternion then My \isog 'Q_q else My \isog 'D_q,
+ extremal_class My = (if cG == Quaternion then cG else Dihedral),
+ if cG == Dihedral then Mxy \isog 'D_q else Mxy \isog 'Q_q
+ & extremal_class Mxy = (if cG == Dihedral then cG else Quaternion)]].
+Proof.
+move=> cG m q r X yG xyG My Mxy genG; have [oG _ _ _] := genG.
+have logG: logn (pdiv #|G|) #|G| = n by rewrite oG pfactorKpdiv.
+rewrite /extremal2 -/cG; do [rewrite {1}/extremal_class /= {}logG] in cG *.
+case: ifP => [isoG | _] in cG * => [_ _ /=|].
+ case/andP: isoG => n_gt1 isoG.
+ have:= dihedral2_structure n_gt1 genG isoG; rewrite -/X -/q -/r -/yG -/xyG.
+ case=> [[defG oX' invXX'] nilG [defOhm defMho] maxG defZ].
+ rewrite eqn_leq n_gt1 andbT add0n in defZ *; split=> //.
+ split=> //; first by case: leqP defZ => // _ [].
+ by apply/eqP; rewrite eqEsubset Ohm_sub -{1}defOhm Ohm_leq.
+ case: leqP defZ => // n_gt2 [_ _ isoMy isoMxy defX].
+ have n1_gt1: n.-1 > 1 by rewrite -(subnKC n_gt2).
+ by split=> //; apply/dihedral_classP; exists n.-1.
+case: ifP => [isoG | _] in cG * => [_ _ /=|].
+ case/andP: isoG => n_gt2 isoG; rewrite n_gt2 add1n.
+ have:= quaternion_structure n_gt2 genG isoG; rewrite -/X -/q -/r -/yG -/xyG.
+ case=> [[defG oX' invXX'] nilG [defZ oZ def2 [-> ->] defMho]].
+ case=> [[-> ->] maxG] isoM; split=> //.
+ case: leqP isoM => // n_gt3 [//|isoMy isoMxy defX].
+ have n1_gt2: n.-1 > 2 by rewrite -(subnKC n_gt3).
+ by split=> //; apply/quaternion_classP; exists n.-1.
+do [case: ifP => [isoG | _]; last by case: ifP] in cG * => /= _; move/eqnP=> oy.
+case/andP: isoG => n_gt3 isoG; rewrite (leqNgt n) (ltnW n_gt3) /=.
+have n1_gt2: n.-1 > 2 by rewrite -(subnKC n_gt3).
+have:= semidihedral_structure n_gt3 genG isoG oy.
+rewrite -/X -/q -/r -/yG -/xyG -/My -/Mxy.
+case=> [[defG oxy invXX'] nilG [defZ oZ [-> ->] defMho] [[defX' tiX'] maxG]].
+case=> isoMy isoMxy defX; do 2!split=> //.
+ by apply/dihedral_classP; exists n.-1; first exact: ltnW.
+by apply/quaternion_classP; exists n.-1.
+Qed.
+
+(* This is Aschbacher (23.4). *)
+Lemma maximal_cycle_extremal gT p (G X : {group gT}) :
+ p.-group G -> ~~ abelian G -> cyclic X -> X \subset G -> #|G : X| = p ->
+ (extremal_class G == ModularGroup) || (p == 2) && extremal2 G.
+Proof.
+move=> pG not_cGG cycX sXG iXG; rewrite /extremal2; set cG := extremal_class G.
+have [|p_pr _ _] := pgroup_pdiv pG.
+ by case: eqP not_cGG => // ->; rewrite abelian1.
+have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1.
+have [n oG] := p_natP pG; have n_gt2: n > 2.
+ apply: contraR not_cGG; rewrite -leqNgt => n_le2.
+ by rewrite (p2group_abelian pG) // oG pfactorK.
+have def_n := subnKC n_gt2; have n_gt1 := ltnW n_gt2; have n_gt0 := ltnW n_gt1.
+pose q := (p ^ n.-1)%N; pose r := (p ^ n.-2)%N.
+have q_gt1: q > 1 by rewrite (ltn_exp2l 0) // -(subnKC n_gt2).
+have r_gt0: r > 0 by rewrite expn_gt0 p_gt0.
+have def_pr: (p * r)%N = q by rewrite /q /r -def_n.
+have oX: #|X| = q by rewrite -(divg_indexS sXG) oG iXG /q -def_n mulKn.
+have ntX: X :!=: 1 by rewrite -cardG_gt1 oX.
+have maxX: maximal X G by rewrite p_index_maximal ?iXG.
+have nsXG: X <| G := p_maximal_normal pG maxX; have [_ nXG] := andP nsXG.
+have cXX: abelian X := cyclic_abelian cycX.
+have scXG: 'C_G(X) = X.
+ apply/eqP; rewrite eqEsubset subsetI sXG -abelianE cXX !andbT.
+ apply: contraR not_cGG; case/subsetPn=> y; case/setIP=> Gy cXy notXy.
+ rewrite -!cycle_subG in Gy notXy; rewrite -(mulg_normal_maximal nsXG _ Gy) //.
+ by rewrite abelianM cycle_abelian cyclic_abelian ?cycle_subG.
+have [x defX] := cyclicP cycX; have pX := pgroupS sXG pG.
+have Xx: x \in X by [rewrite defX cycle_id]; have Gx := subsetP sXG x Xx.
+have [ox p_x]: #[x] = q /\ p.-elt x by rewrite defX in pX oX.
+pose Z := <[x ^+ r]>.
+have defZ: Z = 'Ohm_1(X) by rewrite defX (Ohm_p_cycle _ p_x) ox subn1 pfactorK.
+have oZ: #|Z| = p by rewrite -orderE orderXdiv ox -def_pr ?dvdn_mull ?mulnK.
+have cGZ: Z \subset 'C(G).
+ have nsZG: Z <| G by rewrite defZ (char_normal_trans (Ohm_char 1 _)).
+ move/implyP: (meet_center_nil (pgroup_nil pG) nsZG).
+ rewrite -cardG_gt1 oZ p_gt1 setIA (setIidPl (normal_sub nsZG)).
+ by apply: contraR; move/prime_TIg=> -> //; rewrite oZ.
+have X_Gp y: y \in G -> y ^+ p \in X.
+ move=> Gy; have nXy: y \in 'N(X) := subsetP nXG y Gy.
+ rewrite coset_idr ?groupX // morphX //; apply/eqP.
+ by rewrite -order_dvdn -iXG -card_quotient // order_dvdG ?mem_quotient.
+have [y X'y]: exists2 y, y \in G :\: X &
+ (p == 2) + 3 <= n /\ x ^ y = x ^+ r.+1 \/ p = 2 /\ x * x ^ y \in Z.
+- have [y Gy notXy]: exists2 y, y \in G & y \notin X.
+ by apply/subsetPn; rewrite proper_subn ?(maxgroupp maxX).
+ have nXy: y \in 'N(X) := subsetP nXG y Gy; pose ay := conj_aut X y.
+ have oay: #[ay] = p.
+ apply: nt_prime_order => //.
+ by rewrite -morphX // mker // ker_conj_aut (subsetP cXX) ?X_Gp.
+ rewrite (sameP eqP (kerP _ nXy)) ker_conj_aut.
+ by apply: contra notXy => cXy; rewrite -scXG inE Gy.
+ have [m []]:= cyclic_pgroup_Aut_structure pX cycX ntX.
+ set Ap := 'O_p(_); case=> def_m [m1 _] [m_inj _] _ _ _.
+ have sylAp: p.-Sylow(Aut X) Ap.
+ by rewrite nilpotent_pcore_Hall // abelian_nil // Aut_cyclic_abelian.
+ have Ap1ay: ay \in 'Ohm_1(Ap).
+ rewrite (OhmE _ (pcore_pgroup _ _)) mem_gen // !inE -order_dvdn oay dvdnn.
+ rewrite (mem_normal_Hall sylAp) ?pcore_normal ?Aut_aut //.
+ by rewrite /p_elt oay pnat_id.
+ rewrite {1}oX pfactorK // -{1}def_n /=.
+ have [p2 | odd_p] := even_prime p_pr; last first.
+ rewrite (sameP eqP (prime_oddPn p_pr)) odd_p n_gt2.
+ case=> _ [_ _ _] [_ _ [s [As os m_s defAp1]]].
+ have [j def_s]: exists j, s = ay ^+ j.
+ apply/cycleP; rewrite -cycle_subG subEproper eq_sym eqEcard -!orderE.
+ by rewrite -defAp1 cycle_subG Ap1ay oay os leqnn .
+ exists (y ^+ j); last first.
+ left; rewrite -(norm_conj_autE _ Xx) ?groupX // morphX // -def_s.
+ by rewrite -def_m // m_s expg_znat // oX pfactorK ?eqxx.
+ rewrite -scXG !inE groupX //= andbT -ker_conj_aut !inE morphX // -def_s.
+ rewrite andbC -(inj_in_eq m_inj) ?group1 // m_s m1 oX pfactorK // -/r.
+ rewrite mulrSr -subr_eq0 addrK -val_eqE /= val_Zp_nat //.
+ by rewrite [_ == 0%N]dvdn_Pexp2l // -def_n ltnn.
+ rewrite {1}p2 /= => [[t [At ot m_t]]]; rewrite {1}oX pfactorK // -{1}def_n.
+ rewrite eqSS subn_eq0 => defA; exists y; rewrite ?inE ?notXy //.
+ rewrite p2 -(norm_conj_autE _ Xx) //= -/ay -def_m ?Aut_aut //.
+ case Tay: (ay \in <[t]>).
+ rewrite cycle2g // !inE -order_eq1 oay p2 /= in Tay.
+ by right; rewrite (eqP Tay) m_t expg_zneg // mulgV group1.
+ case: leqP defA => [_ defA|le3n [a [Aa _ _ defA [s [As os m_s m_st defA1]]]]].
+ by rewrite -defA Aut_aut in Tay.
+ have: ay \in [set s; s * t].
+ have: ay \in 'Ohm_1(Aut X) := subsetP (OhmS 1 (pcore_sub _ _)) ay Ap1ay.
+ case/dprodP: (Ohm_dprod 1 defA) => _ <- _ _.
+ rewrite defA1 (@Ohm_p_cycle _ _ 2) /p_elt ot //= expg1 cycle2g //.
+ by rewrite mulUg mul1g inE Tay cycle2g // mulgU mulg1 mulg_set1.
+ case/set2P=> ->; [left | right].
+ by rewrite ?le3n m_s expg_znat // oX pfactorK // -p2.
+ by rewrite m_st expg_znat // oX pfactorK // -p2 -/r -expgS prednK ?cycle_id.
+have [Gy notXy] := setDP X'y; have nXy := subsetP nXG y Gy.
+have defG j: <[x]> <*> <[x ^+ j * y]> = G.
+ rewrite -defX -genM_join.
+ by rewrite (mulg_normal_maximal nsXG) ?cycle_subG ?groupMl ?groupX ?genGid.
+have[i def_yp]: exists i, y ^- p = x ^+ i.
+ by apply/cycleP; rewrite -defX groupV X_Gp.
+have p_i: p %| i.
+ apply: contraR notXy; rewrite -prime_coprime // => co_p_j.
+ have genX: generator X (y ^- p).
+ by rewrite def_yp defX generator_coprime ox coprime_expl.
+ rewrite -scXG (setIidPl _) // centsC ((X :=P: _) genX) cycle_subG groupV.
+ rewrite /= -(defG 0%N) mul1g centY inE -defX (subsetP cXX) ?X_Gp //.
+ by rewrite (subsetP (cycle_abelian y)) ?mem_cycle.
+case=> [[n_gt23 xy] | [p2 Z_xxy]].
+ suffices ->: cG = ModularGroup by []; apply/modular_group_classP.
+ exists p => //; exists n => //; rewrite isogEcard card_modular_group //.
+ rewrite oG leqnn andbT Grp_modular_group // -/q -/r.
+ have{i def_yp p_i} [i def_yp]: exists i, y ^- p = x ^+ i ^+ p.
+ by case/dvdnP: p_i => j def_i; exists j; rewrite -expgM -def_i.
+ have Zyx: [~ y, x] \in Z.
+ by rewrite -groupV invg_comm commgEl xy expgS mulKg cycle_id.
+ have def_yxj j: [~ y, x ^+ j] = [~ y, x] ^+ j.
+ by rewrite commgX /commute ?(centsP cGZ _ Zyx).
+ have Zyxj j: [~ y, x ^+ j] \in Z by rewrite def_yxj groupX.
+ have x_xjy j: x ^ (x ^+ j * y) = x ^+ r.+1.
+ by rewrite conjgM {2}/conjg commuteX //= mulKg.
+ have [cyxi | not_cyxi] := eqVneq ([~ y, x ^+ i] ^+ 'C(p, 2)) 1.
+ apply/existsP; exists (x, x ^+ i * y); rewrite /= !xpair_eqE.
+ rewrite defG x_xjy -order_dvdn ox dvdnn !eqxx andbT /=.
+ rewrite expMg_Rmul /commute ?(centsP cGZ _ (Zyxj _)) ?groupX // cyxi.
+ by rewrite -def_yp -mulgA mulKg.
+ have [p2 | odd_p] := even_prime p_pr; last first.
+ by rewrite -order_dvdn bin2odd ?dvdn_mulr // -oZ order_dvdG in not_cyxi.
+ have def_yxi: [~ y, x ^+ i] = x ^+ r.
+ have:= Zyxj i; rewrite /Z cycle_traject orderE oZ p2 !inE mulg1.
+ by case/pred2P=> // cyxi; rewrite cyxi p2 eqxx in not_cyxi.
+ apply/existsP; exists (x, x ^+ (i + r %/ 2) * y); rewrite /= !xpair_eqE.
+ rewrite defG x_xjy -order_dvdn ox dvdnn !eqxx andbT /=.
+ rewrite expMg_Rmul /commute ?(centsP cGZ _ (Zyxj _)) ?groupX // def_yxj.
+ rewrite -expgM mulnDl addnC !expgD (expgM x i) -def_yp mulgKV.
+ rewrite -def_yxj def_yxi p2 mulgA -expgD in n_gt23 *.
+ rewrite -expg_mod_order ox /q /r p2 -(subnKC n_gt23) mulnC !expnS mulKn //.
+ rewrite addnn -mul2n modnn mul1g -order_dvdn dvdn_mulr //.
+ by rewrite -p2 -oZ order_dvdG.
+have{i def_yp p_i} Zy2: y ^+ 2 \in Z.
+ rewrite defZ (OhmE _ pX) -groupV -p2 def_yp mem_gen // !inE groupX //= p2.
+ rewrite expgS -{2}def_yp -(mulKg y y) -conjgE -conjXg -conjVg def_yp conjXg.
+ rewrite -expgMn //; last by apply: (centsP cXX); rewrite ?memJ_norm.
+ by rewrite -order_dvdn (dvdn_trans (order_dvdG Z_xxy)) ?oZ.
+rewrite !cycle_traject !orderE oZ p2 !inE !mulg1 /= in Z_xxy Zy2 *.
+rewrite -eq_invg_mul eq_sym -[r]prednK // expgS (inj_eq (mulgI _)) in Z_xxy.
+case/pred2P: Z_xxy => xy; last first.
+ suffices ->: cG = SemiDihedral by []; apply/semidihedral_classP.
+ have n_gt3: n > 3.
+ case: ltngtP notXy => // [|n3]; first by rewrite ltnNge n_gt2.
+ rewrite -scXG inE Gy defX cent_cycle; case/cent1P; red.
+ by rewrite (conjgC x) xy /r p2 n3.
+ exists n => //; rewrite isogEcard card_semidihedral // oG p2 leqnn andbT.
+ rewrite Grp_semidihedral //; apply/existsP=> /=.
+ case/pred2P: Zy2 => y2; [exists (x, y) | exists (x, x * y)].
+ by rewrite /= -{1}[y]mul1g (defG 0%N) y2 xy -p2 -/q -ox expg_order.
+ rewrite /= (defG 1%N) conjgM {2}/conjg mulKg -p2 -/q -ox expg_order -xy.
+ rewrite !xpair_eqE !eqxx /= andbT p2 expgS {2}(conjgC x) xy mulgA -(mulgA x).
+ rewrite [y * y]y2 -expgS -expgD addSnnS prednK // addnn -mul2n -p2 def_pr.
+ by rewrite -ox expg_order.
+case/pred2P: Zy2 => y2.
+ suffices ->: cG = Dihedral by []; apply/dihedral_classP.
+ exists n => //; rewrite isogEcard card_2dihedral // oG p2 leqnn andbT.
+ rewrite Grp_2dihedral //; apply/existsP; exists (x, y) => /=.
+ by rewrite /= -{1}[y]mul1g (defG 0%N) y2 xy -p2 -/q -ox expg_order.
+suffices ->: cG = Quaternion by []; apply/quaternion_classP.
+exists n => //; rewrite isogEcard card_quaternion // oG p2 leqnn andbT.
+rewrite Grp_quaternion //; apply/existsP; exists (x, y) => /=.
+by rewrite /= -{1}[y]mul1g (defG 0%N) y2 xy -p2 -/q -ox expg_order.
+Qed.
+
+(* This is Aschbacher (23.5) *)
+Lemma cyclic_SCN gT p (G U : {group gT}) :
+ p.-group G -> U \in 'SCN(G) -> ~~ abelian G -> cyclic U ->
+ [/\ p = 2, #|G : U| = 2 & extremal2 G]
+\/ exists M : {group gT},
+ [/\ M :=: 'C_G('Mho^1(U)), #|M : U| = p, extremal_class M = ModularGroup,
+ 'Ohm_1(M)%G \in 'E_p^2(G) & 'Ohm_1(M) \char G].
+Proof.
+move=> pG /SCN_P[nsUG scUG] not_cGG cycU; have [sUG nUG] := andP nsUG.
+have [cUU pU] := (cyclic_abelian cycU, pgroupS sUG pG).
+have ltUG: ~~ (G \subset U).
+ by apply: contra not_cGG => sGU; exact: abelianS cUU.
+have ntU: U :!=: 1.
+ by apply: contra ltUG; move/eqP=> U1; rewrite -(setIidPl (cents1 G)) -U1 scUG.
+have [p_pr _ [n oU]] := pgroup_pdiv pU ntU.
+have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1.
+have [u defU] := cyclicP cycU; have Uu: u \in U by rewrite defU cycle_id.
+have Gu := subsetP sUG u Uu; have p_u := mem_p_elt pG Gu.
+have defU1: 'Mho^1(U) = <[u ^+ p]> by rewrite defU (Mho_p_cycle _ p_u).
+have modM1 (M : {group gT}):
+ [/\ U \subset M, #|M : U| = p & extremal_class M = ModularGroup] ->
+ M :=: 'C_M('Mho^1(U)) /\ 'Ohm_1(M)%G \in 'E_p^2(M).
+- case=> sUM iUM /modular_group_classP[q q_pr {n oU}[n n_gt23 isoM]].
+ have n_gt2: n > 2 by exact: leq_trans (leq_addl _ _) n_gt23.
+ have def_n: n = (n - 3).+3 by rewrite -{1}(subnKC n_gt2).
+ have oM: #|M| = (q ^ n)%N by rewrite (card_isog isoM) card_modular_group.
+ have pM: q.-group M by rewrite /pgroup oM pnat_exp pnat_id.
+ have def_q: q = p; last rewrite {q q_pr}def_q in oM pM isoM n_gt23.
+ by apply/eqP; rewrite eq_sym [p == q](pgroupP pM) // -iUM dvdn_indexg.
+ have [[x y] genM modM] := generators_modular_group p_pr n_gt2 isoM.
+ case/modular_group_structure: genM => // _ [defZ _ oZ] _ defMho.
+ have ->: 'Mho^1(U) = 'Z(M).
+ apply/eqP; rewrite eqEcard oZ defZ -(defMho 1%N) ?MhoS //= defU1 -orderE.
+ suff ou: #[u] = (p * p ^ n.-2)%N by rewrite orderXdiv ou ?dvdn_mulr ?mulKn.
+ by rewrite orderE -defU -(divg_indexS sUM) iUM oM def_n mulKn.
+ case: eqP => [[p2 n3] | _ defOhm]; first by rewrite p2 n3 in n_gt23.
+ have{defOhm} [|defM1 oM1] := defOhm 1%N; first by rewrite def_n.
+ split; rewrite ?(setIidPl _) //; first by rewrite centsC subsetIr.
+ rewrite inE oM1 pfactorK // andbT inE Ohm_sub abelem_Ohm1 //.
+ exact: (card_p2group_abelian p_pr oM1).
+have ou: #[u] = (p ^ n.+1)%N by rewrite defU in oU.
+pose Gs := G / U; have pGs: p.-group Gs by rewrite quotient_pgroup.
+have ntGs: Gs != 1 by rewrite -subG1 quotient_sub1.
+have [_ _ [[|k] oGs]] := pgroup_pdiv pGs ntGs.
+ have iUG: #|G : U| = p by rewrite -card_quotient ?oGs.
+ case: (predU1P (maximal_cycle_extremal _ _ _ _ iUG)) => // [modG | ext2G].
+ by right; exists G; case: (modM1 G) => // <- ->; rewrite Ohm_char.
+ by left; case: eqP ext2G => // <-.
+pose M := 'C_G('Mho^1(U)); right; exists [group of M].
+have sMG: M \subset G by exact: subsetIl.
+have [pM nUM] := (pgroupS sMG pG, subset_trans sMG nUG).
+have sUM: U \subset M by rewrite subsetI sUG sub_abelian_cent ?Mho_sub.
+pose A := Aut U; have cAA: abelian A by rewrite Aut_cyclic_abelian.
+have sylAp: p.-Sylow(A) 'O_p(A) by rewrite nilpotent_pcore_Hall ?abelian_nil.
+have [f [injf sfGsA fG]]: exists f : {morphism Gs >-> {perm gT}},
+ [/\ 'injm f, f @* Gs \subset A & {in G, forall y, f (coset U y) u = u ^ y}].
+- have [] := first_isom_loc [morphism of conj_aut U] nUG.
+ rewrite ker_conj_aut scUG /= -/Gs => f injf im_f.
+ exists f; rewrite im_f ?Aut_conj_aut //.
+ split=> // y Gy; have nUy := subsetP nUG y Gy.
+ suffices ->: f (coset U y) = conj_aut U y by rewrite norm_conj_autE.
+ by apply: set1_inj; rewrite -!morphim_set1 ?mem_quotient // im_f ?sub1set.
+have cGsGs: abelian Gs by rewrite -(injm_abelian injf) // (abelianS sfGsA).
+have p_fGs: p.-group (f @* Gs) by rewrite morphim_pgroup.
+have sfGsAp: f @* Gs \subset 'O_p(A) by rewrite (sub_Hall_pcore sylAp).
+have [a [fGa oa au n_gt01 cycGs]]: exists a,
+ [/\ a \in f @* Gs, #[a] = p, a u = u ^+ (p ^ n).+1, (p == 2) + 1 <= n
+ & cyclic Gs \/ p = 2 /\ (exists2 c, c \in f @* Gs & c u = u^-1)].
+- have [m [[def_m _ _ _ _] _]] := cyclic_pgroup_Aut_structure pU cycU ntU.
+ have ->: logn p #|U| = n.+1 by rewrite oU pfactorK.
+ rewrite /= -/A; case: posnP => [_ defA | n_gt0 [c [Ac oc m_c defA]]].
+ have:= cardSg sfGsAp; rewrite (card_Hall sylAp) /= -/A defA card_injm //.
+ by rewrite oGs (part_p'nat (pcore_pgroup _ _)) pfactor_dvdn // logn1.
+ have [p2 | odd_p] := even_prime p_pr; last first.
+ case: eqP => [-> // | _] in odd_p *; rewrite odd_p in defA.
+ have [[cycA _] _ [a [Aa oa m_a defA1]]] := defA.
+ exists a; rewrite -def_m // oa m_a expg_znat //.
+ split=> //; last by left; rewrite -(injm_cyclic injf) ?(cyclicS sfGsA).
+ have: f @* Gs != 1 by rewrite morphim_injm_eq1.
+ rewrite -cycle_subG; apply: contraR => not_sfGs_a.
+ by rewrite -(setIidPl sfGsAp) TI_Ohm1 // defA1 setIC prime_TIg -?orderE ?oa.
+ do [rewrite {1}p2 /= eqn_leq n_gt0; case: leqP => /= [_ | n_gt1]] in defA.
+ have:= cardSg sfGsAp; rewrite (card_Hall sylAp) /= -/A defA -orderE oc p2.
+ by rewrite card_injm // oGs p2 pfactor_dvdn // p_part.
+ have{defA} [s [As os _ defA [a [Aa oa m_a _ defA1]]]] := defA; exists a.
+ have fGs_a: a \in f @* Gs.
+ suffices: f @* Gs :&: <[s]> != 1.
+ apply: contraR => not_fGs_a; rewrite TI_Ohm1 // defA1 setIC.
+ by rewrite prime_TIg -?orderE ?oa // cycle_subG.
+ have: (f @* Gs) * <[s]> \subset A by rewrite mulG_subG cycle_subG sfGsA.
+ move/subset_leq_card; apply: contraL; move/eqP; move/TI_cardMg->.
+ rewrite -(dprod_card defA) -ltnNge mulnC -!orderE ltn_pmul2r // oc.
+ by rewrite card_injm // oGs p2 (ltn_exp2l 1%N).
+ rewrite -def_m // oa m_a expg_znat // p2; split=> //.
+ rewrite abelian_rank1_cyclic // (rank_pgroup pGs) //.
+ rewrite -(injm_p_rank injf) // p_rank_abelian 1?morphim_abelian //= p2 -/Gs.
+ case: leqP => [|fGs1_gt1]; [by left | right].
+ split=> //; exists c; last by rewrite -def_m // m_c expg_zneg.
+ have{defA1} defA1: <[a]> \x <[c]> = 'Ohm_1(Aut U).
+ by rewrite -(Ohm_dprod 1 defA) defA1 (@Ohm_p_cycle 1 _ 2) /p_elt oc.
+ have def_fGs1: 'Ohm_1(f @* Gs) = 'Ohm_1(A).
+ apply/eqP; rewrite eqEcard OhmS // -(dprod_card defA1) -!orderE oa oc.
+ by rewrite dvdn_leq ?(@pfactor_dvdn 2 2) ?cardG_gt0.
+ rewrite (subsetP (Ohm_sub 1 _)) // def_fGs1 -cycle_subG.
+ by case/dprodP: defA1 => _ <- _ _; rewrite mulG_subr.
+have n_gt0: n > 0 := leq_trans (leq_addl _ _) n_gt01.
+have [ys Gys _ def_a] := morphimP fGa.
+have oys: #[ys] = p by rewrite -(order_injm injf) // -def_a oa.
+have defMs: M / U = <[ys]>.
+ apply/eqP; rewrite eq_sym eqEcard -orderE oys cycle_subG; apply/andP; split.
+ have [y nUy Gy /= def_ys] := morphimP Gys.
+ rewrite def_ys mem_quotient //= inE Gy defU1 cent_cycle cent1C.
+ rewrite (sameP cent1P commgP) commgEl conjXg -fG //= -def_ys -def_a au.
+ by rewrite -expgM mulSn expgD mulKg -expnSr -ou expg_order.
+ rewrite card_quotient // -(setIidPr sUM) -scUG setIA (setIidPl sMG).
+ rewrite defU cent_cycle index_cent1 -(card_imset _ (mulgI u^-1)) -imset_comp.
+ have <-: #|'Ohm_1(U)| = p.
+ rewrite defU (Ohm_p_cycle 1 p_u) -orderE (orderXexp _ ou) ou pfactorK //.
+ by rewrite subKn.
+ rewrite (OhmE 1 pU) subset_leq_card ?sub_gen //.
+ apply/subsetP=> _ /imsetP[z /setIP[/(subsetP nUG) nUz cU1z] ->].
+ have Uv' := groupVr Uu; have Uuz: u ^ z \in U by rewrite memJ_norm.
+ rewrite !inE groupM // expgMn /commute 1?(centsP cUU u^-1) //= expgVn -conjXg.
+ by rewrite (sameP commgP cent1P) cent1C -cent_cycle -defU1.
+have iUM: #|M : U| = p by rewrite -card_quotient ?defMs.
+have not_cMM: ~~ abelian M.
+ apply: contraL p_pr => cMM; rewrite -iUM -indexgI /= -/M.
+ by rewrite (setIidPl _) ?indexgg // -scUG subsetI sMG sub_abelian_cent.
+have modM: extremal_class M = ModularGroup.
+ have sU1Z: 'Mho^1(U) \subset 'Z(M).
+ by rewrite subsetI (subset_trans (Mho_sub 1 U)) // centsC subsetIr.
+ case: (predU1P (maximal_cycle_extremal _ _ _ _ iUM)) => //=; rewrite -/M.
+ case/andP; move/eqP=> p2 ext2M; rewrite p2 add1n in n_gt01.
+ suffices{sU1Z}: #|'Z(M)| = 2.
+ move/eqP; rewrite eqn_leq leqNgt (leq_trans _ (subset_leq_card sU1Z)) //.
+ by rewrite defU1 -orderE (orderXexp 1 ou) subn1 p2 (ltn_exp2l 1).
+ move: ext2M; rewrite /extremal2 !inE orbC -orbA; case/or3P; move/eqP.
+ - case/semidihedral_classP=> m m_gt3 isoM.
+ have [[x z] genM [oz _]] := generators_semidihedral m_gt3 isoM.
+ by case/semidihedral_structure: genM => // _ _ [].
+ - case/quaternion_classP=> m m_gt2 isoM.
+ have [[x z] genM _] := generators_quaternion m_gt2 isoM.
+ by case/quaternion_structure: genM => // _ _ [].
+ case/dihedral_classP=> m m_gt1 isoM.
+ have [[x z] genM _] := generators_2dihedral m_gt1 isoM.
+ case/dihedral2_structure: genM not_cMM => // _ _ _ _.
+ by case: (m == 2) => [|[]//]; move/abelem_abelian->.
+split=> //.
+ have [//|_] := modM1 [group of M]; rewrite !inE -andbA /=.
+ by case/andP; move/subset_trans->.
+have{cycGs} [cycGs | [p2 [c fGs_c u_c]]] := cycGs.
+ suffices ->: 'Ohm_1(M) = 'Ohm_1(G) by exact: Ohm_char.
+ suffices sG1M: 'Ohm_1(G) \subset M.
+ by apply/eqP; rewrite eqEsubset -{2}(Ohm_id 1 G) !OhmS.
+ rewrite -(quotientSGK _ sUM) ?(subset_trans (Ohm_sub _ G)) //= defMs.
+ suffices ->: <[ys]> = 'Ohm_1(Gs) by rewrite morphim_Ohm.
+ apply/eqP; rewrite eqEcard -orderE cycle_subG /= {1}(OhmE 1 pGs) /=.
+ rewrite mem_gen ?inE ?Gys -?order_dvdn oys //=.
+ rewrite -(part_pnat_id (pgroupS (Ohm_sub _ _) pGs)) p_part (leq_exp2l _ 1) //.
+ by rewrite -p_rank_abelian -?rank_pgroup -?abelian_rank1_cyclic.
+suffices charU1: 'Mho^1(U) \char G^`(1).
+ rewrite (char_trans (Ohm_char _ _)) // subcent_char ?char_refl //.
+ exact: char_trans (der_char 1 G).
+suffices sUiG': 'Mho^1(U) \subset G^`(1).
+ have cycG': cyclic G^`(1) by rewrite (cyclicS _ cycU) // der1_min.
+ by case/cyclicP: cycG' sUiG' => zs ->; exact: cycle_subgroup_char.
+rewrite defU1 cycle_subG p2 -groupV invMg -{2}u_c.
+by case/morphimP: fGs_c => _ _ /morphimP[z _ Gz ->] ->; rewrite fG ?mem_commg.
+Qed.
+
+(* This is Aschbacher, exercise (8.4) *)
+Lemma normal_rank1_structure gT p (G : {group gT}) :
+ p.-group G -> (forall X : {group gT}, X <| G -> abelian X -> cyclic X) ->
+ cyclic G \/ [&& p == 2, extremal2 G & (#|G| >= 16) || (G \isog 'Q_8)].
+Proof.
+move=> pG dn_G_1.
+have [cGG | not_cGG] := boolP (abelian G); first by left; rewrite dn_G_1.
+have [X maxX]: {X | [max X | X <| G & abelian X]}.
+ by apply: ex_maxgroup; exists 1%G; rewrite normal1 abelian1.
+have cycX: cyclic X by rewrite dn_G_1; case/andP: (maxgroupp maxX).
+have scX: X \in 'SCN(G) := max_SCN pG maxX.
+have [[p2 _ cG] | [M [_ _ _]]] := cyclic_SCN pG scX not_cGG cycX; last first.
+ rewrite 2!inE -andbA; case/and3P=> sEG abelE dimE_2 charE.
+ have:= dn_G_1 _ (char_normal charE) (abelem_abelian abelE).
+ by rewrite (abelem_cyclic abelE) (eqP dimE_2).
+have [n oG] := p_natP pG; right; rewrite p2 cG /= in oG *.
+rewrite oG (@leq_exp2l 2 4) //.
+rewrite /extremal2 /extremal_class oG pfactorKpdiv // in cG.
+case: andP cG => [[n_gt1 isoG] _ | _]; last first.
+ by rewrite leq_eqVlt; case: (3 < n); case: eqP => //= <-; do 2?case: ifP.
+have [[x y] genG _] := generators_2dihedral n_gt1 isoG.
+have [_ _ _ [_ _ maxG]] := dihedral2_structure n_gt1 genG isoG.
+rewrite 2!ltn_neqAle n_gt1 !(eq_sym _ n).
+case: eqP => [_ abelG| _]; first by rewrite (abelem_abelian abelG) in not_cGG.
+case: eqP => // -> [_ _ isoY _ _]; set Y := <<_>> in isoY.
+have nxYG: Y <| G by rewrite (p_maximal_normal pG) // maxG !inE eqxx orbT.
+have [// | [u v] genY _] := generators_2dihedral _ isoY.
+case/dihedral2_structure: (genY) => //= _ _ _ _ abelY.
+have:= dn_G_1 _ nxYG (abelem_abelian abelY).
+by rewrite (abelem_cyclic abelY); case: genY => ->.
+Qed.
+
+(* Replacement for Section 4 proof. *)
+Lemma odd_pgroup_rank1_cyclic gT p (G : {group gT}) :
+ p.-group G -> odd #|G| -> cyclic G = ('r_p(G) <= 1).
+Proof.
+move=> pG oddG; rewrite -rank_pgroup //; apply/idP/idP=> [cycG | dimG1].
+ by rewrite -abelian_rank1_cyclic ?cyclic_abelian.
+have [X nsXG cXX|//|] := normal_rank1_structure pG; last first.
+ by rewrite (negPf (odd_not_extremal2 oddG)) andbF.
+by rewrite abelian_rank1_cyclic // (leq_trans (rankS (normal_sub nsXG))).
+Qed.
+
+(* This is the second part of Aschbacher, exercise (8.4). *)
+Lemma prime_Ohm1P gT p (G : {group gT}) :
+ p.-group G -> G :!=: 1 ->
+ reflect (#|'Ohm_1(G)| = p)
+ (cyclic G || (p == 2) && (extremal_class G == Quaternion)).
+Proof.
+move=> pG ntG; have [p_pr p_dvd_G _] := pgroup_pdiv pG ntG.
+apply: (iffP idP) => [|oG1p].
+ case/orP=> [cycG|]; first exact: Ohm1_cyclic_pgroup_prime.
+ case/andP=> /eqP p2 /eqP/quaternion_classP[n n_gt2 isoG].
+ rewrite p2; have [[x y]] := generators_quaternion n_gt2 isoG.
+ by case/quaternion_structure=> // _ _ [<- oZ _ [->]].
+have [X nsXG cXX|-> //|]:= normal_rank1_structure pG.
+ have [sXG _] := andP nsXG; have pX := pgroupS sXG pG.
+ rewrite abelian_rank1_cyclic // (rank_pgroup pX) p_rank_abelian //.
+ rewrite -{2}(pfactorK 1 p_pr) -{3}oG1p dvdn_leq_log ?cardG_gt0 //.
+ by rewrite cardSg ?OhmS.
+case/and3P=> /eqP p2; rewrite p2 (orbC (cyclic G)) /extremal2.
+case cG: (extremal_class G) => //; case: notF.
+ case/dihedral_classP: cG => n n_gt1 isoG.
+ have [[x y] genG _] := generators_2dihedral n_gt1 isoG.
+ have [oG _ _ _] := genG; case/dihedral2_structure: genG => // _ _ [defG1 _] _.
+ by case/idPn: n_gt1; rewrite -(@ltn_exp2l 2) // -oG -defG1 oG1p p2.
+case/semidihedral_classP: cG => n n_gt3 isoG.
+have [[x y] genG [oy _]] := generators_semidihedral n_gt3 isoG.
+case/semidihedral_structure: genG => // _ _ [_ _ [defG1 _] _] _ [isoG1 _ _].
+case/idPn: (n_gt3); rewrite -(ltn_predK n_gt3) ltnS -leqNgt -(@leq_exp2l 2) //.
+rewrite -card_2dihedral //; last by rewrite -(subnKC n_gt3).
+by rewrite -(card_isog isoG1) /= -defG1 oG1p p2.
+Qed.
+
+(* This is Aschbacher (23.9) *)
+Theorem symplectic_type_group_structure gT p (G : {group gT}) :
+ p.-group G -> (forall X : {group gT}, X \char G -> abelian X -> cyclic X) ->
+ exists2 E : {group gT}, E :=: 1 \/ extraspecial E
+ & exists R : {group gT},
+ [/\ cyclic R \/ [/\ p = 2, extremal2 R & #|R| >= 16],
+ E \* R = G
+ & E :&: R = 'Z(E)].
+Proof.
+move=> pG sympG; have [H [charH]] := Thompson_critical pG.
+have sHG := char_sub charH; have pH := pgroupS sHG pG.
+set U := 'Z(H) => sPhiH_U sHG_U defU; set Z := 'Ohm_1(U).
+have sZU: Z \subset U by rewrite Ohm_sub.
+have charU: U \char G := char_trans (center_char H) charH.
+have cUU: abelian U := center_abelian H.
+have cycU: cyclic U by exact: sympG.
+have pU: p.-group U := pgroupS (char_sub charU) pG.
+have cHU: U \subset 'C(H) by rewrite subsetIr.
+have cHsHs: abelian (H / Z).
+ rewrite sub_der1_abelian //= (OhmE _ pU) genS //= -/U.
+ apply/subsetP=> _ /imset2P[h k Hh Hk ->].
+ have Uhk: [~ h, k] \in U by rewrite (subsetP sHG_U) ?mem_commg ?(subsetP sHG).
+ rewrite inE Uhk inE -commXg; last by red; rewrite -(centsP cHU).
+ apply/commgP; red; rewrite (centsP cHU) // (subsetP sPhiH_U) //.
+ by rewrite (Phi_joing pH) mem_gen // inE orbC (Mho_p_elt 1) ?(mem_p_elt pH).
+have nsZH: Z <| H by rewrite sub_center_normal.
+have [K /=] := inv_quotientS nsZH (Ohm_sub 1 (H / Z)); fold Z => defKs sZK sKH.
+have nsZK: Z <| K := normalS sZK sKH nsZH; have [_ nZK] := andP nsZK.
+have abelKs: p.-abelem (K / Z) by rewrite -defKs Ohm1_abelem ?quotient_pgroup.
+have charK: K \char G.
+ have charZ: Z \char H := char_trans (Ohm_char _ _) (center_char H).
+ rewrite (char_trans _ charH) // (char_from_quotient nsZK) //.
+ by rewrite -defKs Ohm_char.
+have cycZK: cyclic 'Z(K).
+ by rewrite sympG ?center_abelian ?(char_trans (center_char _)).
+have [cKK | not_cKK] := orP (orbN (abelian K)).
+ have defH: U = H.
+ apply: center_idP; apply: cyclic_factor_abelian (Ohm_sub 1 _) _.
+ rewrite /= -/Z abelian_rank1_cyclic //.
+ have cKsKs: abelian (K / Z) by rewrite -defKs (abelianS (Ohm_sub 1 _)).
+ have cycK: cyclic K by rewrite -(center_idP cKK).
+ by rewrite -rank_Ohm1 defKs -abelian_rank1_cyclic ?quotient_cyclic.
+ have scH: H \in 'SCN(G) by apply/SCN_P; rewrite defU char_normal.
+ have [cGG | not_cGG] := orP (orbN (abelian G)).
+ exists 1%G; [by left | exists G; rewrite cprod1g (setIidPl _) ?sub1G //].
+ by split; first left; rewrite ?center1 // sympG ?char_refl.
+ have cycH: cyclic H by rewrite -{}defH.
+ have [[p2 _ cG2]|[M [_ _ _]]] := cyclic_SCN pG scH not_cGG cycH; last first.
+ do 2![case/setIdP] => _ abelE dimE_2 charE.
+ have:= sympG _ charE (abelem_abelian abelE).
+ by rewrite (abelem_cyclic abelE) (eqP dimE_2).
+ have [n oG] := p_natP pG; rewrite p2 in oG.
+ have [n_gt3 | n_le3] := ltnP 3 n.
+ exists 1%G; [by left | exists G; rewrite cprod1g (setIidPl _) ?sub1G //].
+ by split; first right; rewrite ?center1 // oG (@leq_exp2l 2 4).
+ have esG: extraspecial G.
+ by apply: (p3group_extraspecial pG); rewrite // p2 oG pfactorK.
+ exists G; [by right | exists ('Z(G))%G; rewrite cprod_center_id setIA setIid].
+ by split=> //; left; rewrite prime_cyclic; case: esG.
+have ntK: K :!=: 1 by apply: contra not_cKK; move/eqP->; exact: abelian1.
+have [p_pr _ _] := pgroup_pdiv (pgroupS sKH pH) ntK.
+have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1.
+have oZ: #|Z| = p.
+ apply: Ohm1_cyclic_pgroup_prime => //=; apply: contra ntK; move/eqP.
+ by move/(trivg_center_pgroup pH)=> GH; rewrite -subG1 -GH.
+have sZ_ZK: Z \subset 'Z(K).
+ by rewrite subsetI sZK (subset_trans (Ohm_sub _ _ )) // subIset ?centS ?orbT.
+have sZsKs: 'Z(K) / Z \subset K / Z by rewrite quotientS ?center_sub.
+have [Es /= splitKs] := abelem_split_dprod abelKs sZsKs.
+have [_ /= defEsZs cEsZs tiEsZs] := dprodP splitKs.
+have sEsKs: Es \subset K / Z by rewrite -defEsZs mulG_subr.
+have [E defEs sZE sEK] := inv_quotientS nsZK sEsKs; rewrite /= -/Z in defEs sZE.
+have [nZE nZ_ZK] := (subset_trans sEK nZK, subset_trans (center_sub K) nZK).
+have defK: 'Z(K) * E = K.
+ rewrite -(mulSGid sZ_ZK) -mulgA -quotientK ?mul_subG ?quotientMl //.
+ by rewrite -defEs defEsZs quotientGK.
+have defZE: 'Z(E) = Z.
+ have cEZK: 'Z(K) \subset 'C(E) by rewrite subIset // orbC centS.
+ have cE_Z: E \subset 'C(Z) by rewrite centsC (subset_trans sZ_ZK).
+ apply/eqP; rewrite eqEsubset andbC subsetI sZE centsC cE_Z /=.
+ rewrite -quotient_sub1 ?subIset ?nZE //= -/Z -tiEsZs subsetI defEs.
+ rewrite !quotientS ?center_sub //= subsetI subIset ?sEK //=.
+ by rewrite -defK centM setSI // centsC.
+have sEH := subset_trans sEK sKH; have pE := pgroupS sEH pH.
+have esE: extraspecial E.
+ split; last by rewrite defZE oZ.
+ have sPhiZ: 'Phi(E) \subset Z.
+ rewrite -quotient_sub1 ?(subset_trans (Phi_sub _)) ?(quotient_Phi pE) //.
+ rewrite subG1 (trivg_Phi (quotient_pgroup _ pE)) /= -defEs.
+ by rewrite (abelemS sEsKs) //= -defKs Ohm1_abelem ?quotient_pgroup.
+ have sE'Phi: E^`(1) \subset 'Phi(E) by rewrite (Phi_joing pE) joing_subl.
+ have ntE': E^`(1) != 1.
+ rewrite (sameP eqP commG1P) -abelianE; apply: contra not_cKK => cEE.
+ by rewrite -defK mulGSid ?center_abelian // -(center_idP cEE) defZE.
+ have defE': E^`(1) = Z.
+ apply/eqP; rewrite eqEcard (subset_trans sE'Phi) //= oZ.
+ have [_ _ [n ->]] := pgroup_pdiv (pgroupS (der_sub _ _) pE) ntE'.
+ by rewrite (leq_exp2l 1) ?prime_gt1.
+ by split; rewrite defZE //; apply/eqP; rewrite eqEsubset sPhiZ -defE'.
+have [spE _] := esE; have [defPhiE defE'] := spE.
+have{defE'} sEG_E': [~: E, G] \subset E^`(1).
+ rewrite defE' defZE /Z (OhmE _ pU) commGC genS //.
+ apply/subsetP=> _ /imset2P[g e Gg Ee ->].
+ have He: e \in H by rewrite (subsetP sKH) ?(subsetP sEK).
+ have Uge: [~ g, e] \in U by rewrite (subsetP sHG_U) ?mem_commg.
+ rewrite inE Uge inE -commgX; last by red; rewrite -(centsP cHU).
+ have sZ_ZG: Z \subset 'Z(G).
+ have charZ: Z \char G := char_trans (Ohm_char _ _) charU.
+ move/implyP: (meet_center_nil (pgroup_nil pG) (char_normal charZ)).
+ rewrite -cardG_gt1 oZ prime_gt1 //=; apply: contraR => not_sZ_ZG.
+ by rewrite prime_TIg ?oZ.
+ have: e ^+ p \in 'Z(G).
+ rewrite (subsetP sZ_ZG) // -defZE -defPhiE (Phi_joing pE) mem_gen //.
+ by rewrite inE orbC (Mho_p_elt 1) ?(mem_p_elt pE).
+ by case/setIP=> _ /centP cGep; apply/commgP; red; rewrite cGep.
+have sEG: E \subset G := subset_trans sEK (char_sub charK).
+set R := 'C_G(E).
+have{sEG_E'} defG: E \* R = G by exact: (critical_extraspecial pG).
+have [_ defER cRE] := cprodP defG.
+have defH: E \* 'C_H(E) = H by rewrite -(setIidPr sHG) setIAC (cprod_modl defG).
+have{defH} [_ defH cRH_E] := cprodP defH.
+have cRH_RH: abelian 'C_H(E).
+ have sZ_ZRH: Z \subset 'Z('C_H(E)).
+ rewrite subsetI -{1}defZE setSI //= (subset_trans sZU) // centsC.
+ by rewrite subIset // centsC cHU.
+ rewrite (cyclic_factor_abelian sZ_ZRH) //= -/Z.
+ have defHs: Es \x ('C_H(E) / Z) = H / Z.
+ rewrite defEs dprodE ?quotient_cents // -?quotientMl ?defH -?quotientGI //=.
+ by rewrite setIA (setIidPl sEH) ['C_E(E)]defZE trivg_quotient.
+ have:= Ohm_dprod 1 defHs; rewrite /= defKs (Ohm1_id (abelemS sEsKs abelKs)).
+ rewrite dprodC; case/dprodP=> _ defEsRHs1 cRHs1Es tiRHs1Es.
+ have sRHsHs: 'C_H(E) / Z \subset H / Z by rewrite quotientS ?subsetIl.
+ have cRHsRHs: abelian ('C_H(E) / Z) by exact: abelianS cHsHs.
+ have pHs: p.-group (H / Z) by rewrite quotient_pgroup.
+ rewrite abelian_rank1_cyclic // (rank_pgroup (pgroupS sRHsHs pHs)).
+ rewrite p_rank_abelian // -(leq_add2r (logn p #|Es|)) -lognM ?cardG_gt0 //.
+ rewrite -TI_cardMg // defEsRHs1 /= -defEsZs TI_cardMg ?lognM ?cardG_gt0 //.
+ by rewrite leq_add2r -abelem_cyclic ?(abelemS sZsKs) // quotient_cyclic.
+have{cRH_RH} defRH: 'C_H(E) = U.
+ apply/eqP; rewrite eqEsubset andbC setIS ?centS // subsetI subsetIl /=.
+ by rewrite -{2}defH centM subsetI subsetIr.
+have scUR: 'C_R(U) = U by rewrite -setIA -{1}defRH -centM defH.
+have sUR: U \subset R by rewrite -defRH setSI.
+have tiER: E :&: R = 'Z(E) by rewrite setIA (setIidPl (subset_trans sEH sHG)).
+have [cRR | not_cRR] := boolP (abelian R).
+ exists E; [by right | exists [group of R]; split=> //; left].
+ by rewrite /= -(setIidPl (sub_abelian_cent cRR sUR)) scUR.
+have{scUR} scUR: [group of U] \in 'SCN(R).
+ by apply/SCN_P; rewrite (normalS sUR (subsetIl _ _)) // char_normal.
+have pR: p.-group R := pgroupS (subsetIl _ _) pG.
+have [R_le_3 | R_gt_3] := leqP (logn p #|R|) 3.
+ have esR: extraspecial R := p3group_extraspecial pR not_cRR R_le_3.
+ have esG: extraspecial G := cprod_extraspecial pG defG tiER esE esR.
+ exists G; [by right | exists ('Z(G))%G; rewrite cprod_center_id setIA setIid].
+ by split=> //; left; rewrite prime_cyclic; case: esG.
+have [[p2 _ ext2R] | [M []]] := cyclic_SCN pR scUR not_cRR cycU.
+ exists E; [by right | exists [group of R]; split=> //; right].
+ by rewrite dvdn_leq ?(@pfactor_dvdn 2 4) ?cardG_gt0 // -{2}p2.
+rewrite /= -/R => defM iUM modM _ _; pose N := 'C_G('Mho^1(U)).
+have charZN2: 'Z('Ohm_2(N)) \char G.
+ rewrite (char_trans (center_char _)) // (char_trans (Ohm_char _ _)) //.
+ by rewrite subcent_char ?char_refl // (char_trans (Mho_char _ _)).
+have:= sympG _ charZN2 (center_abelian _).
+rewrite abelian_rank1_cyclic ?center_abelian // leqNgt; case/negP.
+have defN: E \* M = N.
+ rewrite defM (cprod_modl defG) // centsC (subset_trans (Mho_sub 1 _)) //.
+ by rewrite /= -/U -defRH subsetIr.
+case/modular_group_classP: modM => q q_pr [n n_gt23 isoM].
+have{n_gt23} n_gt2 := leq_trans (leq_addl _ _) n_gt23.
+have n_gt1 := ltnW n_gt2; have n_gt0 := ltnW n_gt1.
+have [[x y] genM modM] := generators_modular_group q_pr n_gt2 isoM.
+have{q_pr} defq: q = p; last rewrite {q}defq in genM modM isoM.
+ have: p %| #|M| by rewrite -iUM dvdn_indexg.
+ by have [-> _ _ _] := genM; rewrite Euclid_dvdX // dvdn_prime2 //; case: eqP.
+have [oM Mx ox X'y] := genM; have [My _] := setDP X'y; have [oy _] := modM.
+have [sUM sMR]: U \subset M /\ M \subset R.
+ by rewrite defM subsetI sUR subsetIl centsC (subset_trans (Mho_sub _ _)).
+have oU1: #|'Mho^1(U)| = (p ^ n.-2)%N.
+ have oU: #|U| = (p ^ n.-1)%N.
+ by rewrite -(divg_indexS sUM) iUM oM -subn1 expnB.
+ case/cyclicP: cycU pU oU => u -> p_u ou.
+ by rewrite (Mho_p_cycle 1 p_u) -orderE (orderXexp 1 ou) subn1.
+have sZU1: Z \subset 'Mho^1(U).
+ rewrite -(cardSg_cyclic cycU) ?Ohm_sub ?Mho_sub // oZ oU1.
+ by rewrite -(subnKC n_gt2) expnS dvdn_mulr.
+case/modular_group_structure: genM => // _ [defZM _ oZM] _ _.
+have:= n_gt2; rewrite leq_eqVlt eq_sym !xpair_eqE andbC.
+case: eqP => [n3 _ _ | _ /= n_gt3 defOhmM].
+ have eqZU1: Z = 'Mho^1(U) by apply/eqP; rewrite eqEcard sZU1 oZ oU1 n3 /=.
+ rewrite (setIidPl _) in defM; first by rewrite -defM oM n3 pfactorK in R_gt_3.
+ by rewrite -eqZU1 subIset ?centS ?orbT.
+have{defOhmM} [|defM2 _] := defOhmM 2; first by rewrite -subn1 ltn_subRL.
+do [set xpn3 := x ^+ _; set X2 := <[_]>] in defM2.
+have oX2: #|X2| = (p ^ 2)%N.
+ by rewrite -orderE (orderXexp _ ox) -{1}(subnKC n_gt2) addSn addnK.
+have sZX2: Z \subset X2.
+ have cycXp: cyclic <[x ^+ p]> := cycle_cyclic _.
+ rewrite -(cardSg_cyclic cycXp) /=; first by rewrite oZ oX2 dvdn_mull.
+ rewrite -defZM subsetI (subset_trans (Ohm_sub _ _)) //=.
+ by rewrite (subset_trans sZU1) // centsC defM subsetIr.
+ by rewrite /xpn3 -subnSK //expnS expgM cycleX.
+have{defM2} [_ /= defM2 cYX2 tiX2Y] := dprodP defM2.
+have{defN} [_ defN cME] := cprodP defN.
+have cEM2: E \subset 'C('Ohm_2(M)).
+ by rewrite centsC (subset_trans _ cME) ?centS ?Ohm_sub.
+have [cEX2 cYE]: X2 \subset 'C(E) /\ E \subset 'C(<[y]>).
+ by apply/andP; rewrite centsC -subsetI -centM defM2.
+have pN: p.-group N := pgroupS (subsetIl _ _) pG.
+have defN2: (E <*> X2) \x <[y]> = 'Ohm_2(N).
+ rewrite dprodE ?centY ?subsetI 1?centsC ?cYE //=; last first.
+ rewrite -cycle_subG in My; rewrite joingC cent_joinEl //= -/X2.
+ rewrite -(setIidPr My) setIA -group_modl ?cycle_subG ?groupX //.
+ by rewrite mulGSid // (subset_trans _ sZX2) // -defZE -tiER setIS.
+ apply/eqP; rewrite cent_joinEr // -mulgA defM2 eqEsubset mulG_subG.
+ rewrite OhmS ?andbT; last by rewrite -defN mulG_subr.
+ have expE: exponent E %| p ^ 2 by rewrite exponent_special ?(pgroupS sEG).
+ rewrite /= (OhmE 2 pN) sub_gen /=; last 1 first.
+ by rewrite subsetI -defN mulG_subl sub_LdivT expE.
+ rewrite -cent_joinEl // -genM_join genS // -defN.
+ apply/subsetP=> ez; case/setIP; case/imset2P=> e z Ee Mz ->{ez}.
+ rewrite inE expgMn; last by red; rewrite -(centsP cME).
+ rewrite (exponentP expE) // mul1g => zp2; rewrite mem_mulg //=.
+ by rewrite (OhmE 2 (pgroupS sMR pR)) mem_gen // !inE Mz.
+have{defN2} defZN2: X2 \x <[y]> = 'Z('Ohm_2(N)).
+ rewrite -[X2](mulSGid sZX2) /= -/Z -defZE -(center_dprod defN2).
+ do 2!rewrite -{1}(center_idP (cycle_abelian _)) -/X2; congr (_ \x _).
+ by case/cprodP: (center_cprod (cprodEY cEX2)).
+have{defZN2} strZN2: \big[dprod/1]_(z <- [:: xpn3; y]) <[z]> = 'Z('Ohm_2(N)).
+ by rewrite unlock /= dprodg1.
+rewrite -size_abelian_type ?center_abelian //.
+have pZN2: p.-group 'Z('Ohm_2(N)) by rewrite (pgroupS _ pN) // subIset ?Ohm_sub.
+rewrite -(perm_eq_size (perm_eq_abelian_type pZN2 strZN2 _)) //= !inE.
+rewrite !(eq_sym 1) -!order_eq1 oy orderE oX2.
+by rewrite (eqn_exp2l 2 0) // (eqn_exp2l 1 0).
+Qed.
+
+End ExtremalTheory.