-
Notifications
You must be signed in to change notification settings - Fork 110
/
fingroup.v
3071 lines (2353 loc) · 110 KB
/
fingroup.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* (c) Copyright 2006-2016 Microsoft Corporation and Inria. *)
(* Distributed under the terms of CeCILL-B. *)
From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq choice.
From mathcomp Require Import fintype div path tuple bigop prime finset.
(******************************************************************************)
(* This file defines the main interface for finite groups : *)
(* finGroupType == the structure for finite types with a group law. *)
(* {group gT} == type of groups with elements of type gT. *)
(* baseFinGroupType == the structure for finite types with a monoid law *)
(* and an involutive antimorphism; finGroupType is *)
(* derived from baseFinGroupType (via a telescope). *)
(* FinGroupType mulVg == the finGroupType structure for an existing *)
(* baseFinGroupType structure, built from a proof of *)
(* the left inverse group axiom for that structure's *)
(* operations. *)
(* BaseFinGroupType bgm == the baseFingroupType structure built by packaging *)
(* bgm : FinGroup.mixin_of T for a type T with an *)
(* existing finType structure. *)
(* FinGroup.BaseMixin mulA mul1x invK invM == *)
(* the mixin for a baseFinGroupType structure, built *)
(* from proofs of the baseFinGroupType axioms. *)
(* FinGroup.Mixin mulA mul1x mulVg == *)
(* the mixin for a baseFinGroupType structure, built *)
(* from proofs of the group axioms. *)
(* [baseFinGroupType of T] == a clone of an existing baseFinGroupType *)
(* structure on T, for T (the existing structure *)
(* might be for some delta-expansion of T). *)
(* [finGroupType of T] == a clone of an existing finGroupType structure on *)
(* T, for the canonical baseFinGroupType structure *)
(* of T (the existing structure might be for the *)
(* baseFinGroupType of some delta-expansion of T). *)
(* [group of G] == a clone for an existing {group gT} structure on *)
(* G : {set gT} (the existing structure might be for *)
(* some delta-expansion of G). *)
(* If gT implements finGroupType, then we can form {set gT}, the type of *)
(* finite sets with elements of type gT (as finGroupType extends finType). *)
(* The group law extends pointwise to {set gT}, which thus implements a sub- *)
(* interface baseFinGroupType of finGroupType. To be consistent with the *)
(* predType interface, this is done by coercion to FinGroup.arg_sort, an *)
(* alias for FinGroup.sort. Accordingly, all pointwise group operations below *)
(* have arguments of type (FinGroup.arg_sort) gT and return results of type *)
(* FinGroup.sort gT. *)
(* The notations below are declared in two scopes: *)
(* group_scope (delimiter %g) for point operations and set constructs. *)
(* Group_scope (delimiter %G) for explicit {group gT} structures. *)
(* These scopes should not be opened globally, although group_scope is often *)
(* opened locally in group-theory files (via Import GroupScope). *)
(* As {group gT} is both a subtype and an interface structure for {set gT}, *)
(* the fact that a given G : {set gT} is a group can (and usually should) be *)
(* inferred by type inference with canonical structures. This means that all *)
(* `group' constructions (e.g., the normaliser 'N_G(H)) actually define sets *)
(* with a canonical {group gT} structure; the %G delimiter can be used to *)
(* specify the actual {group gT} structure (e.g., 'N_G(H)%G). *)
(* Operations on elements of a group: *)
(* x * y == the group product of x and y. *)
(* x ^+ n == the nth power of x, i.e., x * ... * x (n times). *)
(* x^-1 == the group inverse of x. *)
(* x ^- n == the inverse of x ^+ n (notation for (x ^+ n)^-1). *)
(* 1 == the unit element. *)
(* x ^ y == the conjugate of x by y (i.e., y^-1 * (x * y)). *)
(* [~ x, y] == the commutator of x and y (i.e., x^-1 * x ^ y). *)
(* [~ x1, ..., xn] == the commutator of x1, ..., xn (associating left). *)
(* \prod_(i ...) x i == the product of the x i (order-sensitive). *)
(* commute x y <-> x and y commute. *)
(* centralises x A <-> x centralises A. *)
(* 'C[x] == the set of elements that commute with x. *)
(* 'C_G[x] == the set of elements of G that commute with x. *)
(* <[x]> == the cyclic subgroup generated by the element x. *)
(* #[x] == the order of the element x, i.e., #|<[x]>|. *)
(* Operations on subsets/subgroups of a finite group: *)
(* H * G == {xy | x \in H, y \in G}. *)
(* 1 or [1] or [1 gT] == the unit group. *)
(* [set: gT]%G == the group of all x : gT (in Group_scope). *)
(* group_set G == G contains 1 and is closed under binary product; *)
(* this is the characteristic property of the *)
(* {group gT} subtype of {set gT}. *)
(* [subg G] == the subtype, set, or group of all x \in G: this *)
(* notation is defined simultaneously in %type, %g *)
(* and %G scopes, and G must denote a {group gT} *)
(* structure (G is in the %G scope). *)
(* subg, sgval == the projection into and injection from [subg G]. *)
(* H^# == the set H minus the unit element. *)
(* repr H == some element of H if 1 \notin H != set0, else 1. *)
(* (repr is defined over sets of a baseFinGroupType, *)
(* so it can be used, e.g., to pick right cosets.) *)
(* x *: H == left coset of H by x. *)
(* lcosets H G == the set of the left cosets of H by elements of G. *)
(* H :* x == right coset of H by x. *)
(* rcosets H G == the set of the right cosets of H by elements of G. *)
(* #|G : H| == the index of H in G, i.e., #|rcosets G H|. *)
(* H :^ x == the conjugate of H by x. *)
(* x ^: H == the conjugate class of x in H. *)
(* classes G == the set of all conjugate classes of G. *)
(* G :^: H == {G :^ x | x \in H}. *)
(* class_support G H == {x ^ y | x \in G, y \in H}. *)
(* commg_set G H == {[~ x, y] | x \in G, y \in H}; NOT the commutator! *)
(* <<H>> == the subgroup generated by the set H. *)
(* [~: G, H] == the commmutator subgroup of G and H, i.e., *)
(* <<commg_set G H>>>. *)
(* [~: H1, ..., Hn] == commutator subgroup of H1, ..., Hn (left assoc.). *)
(* H <*> G == the subgroup generated by sets H and G (H join G). *)
(* (H * G)%G == the join of G H : {group gT} (convertible, but not *)
(* identical to (G <*> H)%G). *)
(* (\prod_(i ...) H i)%G == the group generated by the H i. *)
(* {in G, centralised H} <-> G centralises H. *)
(* {in G, normalised H} <-> G normalises H. *)
(* <-> forall x, x \in G -> H :^ x = H. *)
(* 'N(H) == the normaliser of H. *)
(* 'N_G(H) == the normaliser of H in G. *)
(* H <| G <=> H is a normal subgroup of G. *)
(* 'C(H) == the centraliser of H. *)
(* 'C_G(H) == the centraliser of H in G. *)
(* gcore H G == the largest subgroup of H normalised by G. *)
(* If H is a subgroup of G, this is the largest *)
(* normal subgroup of G contained in H). *)
(* abelian H <=> H is abelian. *)
(* subgroups G == the set of subgroups of G, i.e., the set of all *)
(* H : {group gT} such that H \subset G. *)
(* In the notation below G is a variable that is bound in P. *)
(* [max G | P] <=> G is the largest group such that P holds. *)
(* [max H of G | P] <=> H is the largest group G such that P holds. *)
(* [max G | P & Q] := [max G | P && Q], likewise [max H of G | P & Q]. *)
(* [min G | P] <=> G is the smallest group such that P holds. *)
(* [min G | P & Q] := [min G | P && Q], likewise [min H of G | P & Q]. *)
(* [min H of G | P] <=> H is the smallest group G such that P holds. *)
(* In addition to the generic suffixes described in ssrbool.v and finset.v, *)
(* we associate the following suffixes to group operations: *)
(* 1 - identity element, as in group1 : 1 \in G. *)
(* M - multiplication, as is invMg : (x * y)^-1 = y^-1 * x^-1. *)
(* Also nat multiplication, for expgM : x ^+ (m * n) = x ^+ m ^+ n. *)
(* D - (nat) addition, for expgD : x ^+ (m + n) = x ^+ m * x ^+ n. *)
(* V - inverse, as in mulgV : x * x^-1 = 1. *)
(* X - exponentiation, as in conjXg : (x ^+ n) ^ y = (x ^ y) ^+ n. *)
(* J - conjugation, as in orderJ : #[x ^ y] = #[x]. *)
(* R - commutator, as in conjRg : [~ x, y] ^ z = [~ x ^ z, y ^ z]. *)
(* Y - join, as in centY : 'C(G <*> H) = 'C(G) :&: 'C(H). *)
(* We sometimes prefix these with an `s' to indicate a set-lifted operation, *)
(* e.g., conjsMg : (A * B) :^ x = A :^ x * B :^ x. *)
(******************************************************************************)
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Declare Scope group_scope.
Declare Scope Group_scope.
Delimit Scope group_scope with g.
Delimit Scope Group_scope with G.
(* This module can be imported to open the scope for group element *)
(* operations locally to a file, without exporting the Open to *)
(* clients of that file (as Open would do). *)
Module GroupScope.
Open Scope group_scope.
End GroupScope.
Import GroupScope.
(* These are the operation notations introduced by this file. *)
Reserved Notation "[ ~ x1 , x2 , .. , xn ]" (at level 0,
format "'[ ' [ ~ x1 , '/' x2 , '/' .. , '/' xn ] ']'").
Reserved Notation "[ 1 gT ]" (at level 0, format "[ 1 gT ]").
Reserved Notation "[ 1 ]" (at level 0, format "[ 1 ]").
Reserved Notation "[ 'subg' G ]" (at level 0, format "[ 'subg' G ]").
Reserved Notation "A ^#" (at level 2, format "A ^#").
Reserved Notation "A :^ x" (at level 35, right associativity).
Reserved Notation "x ^: B" (at level 35, right associativity).
Reserved Notation "A :^: B" (at level 35, right associativity).
Reserved Notation "#| B : A |" (at level 0, B, A at level 99,
format "#| B : A |").
Reserved Notation "''N' ( A )" (at level 8, format "''N' ( A )").
Reserved Notation "''N_' G ( A )" (at level 8, G at level 2,
format "''N_' G ( A )").
Reserved Notation "A <| B" (at level 70, no associativity).
Reserved Notation "A <*> B" (at level 40, left associativity).
Reserved Notation "[ ~: A1 , A2 , .. , An ]" (at level 0,
format "[ ~: '[' A1 , '/' A2 , '/' .. , '/' An ']' ]").
Reserved Notation "[ 'max' A 'of' G | gP ]" (at level 0,
format "[ '[hv' 'max' A 'of' G '/ ' | gP ']' ]").
Reserved Notation "[ 'max' G | gP ]" (at level 0,
format "[ '[hv' 'max' G '/ ' | gP ']' ]").
Reserved Notation "[ 'max' A 'of' G | gP & gQ ]" (at level 0,
format "[ '[hv' 'max' A 'of' G '/ ' | gP '/ ' & gQ ']' ]").
Reserved Notation "[ 'max' G | gP & gQ ]" (at level 0,
format "[ '[hv' 'max' G '/ ' | gP '/ ' & gQ ']' ]").
Reserved Notation "[ 'min' A 'of' G | gP ]" (at level 0,
format "[ '[hv' 'min' A 'of' G '/ ' | gP ']' ]").
Reserved Notation "[ 'min' G | gP ]" (at level 0,
format "[ '[hv' 'min' G '/ ' | gP ']' ]").
Reserved Notation "[ 'min' A 'of' G | gP & gQ ]" (at level 0,
format "[ '[hv' 'min' A 'of' G '/ ' | gP '/ ' & gQ ']' ]").
Reserved Notation "[ 'min' G | gP & gQ ]" (at level 0,
format "[ '[hv' 'min' G '/ ' | gP '/ ' & gQ ']' ]").
Module FinGroup.
(* We split the group axiomatisation in two. We define a *)
(* class of "base groups", which are basically monoids *)
(* with an involutive antimorphism, from which we derive *)
(* the class of groups proper. This allows use to reuse *)
(* much of the group notation and algebraic axioms for *)
(* group subsets, by defining a base group class on them. *)
(* We use class/mixins here rather than telescopes to *)
(* be able to interoperate with the type coercions. *)
(* Another potential benefit (not exploited here) would *)
(* be to define a class for infinite groups, which could *)
(* share all of the algebraic laws. *)
Record mixin_of (T : Type) : Type := BaseMixin {
mul : T -> T -> T;
one : T;
inv : T -> T;
_ : associative mul;
_ : left_id one mul;
_ : involutive inv;
_ : {morph inv : x y / mul x y >-> mul y x}
}.
Structure base_type : Type := PackBase {
sort : Type;
_ : mixin_of sort;
_ : Finite.class_of sort
}.
(* We want to use sort as a coercion class, both to infer *)
(* argument scopes properly, and to allow groups and cosets to *)
(* coerce to the base group of group subsets. *)
(* However, the return type of group operations should NOT be a *)
(* coercion class, since this would trump the real (head-normal) *)
(* coercion class for concrete group types, thus spoiling the *)
(* coercion of A * B to pred_sort in x \in A * B, or rho * tau to *)
(* ffun and Funclass in (rho * tau) x, when rho tau : perm T. *)
(* Therefore we define an alias of sort for argument types, and *)
(* make it the default coercion FinGroup.base_type >-> Sortclass *)
(* so that arguments of a functions whose parameters are of type, *)
(* say, gT : finGroupType, can be coerced to the coercion class *)
(* of arg_sort. Care should be taken, however, to declare the *)
(* return type of functions and operators as FinGroup.sort gT *)
(* rather than gT, e.g., mulg : gT -> gT -> FinGroup.sort gT. *)
(* Note that since we do this here and in quotient.v for all the *)
(* basic functions, the inferred return type should generally be *)
(* correct. *)
Definition arg_sort := sort.
Definition mixin T :=
let: PackBase _ m _ := T return mixin_of (sort T) in m.
Definition finClass T :=
let: PackBase _ _ m := T return Finite.class_of (sort T) in m.
Structure type : Type := Pack {
base : base_type;
_ : left_inverse (one (mixin base)) (inv (mixin base)) (mul (mixin base))
}.
(* We only need three axioms to make a true group. *)
Section Mixin.
Variables (T : Type) (one : T) (mul : T -> T -> T) (inv : T -> T).
Hypothesis mulA : associative mul.
Hypothesis mul1 : left_id one mul.
Hypothesis mulV : left_inverse one inv mul.
Notation "1" := one.
Infix "*" := mul.
Notation "x ^-1" := (inv x).
Lemma mk_invgK : involutive inv.
Proof.
have mulV21 x: x^-1^-1 * 1 = x by rewrite -(mulV x) mulA mulV mul1.
by move=> x; rewrite -[_ ^-1]mulV21 -(mul1 1) mulA !mulV21.
Qed.
Lemma mk_invMg : {morph inv : x y / x * y >-> y * x}.
Proof.
have mulxV x: x * x^-1 = 1 by rewrite -{1}[x]mk_invgK mulV.
move=> x y /=; rewrite -[y^-1 * _]mul1 -(mulV (x * y)) -2!mulA (mulA y).
by rewrite mulxV mul1 mulxV -(mulxV (x * y)) mulA mulV mul1.
Qed.
Definition Mixin := BaseMixin mulA mul1 mk_invgK mk_invMg.
End Mixin.
Definition pack_base T m :=
fun c cT & phant_id (Finite.class cT) c => @PackBase T m c.
Definition clone_base T :=
fun bT & sort bT -> T =>
fun m c (bT' := @PackBase T m c) & phant_id bT' bT => bT'.
Definition clone T :=
fun bT gT & sort bT * sort (base gT) -> T * T =>
fun m (gT' := @Pack bT m) & phant_id gT' gT => gT'.
Section InheritedClasses.
Variable bT : base_type.
Local Notation T := (arg_sort bT).
Local Notation rT := (sort bT).
Local Notation class := (finClass bT).
Canonical eqType := Equality.Pack class.
Canonical choiceType := Choice.Pack class.
Canonical countType := Countable.Pack class.
Canonical finType := Finite.Pack class.
Definition arg_eqType := Eval hnf in [eqType of T].
Definition arg_choiceType := Eval hnf in [choiceType of T].
Definition arg_countType := Eval hnf in [countType of T].
Definition arg_finType := Eval hnf in [finType of T].
End InheritedClasses.
Module Import Exports.
(* Declaring sort as a Coercion is clearly redundant; it only *)
(* serves the purpose of eliding FinGroup.sort in the display of *)
(* return types. The warning could be eliminated by using the *)
(* functor trick to replace Sortclass by a dummy target. *)
Coercion arg_sort : base_type >-> Sortclass.
Coercion sort : base_type >-> Sortclass.
Coercion mixin : base_type >-> mixin_of.
Coercion base : type >-> base_type.
Canonical eqType.
Canonical choiceType.
Canonical countType.
Canonical finType.
Coercion arg_eqType : base_type >-> Equality.type.
Canonical arg_eqType.
Coercion arg_choiceType : base_type >-> Choice.type.
Canonical arg_choiceType.
Coercion arg_countType : base_type >-> Countable.type.
Canonical arg_countType.
Coercion arg_finType : base_type >-> Finite.type.
Canonical arg_finType.
Bind Scope group_scope with sort.
Bind Scope group_scope with arg_sort.
Notation baseFinGroupType := base_type.
Notation finGroupType := type.
Notation BaseFinGroupType T m := (@pack_base T m _ _ id).
Notation FinGroupType := Pack.
Notation "[ 'baseFinGroupType' 'of' T ]" := (@clone_base T _ id _ _ id)
(at level 0, format "[ 'baseFinGroupType' 'of' T ]") : form_scope.
Notation "[ 'finGroupType' 'of' T ]" := (@clone T _ _ id _ id)
(at level 0, format "[ 'finGroupType' 'of' T ]") : form_scope.
End Exports.
End FinGroup.
Export FinGroup.Exports.
Section ElementOps.
Variable T : baseFinGroupType.
Notation rT := (FinGroup.sort T).
Definition oneg : rT := FinGroup.one T.
Definition mulg : T -> T -> rT := FinGroup.mul T.
Definition invg : T -> rT := FinGroup.inv T.
Definition expgn_rec (x : T) n : rT := iterop n mulg x oneg.
End ElementOps.
Definition expgn := nosimpl expgn_rec.
Notation "1" := (oneg _) : group_scope.
Notation "x1 * x2" := (mulg x1 x2) : group_scope.
Notation "x ^-1" := (invg x) : group_scope.
Notation "x ^+ n" := (expgn x n) : group_scope.
Notation "x ^- n" := (x ^+ n)^-1 : group_scope.
(* Arguments of conjg are restricted to true groups to avoid an *)
(* improper interpretation of A ^ B with A and B sets, namely: *)
(* {x^-1 * (y * z) | y \in A, x, z \in B} *)
Definition conjg (T : finGroupType) (x y : T) := y^-1 * (x * y).
Notation "x1 ^ x2" := (conjg x1 x2) : group_scope.
Definition commg (T : finGroupType) (x y : T) := x^-1 * x ^ y.
Notation "[ ~ x1 , x2 , .. , xn ]" := (commg .. (commg x1 x2) .. xn)
: group_scope.
Prenex Implicits mulg invg expgn conjg commg.
Notation "\prod_ ( i <- r | P ) F" :=
(\big[mulg/1]_(i <- r | P%B) F%g) : group_scope.
Notation "\prod_ ( i <- r ) F" :=
(\big[mulg/1]_(i <- r) F%g) : group_scope.
Notation "\prod_ ( m <= i < n | P ) F" :=
(\big[mulg/1]_(m <= i < n | P%B) F%g) : group_scope.
Notation "\prod_ ( m <= i < n ) F" :=
(\big[mulg/1]_(m <= i < n) F%g) : group_scope.
Notation "\prod_ ( i | P ) F" :=
(\big[mulg/1]_(i | P%B) F%g) : group_scope.
Notation "\prod_ i F" :=
(\big[mulg/1]_i F%g) : group_scope.
Notation "\prod_ ( i : t | P ) F" :=
(\big[mulg/1]_(i : t | P%B) F%g) (only parsing) : group_scope.
Notation "\prod_ ( i : t ) F" :=
(\big[mulg/1]_(i : t) F%g) (only parsing) : group_scope.
Notation "\prod_ ( i < n | P ) F" :=
(\big[mulg/1]_(i < n | P%B) F%g) : group_scope.
Notation "\prod_ ( i < n ) F" :=
(\big[mulg/1]_(i < n) F%g) : group_scope.
Notation "\prod_ ( i 'in' A | P ) F" :=
(\big[mulg/1]_(i in A | P%B) F%g) : group_scope.
Notation "\prod_ ( i 'in' A ) F" :=
(\big[mulg/1]_(i in A) F%g) : group_scope.
Section PreGroupIdentities.
Variable T : baseFinGroupType.
Implicit Types x y z : T.
Local Notation mulgT := (@mulg T).
Lemma mulgA : associative mulgT. Proof. by case: T => ? []. Qed.
Lemma mul1g : left_id 1 mulgT. Proof. by case: T => ? []. Qed.
Lemma invgK : @involutive T invg. Proof. by case: T => ? []. Qed.
Lemma invMg x y : (x * y)^-1 = y^-1 * x^-1. Proof. by case: T x y => ? []. Qed.
Lemma invg_inj : @injective T T invg. Proof. exact: can_inj invgK. Qed.
Lemma eq_invg_sym x y : (x^-1 == y) = (x == y^-1).
Proof. by apply: (inv_eq invgK). Qed.
Lemma invg1 : 1^-1 = 1 :> T.
Proof. by apply: invg_inj; rewrite -{1}[1^-1]mul1g invMg invgK mul1g. Qed.
Lemma eq_invg1 x : (x^-1 == 1) = (x == 1).
Proof. by rewrite eq_invg_sym invg1. Qed.
Lemma mulg1 : right_id 1 mulgT.
Proof. by move=> x; apply: invg_inj; rewrite invMg invg1 mul1g. Qed.
Canonical finGroup_law := Monoid.Law mulgA mul1g mulg1.
Lemma expgnE x n : x ^+ n = expgn_rec x n. Proof. by []. Qed.
Lemma expg0 x : x ^+ 0 = 1. Proof. by []. Qed.
Lemma expg1 x : x ^+ 1 = x. Proof. by []. Qed.
Lemma expgS x n : x ^+ n.+1 = x * x ^+ n.
Proof. by case: n => //; rewrite mulg1. Qed.
Lemma expg1n n : 1 ^+ n = 1 :> T.
Proof. by elim: n => // n IHn; rewrite expgS mul1g. Qed.
Lemma expgD x n m : x ^+ (n + m) = x ^+ n * x ^+ m.
Proof. by elim: n => [|n IHn]; rewrite ?mul1g // !expgS IHn mulgA. Qed.
Lemma expgSr x n : x ^+ n.+1 = x ^+ n * x.
Proof. by rewrite -addn1 expgD expg1. Qed.
Lemma expgM x n m : x ^+ (n * m) = x ^+ n ^+ m.
Proof.
elim: m => [|m IHm]; first by rewrite muln0 expg0.
by rewrite mulnS expgD IHm expgS.
Qed.
Lemma expgAC x m n : x ^+ m ^+ n = x ^+ n ^+ m.
Proof. by rewrite -!expgM mulnC. Qed.
Definition commute x y := x * y = y * x.
Lemma commute_refl x : commute x x.
Proof. by []. Qed.
Lemma commute_sym x y : commute x y -> commute y x.
Proof. by []. Qed.
Lemma commute1 x : commute x 1.
Proof. by rewrite /commute mulg1 mul1g. Qed.
Lemma commuteM x y z : commute x y -> commute x z -> commute x (y * z).
Proof. by move=> cxy cxz; rewrite /commute -mulgA -cxz !mulgA cxy. Qed.
Lemma commuteX x y n : commute x y -> commute x (y ^+ n).
Proof.
by move=> cxy; case: n; [apply: commute1 | elim=> // n; apply: commuteM].
Qed.
Lemma commuteX2 x y m n : commute x y -> commute (x ^+ m) (y ^+ n).
Proof. by move=> cxy; apply/commuteX/commute_sym/commuteX. Qed.
Lemma expgVn x n : x^-1 ^+ n = x ^- n.
Proof. by elim: n => [|n IHn]; rewrite ?invg1 // expgSr expgS invMg IHn. Qed.
Lemma expgMn x y n : commute x y -> (x * y) ^+ n = x ^+ n * y ^+ n.
Proof.
move=> cxy; elim: n => [|n IHn]; first by rewrite mulg1.
by rewrite !expgS IHn -mulgA (mulgA y) (commuteX _ (commute_sym cxy)) !mulgA.
Qed.
End PreGroupIdentities.
Hint Resolve commute1 : core.
Arguments invg_inj {T} [x1 x2].
Prenex Implicits commute invgK.
Section GroupIdentities.
Variable T : finGroupType.
Implicit Types x y z : T.
Local Notation mulgT := (@mulg T).
Lemma mulVg : left_inverse 1 invg mulgT.
Proof. by case T. Qed.
Lemma mulgV : right_inverse 1 invg mulgT.
Proof. by move=> x; rewrite -{1}(invgK x) mulVg. Qed.
Lemma mulKg : left_loop invg mulgT.
Proof. by move=> x y; rewrite mulgA mulVg mul1g. Qed.
Lemma mulKVg : rev_left_loop invg mulgT.
Proof. by move=> x y; rewrite mulgA mulgV mul1g. Qed.
Lemma mulgI : right_injective mulgT.
Proof. by move=> x; apply: can_inj (mulKg x). Qed.
Lemma mulgK : right_loop invg mulgT.
Proof. by move=> x y; rewrite -mulgA mulgV mulg1. Qed.
Lemma mulgKV : rev_right_loop invg mulgT.
Proof. by move=> x y; rewrite -mulgA mulVg mulg1. Qed.
Lemma mulIg : left_injective mulgT.
Proof. by move=> x; apply: can_inj (mulgK x). Qed.
Lemma eq_invg_mul x y : (x^-1 == y :> T) = (x * y == 1 :> T).
Proof. by rewrite -(inj_eq (@mulgI x)) mulgV eq_sym. Qed.
Lemma eq_mulgV1 x y : (x == y) = (x * y^-1 == 1 :> T).
Proof. by rewrite -(inj_eq invg_inj) eq_invg_mul. Qed.
Lemma eq_mulVg1 x y : (x == y) = (x^-1 * y == 1 :> T).
Proof. by rewrite -eq_invg_mul invgK. Qed.
Lemma commuteV x y : commute x y -> commute x y^-1.
Proof. by move=> cxy; apply: (@mulIg y); rewrite mulgKV -mulgA cxy mulKg. Qed.
Lemma conjgE x y : x ^ y = y^-1 * (x * y). Proof. by []. Qed.
Lemma conjgC x y : x * y = y * x ^ y.
Proof. by rewrite mulKVg. Qed.
Lemma conjgCV x y : x * y = y ^ x^-1 * x.
Proof. by rewrite -mulgA mulgKV invgK. Qed.
Lemma conjg1 x : x ^ 1 = x.
Proof. by rewrite conjgE commute1 mulKg. Qed.
Lemma conj1g x : 1 ^ x = 1.
Proof. by rewrite conjgE mul1g mulVg. Qed.
Lemma conjMg x y z : (x * y) ^ z = x ^ z * y ^ z.
Proof. by rewrite !conjgE !mulgA mulgK. Qed.
Lemma conjgM x y z : x ^ (y * z) = (x ^ y) ^ z.
Proof. by rewrite !conjgE invMg !mulgA. Qed.
Lemma conjVg x y : x^-1 ^ y = (x ^ y)^-1.
Proof. by rewrite !conjgE !invMg invgK mulgA. Qed.
Lemma conjJg x y z : (x ^ y) ^ z = (x ^ z) ^ y ^ z.
Proof. by rewrite 2!conjMg conjVg. Qed.
Lemma conjXg x y n : (x ^+ n) ^ y = (x ^ y) ^+ n.
Proof. by elim: n => [|n IHn]; rewrite ?conj1g // !expgS conjMg IHn. Qed.
Lemma conjgK : @right_loop T T invg conjg.
Proof. by move=> y x; rewrite -conjgM mulgV conjg1. Qed.
Lemma conjgKV : @rev_right_loop T T invg conjg.
Proof. by move=> y x; rewrite -conjgM mulVg conjg1. Qed.
Lemma conjg_inj : @left_injective T T T conjg.
Proof. by move=> y; apply: can_inj (conjgK y). Qed.
Lemma conjg_eq1 x y : (x ^ y == 1) = (x == 1).
Proof. by rewrite (canF_eq (conjgK _)) conj1g. Qed.
Lemma conjg_prod I r (P : pred I) F z :
(\prod_(i <- r | P i) F i) ^ z = \prod_(i <- r | P i) (F i ^ z).
Proof.
by apply: (big_morph (conjg^~ z)) => [x y|]; rewrite ?conj1g ?conjMg.
Qed.
Lemma commgEl x y : [~ x, y] = x^-1 * x ^ y. Proof. by []. Qed.
Lemma commgEr x y : [~ x, y] = y^-1 ^ x * y.
Proof. by rewrite -!mulgA. Qed.
Lemma commgC x y : x * y = y * x * [~ x, y].
Proof. by rewrite -mulgA !mulKVg. Qed.
Lemma commgCV x y : x * y = [~ x^-1, y^-1] * (y * x).
Proof. by rewrite commgEl !mulgA !invgK !mulgKV. Qed.
Lemma conjRg x y z : [~ x, y] ^ z = [~ x ^ z, y ^ z].
Proof. by rewrite !conjMg !conjVg. Qed.
Lemma invg_comm x y : [~ x, y]^-1 = [~ y, x].
Proof. by rewrite commgEr conjVg invMg invgK. Qed.
Lemma commgP x y : reflect (commute x y) ([~ x, y] == 1 :> T).
Proof. by rewrite [[~ x, y]]mulgA -invMg -eq_mulVg1 eq_sym; apply: eqP. Qed.
Lemma conjg_fixP x y : reflect (x ^ y = x) ([~ x, y] == 1 :> T).
Proof. by rewrite -eq_mulVg1 eq_sym; apply: eqP. Qed.
Lemma commg1_sym x y : ([~ x, y] == 1 :> T) = ([~ y, x] == 1 :> T).
Proof. by rewrite -invg_comm (inv_eq invgK) invg1. Qed.
Lemma commg1 x : [~ x, 1] = 1.
Proof. exact/eqP/commgP. Qed.
Lemma comm1g x : [~ 1, x] = 1.
Proof. by rewrite -invg_comm commg1 invg1. Qed.
Lemma commgg x : [~ x, x] = 1.
Proof. exact/eqP/commgP. Qed.
Lemma commgXg x n : [~ x, x ^+ n] = 1.
Proof. exact/eqP/commgP/commuteX. Qed.
Lemma commgVg x : [~ x, x^-1] = 1.
Proof. exact/eqP/commgP/commuteV. Qed.
Lemma commgXVg x n : [~ x, x ^- n] = 1.
Proof. exact/eqP/commgP/commuteV/commuteX. Qed.
(* Other commg identities should slot in here. *)
End GroupIdentities.
Hint Rewrite mulg1 mul1g invg1 mulVg mulgV (@invgK) mulgK mulgKV
invMg mulgA : gsimpl.
Ltac gsimpl := autorewrite with gsimpl; try done.
Definition gsimp := (mulg1 , mul1g, (invg1, @invgK), (mulgV, mulVg)).
Definition gnorm := (gsimp, (mulgK, mulgKV, (mulgA, invMg))).
Arguments mulgI [T].
Arguments mulIg [T].
Arguments conjg_inj {T} x [x1 x2].
Arguments commgP {T x y}.
Arguments conjg_fixP {T x y}.
Section Repr.
(* Plucking a set representative. *)
Variable gT : baseFinGroupType.
Implicit Type A : {set gT}.
Definition repr A := if 1 \in A then 1 else odflt 1 [pick x in A].
Lemma mem_repr A x : x \in A -> repr A \in A.
Proof.
by rewrite /repr; case: ifP => // _; case: pickP => // A0; rewrite [x \in A]A0.
Qed.
Lemma card_mem_repr A : #|A| > 0 -> repr A \in A.
Proof. by rewrite lt0n => /existsP[x]; apply: mem_repr. Qed.
Lemma repr_set1 x : repr [set x] = x.
Proof. by apply/set1P/card_mem_repr; rewrite cards1. Qed.
Lemma repr_set0 : repr set0 = 1.
Proof. by rewrite /repr; case: pickP => [x|_]; rewrite !inE. Qed.
End Repr.
Arguments mem_repr [gT A].
Section BaseSetMulDef.
(* We only assume a baseFinGroupType to allow this construct to be iterated. *)
Variable gT : baseFinGroupType.
Implicit Types A B : {set gT}.
(* Set-lifted group operations. *)
Definition set_mulg A B := mulg @2: (A, B).
Definition set_invg A := invg @^-1: A.
(* The pre-group structure of group subsets. *)
Lemma set_mul1g : left_id [set 1] set_mulg.
Proof.
move=> A; apply/setP=> y; apply/imset2P/idP=> [[_ x /set1P-> Ax ->] | Ay].
by rewrite mul1g.
by exists (1 : gT) y; rewrite ?(set11, mul1g).
Qed.
Lemma set_mulgA : associative set_mulg.
Proof.
move=> A B C; apply/setP=> y.
apply/imset2P/imset2P=> [[x1 z Ax1 /imset2P[x2 x3 Bx2 Cx3 ->] ->]| [z x3]].
by exists (x1 * x2) x3; rewrite ?mulgA //; apply/imset2P; exists x1 x2.
case/imset2P=> x1 x2 Ax1 Bx2 -> Cx3 ->.
by exists x1 (x2 * x3); rewrite ?mulgA //; apply/imset2P; exists x2 x3.
Qed.
Lemma set_invgK : involutive set_invg.
Proof. by move=> A; apply/setP=> x; rewrite !inE invgK. Qed.
Lemma set_invgM : {morph set_invg : A B / set_mulg A B >-> set_mulg B A}.
Proof.
move=> A B; apply/setP=> z; rewrite inE.
apply/imset2P/imset2P=> [[x y Ax By /(canRL invgK)->] | [y x]].
by exists y^-1 x^-1; rewrite ?invMg // inE invgK.
by rewrite !inE => By1 Ax1 ->; exists x^-1 y^-1; rewrite ?invMg.
Qed.
Definition group_set_baseGroupMixin : FinGroup.mixin_of (set_type gT) :=
FinGroup.BaseMixin set_mulgA set_mul1g set_invgK set_invgM.
Canonical group_set_baseGroupType :=
Eval hnf in BaseFinGroupType (set_type gT) group_set_baseGroupMixin.
Canonical group_set_of_baseGroupType :=
Eval hnf in [baseFinGroupType of {set gT}].
End BaseSetMulDef.
(* Time to open the bag of dirty tricks. When we define groups down below *)
(* as a subtype of {set gT}, we need them to be able to coerce to sets in *)
(* both set-style contexts (x \in G) and monoid-style contexts (G * H), *)
(* and we need the coercion function to be EXACTLY the structure *)
(* projection in BOTH cases -- otherwise the canonical unification breaks.*)
(* Alas, Coq doesn't let us use the same coercion function twice, even *)
(* when the targets are convertible. Our workaround (ab)uses the module *)
(* system to declare two different identity coercions on an alias class. *)
Module GroupSet.
Definition sort (gT : baseFinGroupType) := {set gT}.
End GroupSet.
Identity Coercion GroupSet_of_sort : GroupSet.sort >-> set_of.
Module Type GroupSetBaseGroupSig.
Definition sort gT := group_set_of_baseGroupType gT : Type.
End GroupSetBaseGroupSig.
Module MakeGroupSetBaseGroup (Gset_base : GroupSetBaseGroupSig).
Identity Coercion of_sort : Gset_base.sort >-> FinGroup.arg_sort.
End MakeGroupSetBaseGroup.
Module Export GroupSetBaseGroup := MakeGroupSetBaseGroup GroupSet.
Canonical group_set_eqType gT := Eval hnf in [eqType of GroupSet.sort gT].
Canonical group_set_choiceType gT :=
Eval hnf in [choiceType of GroupSet.sort gT].
Canonical group_set_countType gT := Eval hnf in [countType of GroupSet.sort gT].
Canonical group_set_finType gT := Eval hnf in [finType of GroupSet.sort gT].
Section GroupSetMulDef.
(* Some of these constructs could be defined on a baseFinGroupType. *)
(* We restrict them to proper finGroupType because we only develop *)
(* the theory for that case. *)
Variable gT : finGroupType.
Implicit Types A B : {set gT}.
Implicit Type x y : gT.
Definition lcoset A x := mulg x @: A.
Definition rcoset A x := mulg^~ x @: A.
Definition lcosets A B := lcoset A @: B.
Definition rcosets A B := rcoset A @: B.
Definition indexg B A := #|rcosets A B|.
Definition conjugate A x := conjg^~ x @: A.
Definition conjugates A B := conjugate A @: B.
Definition class x B := conjg x @: B.
Definition classes A := class^~ A @: A.
Definition class_support A B := conjg @2: (A, B).
Definition commg_set A B := commg @2: (A, B).
(* These will only be used later, but are defined here so that we can *)
(* keep all the Notation together. *)
Definition normaliser A := [set x | conjugate A x \subset A].
Definition centraliser A := \bigcap_(x in A) normaliser [set x].
Definition abelian A := A \subset centraliser A.
Definition normal A B := (A \subset B) && (B \subset normaliser A).
(* "normalised" and "centralise[s|d]" are intended to be used with *)
(* the {in ...} form, as in abelian below. *)
Definition normalised A := forall x, conjugate A x = A.
Definition centralises x A := forall y, y \in A -> commute x y.
Definition centralised A := forall x, centralises x A.
End GroupSetMulDef.
Arguments lcoset _ _%g _%g.
Arguments rcoset _ _%g _%g.
Arguments rcosets _ _%g _%g.
Arguments lcosets _ _%g _%g.
Arguments indexg _ _%g _%g.
Arguments conjugate _ _%g _%g.
Arguments conjugates _ _%g _%g.
Arguments class _ _%g _%g.
Arguments classes _ _%g.
Arguments class_support _ _%g _%g.
Arguments commg_set _ _%g _%g.
Arguments normaliser _ _%g.
Arguments centraliser _ _%g.
Arguments abelian _ _%g.
Arguments normal _ _%g _%g.
Arguments normalised _ _%g.
Arguments centralises _ _%g _%g.
Arguments centralised _ _%g.
Notation "[ 1 gT ]" := (1 : {set gT}) : group_scope.
Notation "[ 1 ]" := [1 FinGroup.sort _] : group_scope.
Notation "A ^#" := (A :\ 1) : group_scope.
Notation "x *: A" := ([set x%g] * A) : group_scope.
Notation "A :* x" := (A * [set x%g]) : group_scope.
Notation "A :^ x" := (conjugate A x) : group_scope.
Notation "x ^: B" := (class x B) : group_scope.
Notation "A :^: B" := (conjugates A B) : group_scope.
Notation "#| B : A |" := (indexg B A) : group_scope.
(* No notation for lcoset and rcoset, which are to be used mostly *)
(* in curried form; x *: B and A :* 1 denote singleton products, *)
(* so we can use mulgA, mulg1, etc, on, say, A :* 1 * B :* x. *)
(* No notation for the set commutator generator set commg_set. *)
Notation "''N' ( A )" := (normaliser A) : group_scope.
Notation "''N_' G ( A )" := (G%g :&: 'N(A)) : group_scope.
Notation "A <| B" := (normal A B) : group_scope.
Notation "''C' ( A )" := (centraliser A) : group_scope.
Notation "''C_' G ( A )" := (G%g :&: 'C(A)) : group_scope.
Notation "''C_' ( G ) ( A )" := 'C_G(A) (only parsing) : group_scope.
Notation "''C' [ x ]" := 'N([set x%g]) : group_scope.
Notation "''C_' G [ x ]" := 'N_G([set x%g]) : group_scope.
Notation "''C_' ( G ) [ x ]" := 'C_G[x] (only parsing) : group_scope.
Prenex Implicits repr lcoset rcoset lcosets rcosets normal.
Prenex Implicits conjugate conjugates class classes class_support.
Prenex Implicits commg_set normalised centralised abelian.
Section BaseSetMulProp.
(* Properties of the purely multiplicative structure. *)
Variable gT : baseFinGroupType.
Implicit Types A B C D : {set gT}.
Implicit Type x y z : gT.
(* Set product. We already have all the pregroup identities, so we *)
(* only need to add the monotonicity rules. *)
Lemma mulsgP A B x :
reflect (imset2_spec mulg (mem A) (fun _ => mem B) x) (x \in A * B).
Proof. exact: imset2P. Qed.
Lemma mem_mulg A B x y : x \in A -> y \in B -> x * y \in A * B.
Proof. by move=> Ax By; apply/mulsgP; exists x y. Qed.
Lemma prodsgP (I : finType) (P : pred I) (A : I -> {set gT}) x :
reflect (exists2 c, forall i, P i -> c i \in A i & x = \prod_(i | P i) c i)
(x \in \prod_(i | P i) A i).
Proof.
have [r big_r [Ur mem_r] _] := big_enumP P.
pose inA c := all (fun i => c i \in A i); rewrite -big_r; set piAx := x \in _.
suffices{big_r} IHr: reflect (exists2 c, inA c r & x = \prod_(i <- r) c i) piAx.
apply: (iffP IHr) => -[c inAc ->]; do [exists c; last by rewrite big_r].
by move=> i Pi; rewrite (allP inAc) ?mem_r.
by apply/allP=> i; rewrite mem_r => /inAc.
elim: {P mem_r}r x @piAx Ur => /= [x _ | i r IHr x /andP[r'i /IHr{}IHr]].
by rewrite unlock; apply: (iffP set1P) => [-> | [] //]; exists (fun=> x).
rewrite big_cons; apply: (iffP idP) => [|[c /andP[Aci Ac] ->]]; last first.
by rewrite big_cons mem_mulg //; apply/IHr=> //; exists c.
case/mulsgP=> c_i _ Ac_i /IHr[c /allP-inAcr ->] ->{x}.
exists [eta c with i |-> c_i]; rewrite /= ?big_cons eqxx ?Ac_i.
by apply/allP=> j rj; rewrite /= ifN ?(memPn r'i) ?inAcr.
by congr (_ * _); apply: eq_big_seq => j rj; rewrite ifN ?(memPn r'i).
Qed.
Lemma mem_prodg (I : finType) (P : pred I) (A : I -> {set gT}) c :
(forall i, P i -> c i \in A i) -> \prod_(i | P i) c i \in \prod_(i | P i) A i.
Proof. by move=> Ac; apply/prodsgP; exists c. Qed.
Lemma mulSg A B C : A \subset B -> A * C \subset B * C.
Proof. exact: imset2Sl. Qed.
Lemma mulgS A B C : B \subset C -> A * B \subset A * C.
Proof. exact: imset2Sr. Qed.
Lemma mulgSS A B C D : A \subset B -> C \subset D -> A * C \subset B * D.
Proof. exact: imset2S. Qed.
Lemma mulg_subl A B : 1 \in B -> A \subset A * B.
Proof. by move=> B1; rewrite -{1}(mulg1 A) mulgS ?sub1set. Qed.
Lemma mulg_subr A B : 1 \in A -> B \subset A * B.
Proof. by move=> A1; rewrite -{1}(mul1g B) mulSg ?sub1set. Qed.
Lemma mulUg A B C : (A :|: B) * C = (A * C) :|: (B * C).
Proof. exact: imset2Ul. Qed.
Lemma mulgU A B C : A * (B :|: C) = (A * B) :|: (A * C).
Proof. exact: imset2Ur. Qed.
(* Set (pointwise) inverse. *)
Lemma invUg A B : (A :|: B)^-1 = A^-1 :|: B^-1.
Proof. exact: preimsetU. Qed.
Lemma invIg A B : (A :&: B)^-1 = A^-1 :&: B^-1.
Proof. exact: preimsetI. Qed.
Lemma invDg A B : (A :\: B)^-1 = A^-1 :\: B^-1.
Proof. exact: preimsetD. Qed.
Lemma invCg A : (~: A)^-1 = ~: A^-1.
Proof. exact: preimsetC. Qed.
Lemma invSg A B : (A^-1 \subset B^-1) = (A \subset B).
Proof. by rewrite !(sameP setIidPl eqP) -invIg (inj_eq invg_inj). Qed.
Lemma mem_invg x A : (x \in A^-1) = (x^-1 \in A).
Proof. by rewrite inE. Qed.
Lemma memV_invg x A : (x^-1 \in A^-1) = (x \in A).
Proof. by rewrite inE invgK. Qed.
Lemma card_invg A : #|A^-1| = #|A|.
Proof. exact/card_preimset/invg_inj. Qed.
(* Product with singletons. *)
Lemma set1gE : 1 = [set 1] :> {set gT}. Proof. by []. Qed.
Lemma set1gP x : reflect (x = 1) (x \in [1]).
Proof. exact: set1P. Qed.
Lemma mulg_set1 x y : [set x] :* y = [set x * y].
Proof. by rewrite [_ * _]imset2_set1l imset_set1. Qed.
Lemma invg_set1 x : [set x]^-1 = [set x^-1].
Proof. by apply/setP=> y; rewrite !inE inv_eq //; apply: invgK. Qed.
End BaseSetMulProp.
Arguments set1gP {gT x}.
Arguments mulsgP {gT A B x}.
Arguments prodsgP {gT I P A x}.
Section GroupSetMulProp.
(* Constructs that need a finGroupType *)
Variable gT : finGroupType.
Implicit Types A B C D : {set gT}.
Implicit Type x y z : gT.
(* Left cosets. *)
Lemma lcosetE A x : lcoset A x = x *: A.
Proof. by rewrite [_ * _]imset2_set1l. Qed.
Lemma card_lcoset A x : #|x *: A| = #|A|.
Proof. by rewrite -lcosetE (card_imset _ (mulgI _)). Qed.
Lemma mem_lcoset A x y : (y \in x *: A) = (x^-1 * y \in A).
Proof. by rewrite -lcosetE [_ x](can_imset_pre _ (mulKg _)) inE. Qed.
Lemma lcosetP A x y : reflect (exists2 a, a \in A & y = x * a) (y \in x *: A).
Proof. by rewrite -lcosetE; apply: imsetP. Qed.
Lemma lcosetsP A B C :
reflect (exists2 x, x \in B & C = x *: A) (C \in lcosets A B).
Proof. by apply: (iffP imsetP) => [] [x Bx ->]; exists x; rewrite ?lcosetE. Qed.
Lemma lcosetM A x y : (x * y) *: A = x *: (y *: A).
Proof. by rewrite -mulg_set1 mulgA. Qed.
Lemma lcoset1 A : 1 *: A = A.
Proof. exact: mul1g. Qed.
Lemma lcosetK : left_loop invg (fun x A => x *: A).
Proof. by move=> x A; rewrite -lcosetM mulVg mul1g. Qed.
Lemma lcosetKV : rev_left_loop invg (fun x A => x *: A).
Proof. by move=> x A; rewrite -lcosetM mulgV mul1g. Qed.
Lemma lcoset_inj : right_injective (fun x A => x *: A).
Proof. by move=> x; apply: can_inj (lcosetK x). Qed.
Lemma lcosetS x A B : (x *: A \subset x *: B) = (A \subset B).
Proof.
apply/idP/idP=> sAB; last exact: mulgS.
by rewrite -(lcosetK x A) -(lcosetK x B) mulgS.
Qed.
Lemma sub_lcoset x A B : (A \subset x *: B) = (x^-1 *: A \subset B).
Proof. by rewrite -(lcosetS x^-1) lcosetK. Qed.
Lemma sub_lcosetV x A B : (A \subset x^-1 *: B) = (x *: A \subset B).
Proof. by rewrite sub_lcoset invgK. Qed.
(* Right cosets. *)