aboutsummaryrefslogtreecommitdiff
path: root/mathcomp/solvable/nilpotent.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/nilpotent.v
Initial commit
Diffstat (limited to 'mathcomp/solvable/nilpotent.v')
-rw-r--r--mathcomp/solvable/nilpotent.v755
1 files changed, 755 insertions, 0 deletions
diff --git a/mathcomp/solvable/nilpotent.v b/mathcomp/solvable/nilpotent.v
new file mode 100644
index 0000000..5b271de
--- /dev/null
+++ b/mathcomp/solvable/nilpotent.v
@@ -0,0 +1,755 @@
+(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *)
+Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path fintype div.
+Require Import bigop prime finset fingroup morphism automorphism quotient.
+Require Import commutator gproduct gfunctor center gseries cyclic.
+
+(******************************************************************************)
+(* This file defines nilpotent and solvable groups, and give some of their *)
+(* elementary properties; more will be added later (e.g., the nilpotence of *)
+(* p-groups in sylow.v, or the fact that minimal normal subgroups of solvable *)
+(* groups are elementary abelian in maximal.v). This file defines: *)
+(* nilpotent G == G is nilpotent, i.e., [~: H, G] is a proper subgroup of H *)
+(* for all nontrivial H <| G. *)
+(* solvable G == G is solvable, i.e., H^`(1) is a proper subgroup of H for *)
+(* all nontrivial subgroups H of G. *)
+(* 'L_n(G) == the nth term of the lower central series, namely *)
+(* [~: G, ..., G] (n Gs) if n > 0, with 'L_0(G) = G. *)
+(* G is nilpotent iff 'L_n(G) = 1 for some n. *)
+(* 'Z_n(G) == the nth term of the upper central series, i.e., *)
+(* with 'Z_0(G) = 1, 'Z_n.+1(G) / 'Z_n(G) = 'Z(G / 'Z_n(G)). *)
+(* nil_class G == the nilpotence class of G, i.e., the least n such that *)
+(* 'L_n.+1(G) = 1 (or, equivalently, 'Z_n(G) = G), if G is *)
+(* nilpotent; we take nil_class G = #|G| when G is not *)
+(* nilpotent, so nil_class G < #|G| iff G is nilpotent. *)
+(******************************************************************************)
+
+Set Implicit Arguments.
+Unset Strict Implicit.
+Unset Printing Implicit Defensive.
+
+Import GroupScope.
+
+Section SeriesDefs.
+
+Variables (n : nat) (gT : finGroupType) (A : {set gT}).
+
+Definition lower_central_at_rec := iter n (fun B => [~: B, A]) A.
+
+Definition upper_central_at_rec := iter n (fun B => coset B @*^-1 'Z(A / B)) 1.
+
+End SeriesDefs.
+
+(* By convention, the lower central series starts at 1 while the upper series *)
+(* starts at 0 (sic). *)
+Definition lower_central_at n := lower_central_at_rec n.-1.
+
+(* Note: 'nosimpl' MUST be used outside of a section -- the end of section *)
+(* "cooking" destroys it. *)
+Definition upper_central_at := nosimpl upper_central_at_rec.
+
+Arguments Scope lower_central_at [nat_scope _ group_scope].
+Arguments Scope upper_central_at [nat_scope _ group_scope].
+
+Notation "''L_' n ( G )" := (lower_central_at n G)
+ (at level 8, n at level 2, format "''L_' n ( G )") : group_scope.
+
+Notation "''Z_' n ( G )" := (upper_central_at n G)
+ (at level 8, n at level 2, format "''Z_' n ( G )") : group_scope.
+
+Section PropertiesDefs.
+
+Variables (gT : finGroupType) (A : {set gT}).
+
+Definition nilpotent :=
+ [forall (G : {group gT} | G \subset A :&: [~: G, A]), G :==: 1].
+
+Definition nil_class := index 1 (mkseq (fun n => 'L_n.+1(A)) #|A|).
+
+Definition solvable :=
+ [forall (G : {group gT} | G \subset A :&: [~: G, G]), G :==: 1].
+
+End PropertiesDefs.
+
+Arguments Scope nilpotent [_ group_scope].
+Arguments Scope nil_class [_ group_scope].
+Arguments Scope solvable [_ group_scope].
+Prenex Implicits nil_class nilpotent solvable.
+
+Section NilpotentProps.
+
+Variable gT: finGroupType.
+Implicit Types (A B : {set gT}) (G H : {group gT}).
+
+Lemma nilpotent1 : nilpotent [1 gT].
+Proof. by apply/forall_inP=> H; rewrite commG1 setIid -subG1. Qed.
+
+Lemma nilpotentS A B : B \subset A -> nilpotent A -> nilpotent B.
+Proof.
+move=> sBA nilA; apply/forall_inP=> H sHR.
+have:= forallP nilA H; rewrite (subset_trans sHR) //.
+by apply: subset_trans (setIS _ _) (setSI _ _); rewrite ?commgS.
+Qed.
+
+Lemma nil_comm_properl G H A :
+ nilpotent G -> H \subset G -> H :!=: 1 -> A \subset 'N_G(H) ->
+ [~: H, A] \proper H.
+Proof.
+move=> nilG sHG ntH; rewrite subsetI properE; case/andP=> sAG nHA.
+rewrite (subset_trans (commgS H (subset_gen A))) ?commg_subl ?gen_subG //.
+apply: contra ntH => sHR; have:= forallP nilG H; rewrite subsetI sHG.
+by rewrite (subset_trans sHR) ?commgS.
+Qed.
+
+Lemma nil_comm_properr G A H :
+ nilpotent G -> H \subset G -> H :!=: 1 -> A \subset 'N_G(H) ->
+ [~: A, H] \proper H.
+Proof. by rewrite commGC; apply: nil_comm_properl. Qed.
+
+Lemma centrals_nil (s : seq {group gT}) G :
+ G.-central.-series 1%G s -> last 1%G s = G -> nilpotent G.
+Proof.
+move=> cGs defG; apply/forall_inP=> H /subsetIP[sHG sHR].
+move: sHG; rewrite -{}defG -subG1 -[1]/(gval 1%G).
+elim: s 1%G cGs => //= L s IHs K /andP[/and3P[sRK sKL sLG] /IHs sHL] sHs.
+exact: subset_trans sHR (subset_trans (commSg _ (sHL sHs)) sRK).
+Qed.
+
+End NilpotentProps.
+
+Section LowerCentral.
+
+Variable gT : finGroupType.
+Implicit Types (A B : {set gT}) (G H : {group gT}).
+
+Lemma lcn0 A : 'L_0(A) = A. Proof. by []. Qed.
+Lemma lcn1 A : 'L_1(A) = A. Proof. by []. Qed.
+Lemma lcnSn n A : 'L_n.+2(A) = [~: 'L_n.+1(A), A]. Proof. by []. Qed.
+Lemma lcnSnS n G : [~: 'L_n(G), G] \subset 'L_n.+1(G).
+Proof. by case: n => //; exact: der1_subG. Qed.
+Lemma lcnE n A : 'L_n.+1(A) = lower_central_at_rec n A.
+Proof. by []. Qed.
+Lemma lcn2 A : 'L_2(A) = A^`(1). Proof. by []. Qed.
+
+Lemma lcn_group_set n G : group_set 'L_n(G).
+Proof. by case: n => [|[|n]]; exact: groupP. Qed.
+
+Canonical lower_central_at_group n G := Group (lcn_group_set n G).
+
+Lemma lcn_char n G : 'L_n(G) \char G.
+Proof.
+by case: n => [|n]; last elim: n => [|n IHn]; rewrite ?lcnSn ?charR ?char_refl.
+Qed.
+
+Lemma lcn_normal n G : 'L_n(G) <| G.
+Proof. by apply: char_normal; exact: lcn_char. Qed.
+
+Lemma lcn_sub n G : 'L_n(G) \subset G.
+Proof. by case/andP: (lcn_normal n G). Qed.
+
+Lemma lcn_norm n G : G \subset 'N('L_n(G)).
+Proof. by case/andP: (lcn_normal n G). Qed.
+
+Lemma lcn_subS n G : 'L_n.+1(G) \subset 'L_n(G).
+Proof.
+case: n => // n; rewrite lcnSn commGC commg_subr.
+by case/andP: (lcn_normal n.+1 G).
+Qed.
+
+Lemma lcn_normalS n G : 'L_n.+1(G) <| 'L_n(G).
+Proof. by apply: normalS (lcn_normal _ _); rewrite (lcn_subS, lcn_sub). Qed.
+
+Lemma lcn_central n G : 'L_n(G) / 'L_n.+1(G) \subset 'Z(G / 'L_n.+1(G)).
+Proof.
+case: n => [|n]; first by rewrite trivg_quotient sub1G.
+by rewrite subsetI quotientS ?lcn_sub ?quotient_cents2r.
+Qed.
+
+Lemma lcn_sub_leq m n G : n <= m -> 'L_m(G) \subset 'L_n(G).
+Proof.
+by move/subnK <-; elim: {m}(m - n) => // m; exact: subset_trans (lcn_subS _ _).
+Qed.
+
+Lemma lcnS n A B : A \subset B -> 'L_n(A) \subset 'L_n(B).
+Proof.
+by case: n => // n sAB; elim: n => // n IHn; rewrite !lcnSn genS ?imset2S.
+Qed.
+
+Lemma lcn_cprod n A B G : A \* B = G -> 'L_n(A) \* 'L_n(B) = 'L_n(G).
+Proof.
+case: n => // n /cprodP[[H K -> ->{A B}] defG cHK].
+have sL := subset_trans (lcn_sub _ _); rewrite cprodE ?(centSS _ _ cHK) ?sL //.
+symmetry; elim: n => // n; rewrite lcnSn => ->; rewrite commMG /=; last first.
+ by apply: subset_trans (commg_normr _ _); rewrite sL // -defG mulG_subr.
+rewrite -!(commGC G) -defG -{1}(centC cHK).
+rewrite !commMG ?normsR ?lcn_norm ?cents_norm // 1?centsC //.
+by rewrite -!(commGC 'L__(_)) -!lcnSn !(commG1P _) ?mul1g ?sL // centsC.
+Qed.
+
+Lemma lcn_dprod n A B G : A \x B = G -> 'L_n(A) \x 'L_n(B) = 'L_n(G).
+Proof.
+move=> defG; have [[K H defA defB] _ _ tiAB] := dprodP defG.
+rewrite !dprodEcp // in defG *; first exact: lcn_cprod.
+by rewrite defA defB; apply/trivgP; rewrite -tiAB defA defB setISS ?lcn_sub.
+Qed.
+
+Lemma der_cprod n A B G : A \* B = G -> A^`(n) \* B^`(n) = G^`(n).
+Proof. by move=> defG; elim: n => {defG}// n; apply: (lcn_cprod 2). Qed.
+
+Lemma der_dprod n A B G : A \x B = G -> A^`(n) \x B^`(n) = G^`(n).
+Proof. by move=> defG; elim: n => {defG}// n; apply: (lcn_dprod 2). Qed.
+
+Lemma lcn_bigcprod n I r P (F : I -> {set gT}) G :
+ \big[cprod/1]_(i <- r | P i) F i = G ->
+ \big[cprod/1]_(i <- r | P i) 'L_n(F i) = 'L_n(G).
+Proof.
+elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first exact/esym/trivgP/lcn_sub.
+by rewrite -(lcn_cprod n dG); have [[_ H _ dH]] := cprodP dG; rewrite dH (IH H).
+Qed.
+
+Lemma lcn_bigdprod n I r P (F : I -> {set gT}) G :
+ \big[dprod/1]_(i <- r | P i) F i = G ->
+ \big[dprod/1]_(i <- r | P i) 'L_n(F i) = 'L_n(G).
+Proof.
+elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first exact/esym/trivgP/lcn_sub.
+by rewrite -(lcn_dprod n dG); have [[_ H _ dH]] := dprodP dG; rewrite dH (IH H).
+Qed.
+
+Lemma der_bigcprod n I r P (F : I -> {set gT}) G :
+ \big[cprod/1]_(i <- r | P i) F i = G ->
+ \big[cprod/1]_(i <- r | P i) (F i)^`(n) = G^`(n).
+Proof.
+elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1.
+by rewrite -(der_cprod n dG); have [[_ H _ dH]] := cprodP dG; rewrite dH (IH H).
+Qed.
+
+Lemma der_bigdprod n I r P (F : I -> {set gT}) G :
+ \big[dprod/1]_(i <- r | P i) F i = G ->
+ \big[dprod/1]_(i <- r | P i) (F i)^`(n) = G^`(n).
+Proof.
+elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1.
+by rewrite -(der_dprod n dG); have [[_ H _ dH]] := dprodP dG; rewrite dH (IH H).
+Qed.
+
+Lemma nilpotent_class G : nilpotent G = (nil_class G < #|G|).
+Proof.
+rewrite /nil_class; set s := mkseq _ _.
+transitivity (1 \in s); last by rewrite -index_mem size_mkseq.
+apply/idP/mapP=> {s}/= [nilG | [n _ Ln1]]; last first.
+ apply/forall_inP=> H /subsetIP[sHG sHR].
+ rewrite -subG1 {}Ln1; elim: n => // n IHn.
+ by rewrite (subset_trans sHR) ?commSg.
+pose m := #|G|.-1; exists m; first by rewrite mem_iota /= prednK.
+rewrite ['L__(G)]card_le1_trivg //= -(subnn m).
+elim: {-2}m => [|n]; [by rewrite subn0 prednK | rewrite lcnSn subnS].
+case: (eqsVneq 'L_n.+1(G) 1) => [-> | ntLn]; first by rewrite comm1G cards1.
+case: (m - n) => [|m' /= IHn]; first by rewrite leqNgt cardG_gt1 ntLn.
+rewrite -ltnS (leq_trans (proper_card _) IHn) //.
+by rewrite (nil_comm_properl nilG) ?lcn_sub // subsetI subxx lcn_norm.
+Qed.
+
+Lemma lcn_nil_classP n G :
+ nilpotent G -> reflect ('L_n.+1(G) = 1) (nil_class G <= n).
+Proof.
+rewrite nilpotent_class /nil_class; set s := mkseq _ _.
+set c := index 1 s => lt_c_G; case: leqP => [le_c_n | lt_n_c].
+ have Lc1: nth 1 s c = 1 by rewrite nth_index // -index_mem size_mkseq.
+ by left; apply/trivgP; rewrite -Lc1 nth_mkseq ?lcn_sub_leq.
+right; apply/eqP/negPf; rewrite -(before_find 1 lt_n_c) nth_mkseq //.
+exact: ltn_trans lt_n_c lt_c_G.
+Qed.
+
+Lemma lcnP G : reflect (exists n, 'L_n.+1(G) = 1) (nilpotent G).
+Proof.
+apply: (iffP idP) => [nilG | [n Ln1]].
+ by exists (nil_class G); exact/lcn_nil_classP.
+apply/forall_inP=> H /subsetIP[sHG sHR]; rewrite -subG1 -{}Ln1.
+by elim: n => // n IHn; rewrite (subset_trans sHR) ?commSg.
+Qed.
+
+Lemma abelian_nil G : abelian G -> nilpotent G.
+Proof. by move=> abG; apply/lcnP; exists 1%N; exact/commG1P. Qed.
+
+Lemma nil_class0 G : (nil_class G == 0) = (G :==: 1).
+Proof.
+apply/idP/eqP=> [nilG | ->].
+ by apply/(lcn_nil_classP 0); rewrite ?nilpotent_class (eqP nilG) ?cardG_gt0.
+by rewrite -leqn0; apply/(lcn_nil_classP 0); rewrite ?nilpotent1.
+Qed.
+
+Lemma nil_class1 G : (nil_class G <= 1) = abelian G.
+Proof.
+have [-> | ntG] := eqsVneq G 1.
+ by rewrite abelian1 leq_eqVlt ltnS leqn0 nil_class0 eqxx orbT.
+apply/idP/idP=> cGG.
+ apply/commG1P; apply/(lcn_nil_classP 1); rewrite // nilpotent_class.
+ by rewrite (leq_ltn_trans cGG) // cardG_gt1.
+by apply/(lcn_nil_classP 1); rewrite ?abelian_nil //; apply/commG1P.
+Qed.
+
+Lemma cprod_nil A B G : A \* B = G -> nilpotent G = nilpotent A && nilpotent B.
+Proof.
+move=> defG; case/cprodP: defG (defG) => [[H K -> ->{A B}] defG _] defGc.
+apply/idP/andP=> [nilG | [/lcnP[m LmH1] /lcnP[n LnK1]]].
+ by rewrite !(nilpotentS _ nilG) // -defG (mulG_subr, mulG_subl).
+apply/lcnP; exists (m + n.+1); apply/trivgP.
+case/cprodP: (lcn_cprod (m.+1 + n.+1) defGc) => _ <- _.
+by rewrite mulG_subG /= -{1}LmH1 -LnK1 !lcn_sub_leq ?leq_addl ?leq_addr.
+Qed.
+
+Lemma mulg_nil G H :
+ H \subset 'C(G) -> nilpotent (G * H) = nilpotent G && nilpotent H.
+Proof. by move=> cGH; rewrite -(cprod_nil (cprodEY cGH)) /= cent_joinEr. Qed.
+
+Lemma dprod_nil A B G : A \x B = G -> nilpotent G = nilpotent A && nilpotent B.
+Proof. by case/dprodP=> [[H K -> ->] <- cHK _]; rewrite mulg_nil.
+Qed.
+
+Lemma bigdprod_nil I r (P : pred I) (A_ : I -> {set gT}) G :
+ \big[dprod/1]_(i <- r | P i) A_ i = G
+ -> (forall i, P i -> nilpotent (A_ i)) -> nilpotent G.
+Proof.
+move=> defG nilA; elim/big_rec: _ => [|i B Pi nilB] in G defG *.
+ by rewrite -defG nilpotent1.
+have [[_ H _ defB] _ _ _] := dprodP defG.
+by rewrite (dprod_nil defG) nilA //= defB nilB.
+Qed.
+
+End LowerCentral.
+
+Notation "''L_' n ( G )" := (lower_central_at_group n G) : Group_scope.
+
+Lemma lcn_cont n : GFunctor.continuous (lower_central_at n).
+Proof.
+case: n => //; elim=> // n IHn g0T h0T H phi.
+by rewrite !lcnSn morphimR ?lcn_sub // commSg ?IHn.
+Qed.
+
+Canonical lcn_igFun n := [igFun by lcn_sub^~ n & lcn_cont n].
+Canonical lcn_gFun n := [gFun by lcn_cont n].
+Canonical lcn_mgFun n := [mgFun by fun _ G H => @lcnS _ n G H].
+
+Section UpperCentralFunctor.
+
+Variable n : nat.
+Implicit Type gT : finGroupType.
+
+Lemma ucn_pmap : exists hZ : GFunctor.pmap, @upper_central_at n = hZ.
+Proof.
+elim: n => [|n' [hZ defZ]]; first by exists trivGfun_pgFun.
+by exists [pgFun of center %% hZ]; rewrite /= -defZ.
+Qed.
+
+(* Now extract all the intermediate facts of the last proof. *)
+
+Lemma ucn_group_set gT (G : {group gT}) : group_set 'Z_n(G).
+Proof. by have [hZ ->] := ucn_pmap; exact: groupP. Qed.
+
+Canonical upper_central_at_group gT G := Group (@ucn_group_set gT G).
+
+Lemma ucn_sub gT (G : {group gT}) : 'Z_n(G) \subset G.
+Proof. by have [hZ ->] := ucn_pmap; exact: gFsub. Qed.
+
+Lemma morphim_ucn : GFunctor.pcontinuous (upper_central_at n).
+Proof. by have [hZ ->] := ucn_pmap; exact: pmorphimF. Qed.
+
+Canonical ucn_igFun := [igFun by ucn_sub & morphim_ucn].
+Canonical ucn_gFun := [gFun by morphim_ucn].
+Canonical ucn_pgFun := [pgFun by morphim_ucn].
+
+Variable (gT : finGroupType) (G : {group gT}).
+
+Lemma ucn_char : 'Z_n(G) \char G. Proof. exact: gFchar. Qed.
+Lemma ucn_norm : G \subset 'N('Z_n(G)). Proof. exact: gFnorm. Qed.
+Lemma ucn_normal : 'Z_n(G) <| G. Proof. exact: gFnormal. Qed.
+
+End UpperCentralFunctor.
+
+Notation "''Z_' n ( G )" := (upper_central_at_group n G) : Group_scope.
+
+Section UpperCentral.
+
+Variable gT : finGroupType.
+Implicit Types (A B : {set gT}) (G H : {group gT}).
+
+Lemma ucn0 A : 'Z_0(A) = 1.
+Proof. by []. Qed.
+
+Lemma ucnSn n A : 'Z_n.+1(A) = coset 'Z_n(A) @*^-1 'Z(A / 'Z_n(A)).
+Proof. by []. Qed.
+
+Lemma ucnE n A : 'Z_n(A) = upper_central_at_rec n A.
+Proof. by []. Qed.
+
+Lemma ucn_subS n G : 'Z_n(G) \subset 'Z_n.+1(G).
+Proof. by rewrite -{1}['Z_n(G)]ker_coset morphpreS ?sub1G. Qed.
+
+Lemma ucn_sub_geq m n G : n >= m -> 'Z_m(G) \subset 'Z_n(G).
+Proof.
+move/subnK <-; elim: {n}(n - m) => // n IHn.
+exact: subset_trans (ucn_subS _ _).
+Qed.
+
+Lemma ucn_central n G : 'Z_n.+1(G) / 'Z_n(G) = 'Z(G / 'Z_n(G)).
+Proof. by rewrite ucnSn cosetpreK. Qed.
+
+Lemma ucn_normalS n G : 'Z_n(G) <| 'Z_n.+1(G).
+Proof. by rewrite (normalS _ _ (ucn_normal n G)) ?ucn_subS ?ucn_sub. Qed.
+
+Lemma ucn_comm n G : [~: 'Z_n.+1(G), G] \subset 'Z_n(G).
+Proof.
+rewrite -quotient_cents2 ?normal_norm ?ucn_normal ?ucn_normalS //.
+by rewrite ucn_central subsetIr.
+Qed.
+
+Lemma ucn1 G : 'Z_1(G) = 'Z(G).
+Proof.
+apply: (quotient_inj (normal1 _) (normal1 _)).
+by rewrite /= (ucn_central 0) -injmF ?norms1 ?coset1_injm.
+Qed.
+
+Lemma ucnSnR n G : 'Z_n.+1(G) = [set x in G | [~: [set x], G] \subset 'Z_n(G)].
+Proof.
+apply/setP=> x; rewrite inE -(setIidPr (ucn_sub n.+1 G)) inE ucnSn.
+case Gx: (x \in G) => //=; have nZG := ucn_norm n G.
+rewrite -sub1set -sub_quotient_pre -?quotient_cents2 ?sub1set ?(subsetP nZG) //.
+by rewrite subsetI quotientS ?sub1set.
+Qed.
+
+Lemma ucn_cprod n A B G : A \* B = G -> 'Z_n(A) \* 'Z_n(B) = 'Z_n(G).
+Proof.
+case/cprodP=> [[H K -> ->{A B}] mulHK cHK].
+elim: n => [|n /cprodP[_ /= defZ cZn]]; first exact: cprod1g.
+set Z := 'Z_n(G) in defZ cZn; rewrite (ucnSn n G) /= -/Z.
+have /mulGsubP[nZH nZK]: H * K \subset 'N(Z) by rewrite mulHK gFnorm.
+have <-: 'Z(H / Z) * 'Z(K / Z) = 'Z(G / Z).
+ by rewrite -mulHK quotientMl // center_prod ?quotient_cents.
+have ZquoZ (B A : {group gT}):
+ B \subset 'C(A) -> 'Z_n(A) * 'Z_n(B) = Z -> 'Z(A / Z) = 'Z_n.+1(A) / Z.
+- move=> cAB {defZ}defZ; have cAZnB := subset_trans (ucn_sub n B) cAB.
+ have /second_isom[/=]: A \subset 'N(Z).
+ by rewrite -defZ normsM ?gFnorm ?cents_norm // centsC.
+ suffices ->: Z :&: A = 'Z_n(A).
+ by move=> f inj_f im_f; rewrite -!im_f ?gFsub // ucn_central injm_center.
+ rewrite -defZ -group_modl ?gFsub //; apply/mulGidPl.
+ have [-> | n_gt0] := posnP n; first exact: subsetIl.
+ by apply: subset_trans (ucn_sub_geq A n_gt0); rewrite /= setIC ucn1 setIS.
+rewrite (ZquoZ H K) 1?centsC 1?(centC cZn) // {ZquoZ}(ZquoZ K H) //.
+have cZn1: 'Z_n.+1(K) \subset 'C('Z_n.+1(H)) by apply: centSS cHK; apply: gFsub.
+rewrite -quotientMl ?quotientK ?mul_subG ?(subset_trans (gFsub _ _)) //=.
+rewrite cprodE // -cent_joinEr ?mulSGid //= cent_joinEr //= -/Z.
+by rewrite -defZ mulgSS ?ucn_subS.
+Qed.
+
+Lemma ucn_dprod n A B G : A \x B = G -> 'Z_n(A) \x 'Z_n(B) = 'Z_n(G).
+Proof.
+move=> defG; have [[K H defA defB] _ _ tiAB] := dprodP defG.
+rewrite !dprodEcp // in defG *; first exact: ucn_cprod.
+by rewrite defA defB; apply/trivgP; rewrite -tiAB defA defB setISS ?ucn_sub.
+Qed.
+
+Lemma ucn_bigcprod n I r P (F : I -> {set gT}) G :
+ \big[cprod/1]_(i <- r | P i) F i = G ->
+ \big[cprod/1]_(i <- r | P i) 'Z_n(F i) = 'Z_n(G).
+Proof.
+elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1.
+by rewrite -(ucn_cprod n dG); have [[_ H _ dH]] := cprodP dG; rewrite dH (IH H).
+Qed.
+
+Lemma ucn_bigdprod n I r P (F : I -> {set gT}) G :
+ \big[dprod/1]_(i <- r | P i) F i = G ->
+ \big[dprod/1]_(i <- r | P i) 'Z_n(F i) = 'Z_n(G).
+Proof.
+elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1.
+by rewrite -(ucn_dprod n dG); have [[_ H _ dH]] := dprodP dG; rewrite dH (IH H).
+Qed.
+
+Lemma ucn_lcnP n G : ('L_n.+1(G) == 1) = ('Z_n(G) == G).
+Proof.
+rewrite !eqEsubset sub1G ucn_sub /= andbT -(ucn0 G).
+elim: {1 3}n 0 (addn0 n) => [j <- //|i IHi j].
+rewrite addSnnS => /IHi <- {IHi}; rewrite ucnSn lcnSn.
+have nZG := normal_norm (ucn_normal j G).
+have nZL := subset_trans (lcn_sub _ _) nZG.
+by rewrite -sub_morphim_pre // subsetI morphimS ?lcn_sub // quotient_cents2.
+Qed.
+
+Lemma ucnP G : reflect (exists n, 'Z_n(G) = G) (nilpotent G).
+Proof.
+apply: (iffP (lcnP G)) => [] [n /eqP clGn];
+ by exists n; apply/eqP; rewrite ucn_lcnP in clGn *.
+Qed.
+
+Lemma ucn_nil_classP n G :
+ nilpotent G -> reflect ('Z_n(G) = G) (nil_class G <= n).
+Proof.
+move=> nilG; rewrite (sameP (lcn_nil_classP n nilG) eqP) ucn_lcnP; exact: eqP.
+Qed.
+
+Lemma ucn_id n G : 'Z_n('Z_n(G)) = 'Z_n(G).
+Proof. by rewrite -{2}['Z_n(G)]gFid. Qed.
+
+Lemma ucn_nilpotent n G : nilpotent 'Z_n(G).
+Proof. by apply/ucnP; exists n; rewrite ucn_id. Qed.
+
+Lemma nil_class_ucn n G : nil_class 'Z_n(G) <= n.
+Proof. by apply/ucn_nil_classP; rewrite ?ucn_nilpotent ?ucn_id. Qed.
+
+End UpperCentral.
+
+Section MorphNil.
+
+Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}).
+Implicit Type G : {group aT}.
+
+Lemma morphim_lcn n G : G \subset D -> f @* 'L_n(G) = 'L_n(f @* G).
+Proof.
+move=> sHG; case: n => //; elim=> // n IHn.
+by rewrite !lcnSn -IHn morphimR // (subset_trans _ sHG) // lcn_sub.
+Qed.
+
+Lemma injm_ucn n G : 'injm f -> G \subset D -> f @* 'Z_n(G) = 'Z_n(f @* G).
+Proof. exact: injmF. Qed.
+
+Lemma morphim_nil G : nilpotent G -> nilpotent (f @* G).
+Proof.
+case/ucnP=> n ZnG; apply/ucnP; exists n; apply/eqP.
+by rewrite eqEsubset ucn_sub /= -{1}ZnG morphim_ucn.
+Qed.
+
+Lemma injm_nil G : 'injm f -> G \subset D -> nilpotent (f @* G) = nilpotent G.
+Proof.
+move=> injf sGD; apply/idP/idP; last exact: morphim_nil.
+case/ucnP=> n; rewrite -injm_ucn // => /injm_morphim_inj defZ.
+by apply/ucnP; exists n; rewrite defZ ?(subset_trans (ucn_sub n G)).
+Qed.
+
+Lemma nil_class_morphim G : nilpotent G -> nil_class (f @* G) <= nil_class G.
+Proof.
+move=> nilG; rewrite (sameP (ucn_nil_classP _ (morphim_nil nilG)) eqP) /=.
+by rewrite eqEsubset ucn_sub -{1}(ucn_nil_classP _ nilG (leqnn _)) morphim_ucn.
+Qed.
+
+Lemma nil_class_injm G :
+ 'injm f -> G \subset D -> nil_class (f @* G) = nil_class G.
+Proof.
+move=> injf sGD; case nilG: (nilpotent G).
+ apply/eqP; rewrite eqn_leq nil_class_morphim //.
+ rewrite (sameP (lcn_nil_classP _ nilG) eqP) -subG1.
+ rewrite -(injmSK injf) ?(subset_trans (lcn_sub _ _)) // morphim1.
+ by rewrite morphim_lcn // (lcn_nil_classP _ _ (leqnn _)) //= injm_nil.
+transitivity #|G|; apply/eqP; rewrite eqn_leq.
+ rewrite -(card_injm injf sGD) (leq_trans (index_size _ _)) ?size_mkseq //.
+ by rewrite leqNgt -nilpotent_class injm_nil ?nilG.
+rewrite (leq_trans (index_size _ _)) ?size_mkseq // leqNgt -nilpotent_class.
+by rewrite nilG.
+Qed.
+
+End MorphNil.
+
+Section QuotientNil.
+
+Variables gT : finGroupType.
+Implicit Types (rT : finGroupType) (G H : {group gT}).
+
+Lemma quotient_ucn_add m n G : 'Z_(m + n)(G) / 'Z_n(G) = 'Z_m(G / 'Z_n(G)).
+Proof.
+elim: m => [|m IHm]; first exact: trivg_quotient.
+apply/setP=> Zx; have [x Nx ->{Zx}] := cosetP Zx.
+have [sZG nZG] := andP (ucn_normal n G).
+rewrite (ucnSnR m) inE -!sub1set -morphim_set1 //= -quotientR ?sub1set // -IHm.
+rewrite !quotientSGK ?(ucn_sub_geq, leq_addl, comm_subG _ nZG, sub1set) //=.
+by rewrite addSn /= ucnSnR inE.
+Qed.
+
+Lemma isog_nil rT G (L : {group rT}) : G \isog L -> nilpotent G = nilpotent L.
+Proof. by case/isogP=> f injf <-; rewrite injm_nil. Qed.
+
+Lemma isog_nil_class rT G (L : {group rT}) :
+ G \isog L -> nil_class G = nil_class L.
+Proof. by case/isogP=> f injf <-; rewrite nil_class_injm. Qed.
+
+Lemma quotient_nil G H : nilpotent G -> nilpotent (G / H).
+Proof. exact: morphim_nil. Qed.
+
+Lemma quotient_center_nil G : nilpotent (G / 'Z(G)) = nilpotent G.
+Proof.
+rewrite -ucn1; apply/idP/idP; last exact: quotient_nil.
+case/ucnP=> c nilGq; apply/ucnP; exists c.+1; have nsZ1G := ucn_normal 1 G.
+apply: (quotient_inj _ nsZ1G); last by rewrite /= -(addn1 c) quotient_ucn_add.
+by rewrite (normalS _ _ nsZ1G) ?ucn_sub ?ucn_sub_geq.
+Qed.
+
+Lemma nil_class_quotient_center G :
+ nilpotent (G) -> nil_class (G / 'Z(G)) = (nil_class G).-1.
+Proof.
+move=> nilG; have nsZ1G := ucn_normal 1 G.
+apply/eqP; rewrite -ucn1 eqn_leq; apply/andP; split.
+ apply/ucn_nil_classP; rewrite ?quotient_nil //= -quotient_ucn_add ucn1.
+ by rewrite (ucn_nil_classP _ _ _) ?addn1 ?leqSpred.
+rewrite -subn1 leq_subLR addnC; apply/ucn_nil_classP => //=.
+apply: (quotient_inj _ nsZ1G) => /=.
+ by apply: normalS (ucn_sub _ _) nsZ1G; rewrite /= addnS ucn_sub_geq.
+by rewrite quotient_ucn_add; apply/ucn_nil_classP; rewrite //= quotient_nil.
+Qed.
+
+Lemma nilpotent_sub_norm G H :
+ nilpotent G -> H \subset G -> 'N_G(H) \subset H -> G :=: H.
+Proof.
+move=> nilG sHG sNH; apply/eqP; rewrite eqEsubset sHG andbT; apply/negP=> nsGH.
+have{nsGH} [i sZH []]: exists2 i, 'Z_i(G) \subset H & ~ 'Z_i.+1(G) \subset H.
+ case/ucnP: nilG => n ZnG; rewrite -{}ZnG in nsGH.
+ elim: n => [|i IHi] in nsGH *; first by rewrite sub1G in nsGH.
+ by case sZH: ('Z_i(G) \subset H); [exists i | apply: IHi; rewrite sZH].
+apply: subset_trans sNH; rewrite subsetI ucn_sub -commg_subr.
+by apply: subset_trans sZH; apply: subset_trans (ucn_comm i G); exact: commgS.
+Qed.
+
+Lemma nilpotent_proper_norm G H :
+ nilpotent G -> H \proper G -> H \proper 'N_G(H).
+Proof.
+move=> nilG; rewrite properEneq properE subsetI normG => /andP[neHG sHG].
+by rewrite sHG; apply: contra neHG; move/(nilpotent_sub_norm nilG)->.
+Qed.
+
+Lemma nilpotent_subnormal G H : nilpotent G -> H \subset G -> H <|<| G.
+Proof.
+move=> nilG; elim: {H}_.+1 {-2}H (ltnSn (#|G| - #|H|)) => // m IHm H.
+rewrite ltnS => leGHm sHG; have:= sHG; rewrite subEproper.
+case/predU1P=> [->|]; first exact: subnormal_refl.
+move/(nilpotent_proper_norm nilG); set K := 'N_G(H) => prHK.
+have snHK: H <|<| K by rewrite normal_subnormal ?normalSG.
+have sKG: K \subset G by rewrite subsetIl.
+apply: subnormal_trans snHK (IHm _ (leq_trans _ leGHm) sKG).
+by rewrite ltn_sub2l ?proper_card ?(proper_sub_trans prHK).
+Qed.
+
+Lemma TI_center_nil G H : nilpotent G -> H <| G -> H :&: 'Z(G) = 1 -> H :=: 1.
+Proof.
+move=> nilG /andP[sHG nHG] tiHZ.
+rewrite -{1}(setIidPl sHG); have{nilG} /ucnP[n <-] := nilG.
+elim: n => [|n IHn]; apply/trivgP; rewrite ?subsetIr // -tiHZ.
+rewrite [H :&: 'Z(G)]setIA subsetI setIS ?ucn_sub //= (sameP commG1P trivgP).
+rewrite -commg_subr commGC in nHG.
+rewrite -IHn subsetI (subset_trans _ nHG) ?commSg ?subsetIl //=.
+by rewrite (subset_trans _ (ucn_comm n G)) ?commSg ?subsetIr.
+Qed.
+
+Lemma meet_center_nil G H :
+ nilpotent G -> H <| G -> H :!=: 1 -> H :&: 'Z(G) != 1.
+Proof. by move=> nilG nsHG; apply: contraNneq => /TI_center_nil->. Qed.
+
+Lemma center_nil_eq1 G : nilpotent G -> ('Z(G) == 1) = (G :==: 1).
+Proof.
+move=> nilG; apply/eqP/eqP=> [Z1 | ->]; last exact: center1.
+by rewrite (TI_center_nil nilG) // (setIidPr (center_sub G)).
+Qed.
+
+Lemma cyclic_nilpotent_quo_der1_cyclic G :
+ nilpotent G -> cyclic (G / G^`(1)) -> cyclic G.
+Proof.
+move=> nG; rewrite (isog_cyclic (quotient1_isog G)).
+have [-> // | ntG' cGG'] := (eqVneq G^`(1) 1)%g.
+suffices: 'L_2(G) \subset G :&: 'L_3(G) by move/(eqfun_inP nG)=> <-.
+rewrite subsetI lcn_sub /= -quotient_cents2 ?lcn_norm //.
+apply: cyclic_factor_abelian (lcn_central 2 G) _.
+by rewrite (isog_cyclic (third_isog _ _ _)) ?lcn_normal // lcn_subS.
+Qed.
+
+End QuotientNil.
+
+Section Solvable.
+
+Variable gT : finGroupType.
+Implicit Types G H : {group gT}.
+
+Lemma nilpotent_sol G : nilpotent G -> solvable G.
+Proof.
+move=> nilG; apply/forall_inP=> H /subsetIP[sHG sHH'].
+by rewrite (forall_inP nilG) // subsetI sHG (subset_trans sHH') ?commgS.
+Qed.
+
+Lemma abelian_sol G : abelian G -> solvable G.
+Proof. by move/abelian_nil; exact: nilpotent_sol. Qed.
+
+Lemma solvable1 : solvable [1 gT]. Proof. exact: abelian_sol (abelian1 gT). Qed.
+
+Lemma solvableS G H : H \subset G -> solvable G -> solvable H.
+Proof.
+move=> sHG solG; apply/forall_inP=> K /subsetIP[sKH sKK'].
+by rewrite (forall_inP solG) // subsetI (subset_trans sKH).
+Qed.
+
+Lemma sol_der1_proper G H :
+ solvable G -> H \subset G -> H :!=: 1 -> H^`(1) \proper H.
+Proof.
+move=> solG sHG ntH; rewrite properE comm_subG //; apply: implyP ntH.
+by have:= forallP solG H; rewrite subsetI sHG implybNN.
+Qed.
+
+Lemma derivedP G : reflect (exists n, G^`(n) = 1) (solvable G).
+Proof.
+apply: (iffP idP) => [solG | [n solGn]]; last first.
+ apply/forall_inP=> H /subsetIP[sHG sHH'].
+ rewrite -subG1 -{}solGn; elim: n => // n IHn.
+ exact: subset_trans sHH' (commgSS _ _).
+suffices IHn n: #|G^`(n)| <= (#|G|.-1 - n).+1.
+ by exists #|G|.-1; rewrite [G^`(_)]card_le1_trivg ?(leq_trans (IHn _)) ?subnn.
+elim: n => [|n IHn]; first by rewrite subn0 prednK.
+rewrite dergSn subnS -ltnS.
+have [-> | ntGn] := eqVneq G^`(n) 1; first by rewrite commG1 cards1.
+case: (_ - _) IHn => [|n']; first by rewrite leqNgt cardG_gt1 ntGn.
+by apply: leq_trans (proper_card _); exact: sol_der1_proper (der_sub _ _) _.
+Qed.
+
+End Solvable.
+
+Section MorphSol.
+
+Variables (gT rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}).
+Variable G : {group gT}.
+
+Lemma morphim_sol : solvable G -> solvable (f @* G).
+Proof.
+move/(solvableS (subsetIr D G)); case/derivedP=> n Gn1; apply/derivedP.
+by exists n; rewrite /= -morphimIdom -morphim_der ?subsetIl // Gn1 morphim1.
+Qed.
+
+Lemma injm_sol : 'injm f -> G \subset D -> solvable (f @* G) = solvable G.
+Proof.
+move=> injf sGD; apply/idP/idP; last exact: morphim_sol.
+case/derivedP=> n Gn1; apply/derivedP; exists n; apply/trivgP.
+rewrite -(injmSK injf) ?(subset_trans (der_sub _ _)) ?morphim_der //.
+by rewrite Gn1 morphim1.
+Qed.
+
+End MorphSol.
+
+Section QuotientSol.
+
+Variables gT rT : finGroupType.
+Implicit Types G H K : {group gT}.
+
+Lemma isog_sol G (L : {group rT}) : G \isog L -> solvable G = solvable L.
+Proof. by case/isogP=> f injf <-; rewrite injm_sol. Qed.
+
+Lemma quotient_sol G H : solvable G -> solvable (G / H).
+Proof. exact: morphim_sol. Qed.
+
+Lemma series_sol G H : H <| G -> solvable G = solvable H && solvable (G / H).
+Proof.
+case/andP=> sHG nHG; apply/idP/andP=> [solG | [solH solGH]].
+ by rewrite quotient_sol // (solvableS sHG).
+apply/forall_inP=> K /subsetIP[sKG sK'K].
+suffices sKH: K \subset H by rewrite (forall_inP solH) // subsetI sKH.
+have nHK := subset_trans sKG nHG.
+rewrite -quotient_sub1 // subG1 (forall_inP solGH) //.
+by rewrite subsetI -morphimR ?morphimS.
+Qed.
+
+Lemma metacyclic_sol G : metacyclic G -> solvable G.
+Proof.
+case/metacyclicP=> K [cycK nsKG cycGq].
+by rewrite (series_sol nsKG) !abelian_sol ?cyclic_abelian.
+Qed.
+
+End QuotientSol.