1##############################################################################
2##
3#W  isoclinic.gi               GAP4 package `XMod'                Alper Odabas
4#W                                                                & Enver Uslu
5#Y  Copyright (C) 2001-2019, Chris Wensley et al
6#Y
7##  This file contains generic methods for finding isoclinism classes
8##  of crossed modules.
9##
10
11#############################################################################
12##
13#M  FixedPointSubgroupXMod . . . . elements of the range fixed by the source
14##
15InstallMethod( FixedPointSubgroupXMod, "generic method for precrossed modules",
16    true, [ IsPreXMod, IsGroup, IsGroup ], 0,
17function( XM, T, Q )
18
19    local genQ, act, ext, orb, elts, fix, gens;
20
21    if not ( IsSubgroup( Source(XM), T ) and IsSubgroup( Range(XM), Q ) ) then
22        Error( "T,Q not subgroups of S,R" );
23    fi;
24    genQ := GeneratorsOfGroup( Q );
25    act := XModAction( XM );
26    ext := ExternalSet( Q, T, genQ, List( genQ, g -> ImageElm(act,g) ) );
27    orb := Orbits( ext );
28    elts := Concatenation( Filtered( orb, o -> Length(o) = 1) );
29    fix := Subgroup( T, elts );
30    gens := SmallGeneratingSet( fix );
31    return Subgroup( T, gens );
32end );
33
34#############################################################################
35##
36#M  StabilizerSubgroupXMod . . . . elements of Q<=R which fix T<=S pointwise
37##
38InstallMethod( StabilizerSubgroupXMod,
39    "generic method for a crossed module and subgroups of source, range",
40    true, [ IsPreXMod, IsGroup, IsGroup ], 0,
41function( XM, T, Q )
42
43    local alpha, sonuc, t, q, list, sgp;
44
45    if not ( IsSubgroup( Source(XM), T ) and IsSubgroup( Range(XM), Q ) ) then
46        Error( "T,Q not subgroups of S,R" );
47    fi;
48    alpha := XModAction( XM );
49    list := [];
50    for q in Q do
51        if ForAll( T, t -> ImageElm(ImageElm(alpha,q),t)=t ) then
52            Add( list, q );
53        fi;
54    od;
55    ##  if the lists consist only the identity element then there is a bug
56    ##  in the function AsMagma.
57    if ( Length( Set(list) ) = 1 ) then
58        return TrivialSubgroup( Q );
59    fi;
60    sgp := Subgroup( Q, list );
61    sgp := Subgroup( Q, SmallGeneratingSet(sgp) );
62    return sgp;
63end );
64
65#############################################################################
66##
67#M  CentreXMod  . . . . . . . . . the centre of a crossed module
68##
69InstallMethod( CentreXMod, "generic method for crossed modules", true,
70    [ IsXMod ], 0,
71function( XM )
72
73    local T, G, K, fix;
74
75    T := Source( XM );
76    G := Range( XM );
77    K := Intersection( Centre(G), StabilizerSubgroupXMod( XM, T, G ) );
78    fix := FixedPointSubgroupXMod( XM, T, G );
79    return SubXMod( XM, fix, K );
80end );
81
82#############################################################################
83##
84#M  Centralizer  . . . . . . . . for a subcrossed module of a crossed module
85##
86InstallOtherMethod( Centralizer, "generic method for crossed modules", true,
87    [ IsXMod, IsXMod ], 0,
88function( XM, YM )
89
90    local srcX, rngY, genR, actY, ext, orb, elts, fix, gens, srcC, rngC;
91
92    if not IsSubXMod( XM, YM ) then
93        Error( "YM is not a subcrossed module of XM" );
94    fi;
95    srcX := Source( XM );
96    rngY := Range( YM  );
97    genR := GeneratorsOfGroup( rngY );
98    actY := XModAction( YM );
99    ext := ExternalSet( rngY, srcX, genR, List( genR, g -> ImageElm(actY,g) ) );
100    orb := Orbits( ExternalSetXMod( XM ) );
101    elts := Concatenation( Filtered( orb, o -> Length(o) = 1) );
102    fix := Subgroup( srcX, elts );
103    gens := SmallGeneratingSet( fix );
104    srcC := Subgroup( srcX, gens );
105    rngC := Intersection( StabilizerSubgroupXMod( XM, srcX, rngY ),
106                          Centralizer( Range( XM ), rngY ) );
107    if ( srcC = srcX ) then
108        srcC := srcX;
109        if ( rngC = Range( XM ) ) then
110            return XM;
111        fi;
112    fi;
113    return SubXMod( XM, srcC, rngC );
114end );
115
116#############################################################################
117##
118#M  Displacement
119##
120InstallMethod( Displacement, "generic method for hom, element, element",
121    true, [ IsGroupHomomorphism, IsObject, IsObject ], 0,
122function( alpha, r, s )
123
124    local a;
125
126    if not ( r in Source(alpha) ) then
127        Error( "r not in Source(alpha)" );
128    fi;
129    a := ImageElm( alpha, r );
130    if not ( ( Range(a) = Source(a) ) and ( s in Source(a) ) ) then
131        Error( "alpha not an automorphism of group containing s" );
132    fi;
133    return ImageElm( a, s^-1 ) * s;
134end );
135
136#############################################################################
137##
138#M  DisplacementGroup . . . . . subgroup of source generated by displacements
139##
140InstallMethod( DisplacementGroup, "generic method for crossed modules",
141    true, [ IsXMod, IsGroup, IsGroup ], 0,
142function( XM, H, S )
143
144    local alpha, alp, sonuc, T, G, t, t0, g, list, one;
145
146    T := Source( XM );
147    G := Range( XM );
148    if not ( IsSubgroup( T, S ) and IsSubgroup( G, H ) ) then
149        Error( "S <= T and H <= G fails" );
150    fi;
151    alpha := XModAction( XM );
152    list := [];
153    one := One( T );
154    #? surely we do not need to calculate all the displacements?
155    for g in H do
156        alp := ImageElm( alpha, g );
157        for t in S do
158            t0 := ImageElm( alp, t^-1 ) * t;
159            if ( ( t0 <> one ) and ( Position(list,t0) = fail ) ) then
160                Add( list, t0 );
161            fi;
162        od;
163    od;
164    if ( Length( Set(list) ) = 0 ) then
165        list := [ one ];
166    fi;
167    sonuc := Subgroup( T, list );
168    return Subgroup( T, SmallGeneratingSet( sonuc ) );
169end );
170
171InstallMethod( DisplacementSubgroup, "generic method for crossed modules",
172    true, [ IsXMod ], 0,
173function( XM )
174    return DisplacementGroup( XM, Range(XM), Source(XM) );
175end );
176
177#############################################################################
178##
179#M  Normalizer . . . . . . . . . for a subcrossed module of a crossed module
180##
181InstallOtherMethod( Normalizer, "generic method for crossed modules", true,
182    [ IsXMod, IsXMod ], 0,
183function( XM, YM )
184
185    local act, T, G, S, H, t, h, d, pos, elts, gens, srcN, rngN;
186
187    if not IsSubXMod( XM, YM ) then
188        Error( "YM is not a subcrossed module of XM" );
189    fi;
190    elts := [ ];
191    act := XModAction( XM );
192    T := Source( XM );
193    G := Range( XM  );
194    S := Source( YM );
195    H := Range( YM  );
196    ## is there a more efficient method, just using generators?
197    for t in T do
198        for h in H do
199            d := Displacement( act, h, t );
200            if ( d in S ) then
201                pos := Position( elts, d );
202                if ( pos = fail ) then
203                    Add( elts, d );
204                fi;
205            fi;
206        od;
207    od;
208    srcN := Subgroup( S, elts );
209    gens := SmallGeneratingSet( srcN );
210    srcN := Subgroup( S, gens );
211    rngN := Intersection( Normalizer( G, H ),
212                StabilizerSubgroupXMod( XM, S, G ) );
213    rngN := Subgroup( G, SmallGeneratingSet( rngN ) );
214    return SubXMod( XM, srcN, rngN );
215end );
216
217#############################################################################
218##
219#M  CrossActionSubgroup . . . . . . . . . source group for CommutatorSubXMod
220##
221InstallMethod( CrossActionSubgroup, "generic method for two normal subxmods",
222    true, [ IsXMod, IsXMod, IsXMod ], 0,
223function( TG, SH, RK )
224
225    local alpha, alp, T, s, s0, k, r, r0, h, list, one, cas;
226
227    ## if not ( IsSub2DimensionalDomain(TG,SH)
228    ##          and IsSub2DimensionalDomain(TG,RK) ) then
229    ##     Error( "SH,RK not subcrossed modules of TG" );
230    ## fi;
231    T := Source(TG);
232    alpha := XModAction(TG);
233    list := [];
234    one := One( T );
235    for k in GeneratorsOfGroup( Range(RK) ) do
236        alp := ImageElm( alpha, k );
237        for s in GeneratorsOfGroup( Source(SH) ) do
238            s0 := s^-1 * ImageElm( alp, s );
239            if ( ( s0 <> one ) and ( Position(list,s0) = fail ) ) then
240                Add( list, s0 );
241            fi;
242        od;
243    od;
244    for h in GeneratorsOfGroup( Range(SH) ) do
245        alp := ImageElm( alpha, h );
246        for r in GeneratorsOfGroup( Source(RK) ) do
247            r0 := ImageElm( alp, r^-1 ) * r;
248            if ( ( r0 <> one ) and ( Position(list,r0) = fail ) ) then
249                Add( list, r0 );
250            fi;
251        od;
252    od;
253    if ( Length( Set(list) ) = 0 ) then
254        list := [ one ];
255    fi;
256    cas := Subgroup( T, list );
257    cas := Subgroup( T, SmallGeneratingSet( cas ) );
258    return cas;
259end );
260
261#############################################################################
262##
263#M  IntersectionSubXMods  . . . . intersection of subcrossed modules SH and RK
264##
265InstallMethod( IntersectionSubXMods, "generic method for crossed modules",
266    true, [ IsXMod, IsXMod, IsXMod ], 0,
267function( XM, SH, RK)
268
269    local alpha, T, G, S, H, R, K, bdy, k_bdy, k_alpha, SR, HK;
270
271    T := Source( XM );
272    G := Range( XM );
273    alpha := XModAction( XM );
274    bdy := Boundary( XM );
275    S := Source(SH);
276    H := Range(SH);
277    R := Source(RK);
278    K := Range(RK);
279    SR := Intersection(S,R);
280    HK := Intersection(H,K);
281    return SubXMod(XM,SR,HK);
282end );
283
284#############################################################################
285##
286#M  NaturalMorphismByNormalSubPreXMod . . . . . the quotient prexmod morphism
287##
288InstallMethod( NaturalMorphismByNormalSubPreXMod,
289    "generic method for crossed modules", true, [ IsPreXMod, IsPreXMod ], 0,
290function( XM, SM )
291
292    local actX, bdyX, nhomQ, nhomF, T, G, S, H, Q, F, sgQ, sgF, imbdy, bdy,
293          lenF, psgQ, psgF, asgF, i, autF, aut, act, FM, nat;
294
295    if not IsNormal( XM, SM ) then
296        Error( "not a normal subcrossed module" );
297    fi;
298    actX := XModAction( XM );
299    bdyX := Boundary( XM );
300    T := Source( XM );
301    S := Source( SM );
302    nhomQ := NaturalHomomorphismByNormalSubgroup( T, S );
303    Q := Image( nhomQ );
304    sgQ := SmallGeneratingSet( Q );
305    Q := GroupWithGenerators( sgQ, One(Q) );           # T/S bölüm grubu
306    psgQ := List( sgQ, q -> PreImagesRepresentative( nhomQ, q ) );
307    G := Range( XM );
308    H := Range( SM );
309    if IsTrivial( H ) then
310        F := G;
311        nhomF := IdentityMapping( G );
312        sgF := SmallGeneratingSet( G );
313        psgF := SmallGeneratingSet( G );
314    else
315        nhomF := NaturalHomomorphismByNormalSubgroup( G, H );
316        F := Image( nhomF );
317        sgF := SmallGeneratingSet( F );
318        F := GroupWithGenerators( sgF, One(F) );       # G/H bölüm grubu
319        psgF := List( sgF, f -> PreImagesRepresentative( nhomF, f ) );
320    fi;
321    imbdy := List( psgQ, t -> ImageElm( nhomF, ImageElm( bdyX, t ) ) );
322    bdy := GroupHomomorphismByImages( Q, F, sgQ, imbdy );
323    lenF := Length( psgF );
324    asgF := List( psgF, g -> ImageElm( actX, g ) );
325    autF := ListWithIdenticalEntries( lenF, 0 );
326    for i in [1..lenF] do
327        autF[i] := GroupHomomorphismByImages( Q, Q, sgQ,
328                   List( psgQ, t -> ImageElm( nhomQ, ImageElm(asgF[i],t) ) ) );
329    od;
330    if ( lenF = 0 ) then
331        aut := Group( IdentityMapping( Q ) );
332    else
333        aut := Group( autF );
334    fi;
335    SetIsGroupOfAutomorphisms( aut, true );
336    act := GroupHomomorphismByImages( F, aut, sgF, autF );
337    FM := XModByBoundaryAndAction( bdy, act );
338    if ( HasName( XM ) and HasName( SM ) ) then
339        SetName( FM, Concatenation( Name( XM ), "/", Name( SM ) ) );
340    fi;
341    nat := PreXModMorphismByGroupHomomorphisms( XM, FM, nhomQ, nhomF );
342    SetProjectionOfFactorPreXMod( FM, nat );
343    return nat;
344end );
345
346#############################################################################
347##
348#M  FactorPreXMod  . . . . . . . . . . . . . . the quotient precrossed module
349##
350InstallMethod( FactorPreXMod, "generic method for precrossed modules", true,
351    [ IsPreXMod, IsPreXMod ], 0,
352function( XM, SM )
353    return Range( NaturalMorphismByNormalSubPreXMod( XM, SM ) );
354end );
355
356#############################################################################
357##
358#M  DerivedSubXMod  . . . . . . . . . . the commutator of the crossed module
359##
360InstallMethod( DerivedSubXMod, "generic method for crossed modules", true,
361    [ IsXMod ], 0,
362function( XM )
363
364    local D, dgt;
365
366    D := DerivedSubgroup( Range( XM ) );
367    dgt := DisplacementSubgroup( XM );
368    return SubXMod( XM, dgt, D );
369end );
370
371#############################################################################
372##
373#M  CommutatorSubXMod  . . . . . . . commutator subxmod of two normal subxmods
374##
375InstallMethod( CommutatorSubXMod, "generic method for crossed modules", true,
376    [ IsXMod, IsXMod, IsXMod ], 0,
377function( TG, SH, RK )
378
379    local cas, com;
380
381    cas := CrossActionSubgroup( TG, SH, RK );
382    com := CommutatorSubgroup( Range(SH), Range(RK) );
383    return SubXMod( TG, cas, com );
384end );
385
386#############################################################################
387##
388#M  LowerCentralSeries  . . . . . . . . . the lower central series of an xmod
389##
390InstallOtherMethod( LowerCentralSeries, "generic method for crossed modules",
391    true, [ IsXMod ], 0,
392function( XM )
393
394    local list, C;
395
396    list := [ XM ];
397    C := DerivedSubXMod( XM );
398    while ( C <> list[ Length(list) ] )  do
399        Add( list, C );
400        C := CommutatorSubXMod( XM, C, XM );
401    od;
402    return list;
403end );
404
405#############################################################################
406##
407#M  IsAbelian2DimensionalGroup . . . . check that a crossed module is abelian
408##
409InstallMethod( IsAbelian2DimensionalGroup,
410    "generic method for crossed modules", true, [ IsXMod ], 0,
411function( XM )
412    return ( XM = CentreXMod( XM ) );
413end );
414
415#############################################################################
416##
417#M  IsAspherical2DimensionalGroup . check that a crossed module is aspherical
418##
419InstallMethod( IsAspherical2DimensionalGroup,
420    "generic method for crossed modules", true, [ IsXMod ], 0,
421function( XM )
422    return ( Size( Kernel( Boundary( XM ) ) ) = 1 );
423end );
424
425#############################################################################
426##
427#M  IsSimplyConnected2DimensionalGroup . . check an xmod is simply connected
428##
429InstallMethod( IsSimplyConnected2DimensionalGroup,
430    "generic method for crossed modules", true, [ IsXMod ], 0,
431function( XM )
432    return ( Size( CoKernel( Boundary( XM ) ) ) = 1 );
433end );
434
435#############################################################################
436##
437#M  IsFaithful2DimensionalGroup . . . check that a crossed module is faithful
438##
439InstallMethod( IsFaithful2DimensionalGroup,
440    "generic method for crossed modules", true, [ IsXMod ], 0,
441function( XM )
442    return ( Size( StabilizerSubgroupXMod( XM, Source( XM ), Range( XM ) ) ) = 1 );
443end );
444
445#############################################################################
446##
447#M  IsNilpotent2DimensionalGroup  . . . . . . check that an xmod is nilpotent
448##
449InstallMethod( IsNilpotent2DimensionalGroup,
450    "generic method for crossed modules", true, [ IsXMod ], 0,
451function( XM )
452
453    local S, n, sonuc;
454
455    S := LowerCentralSeries( XM );
456    n := Length(S);
457    if ( Size(S[n]) = [1,1] ) then
458        sonuc := true;
459    else
460        sonuc := false;
461    fi;
462return sonuc;
463end );
464
465#############################################################################
466##
467#M  NilpotencyClassOf2DimensionalGroup . nilpotency degree of a crossed module
468##
469InstallMethod( NilpotencyClassOf2DimensionalGroup,
470    "generic method for crossed modules", true, [ IsXMod ], 0,
471function( XM )
472
473    if not IsNilpotent2DimensionalGroup( XM ) then
474        return 0;
475    else
476        return Length( LowerCentralSeries( XM ) ) - 1;
477    fi;
478end );
479
480#############################################################################
481##
482#M  IsomorphismXMods  . . check that the given crossed modules are isomorphic
483##
484InstallMethod( IsomorphismXMods, "generic method for crossed modules", true,
485    [ Is2DimensionalGroup, Is2DimensionalGroup ], 0,
486function(XM1,XM2)
487
488    local T1, G1, T2, G2, isoT, isoG, iterT, iterG, alp, ph, mor;
489
490    T1 := Source(XM1);
491    G1 := Range(XM1);
492    T2 := Source(XM2);
493    G2 := Range(XM2);
494    isoT := IsomorphismGroups(T1,T2);
495    isoG := IsomorphismGroups(G1,G2);
496    if ( ( isoT = fail ) or ( isoG = fail ) ) then
497        return fail;
498    fi;
499    iterT := Iterator( AllAutomorphisms( T2 ) );
500    while not IsDoneIterator( iterT ) do
501        iterG := Iterator( AllAutomorphisms( G2 ) );
502        alp := isoT * NextIterator( iterT );
503        while not IsDoneIterator( iterG ) do
504            ph := isoG * NextIterator( iterG );
505            mor := Make2DimensionalGroupMorphism( [ XM1, XM2, alp, ph ] );
506            if ( not( mor = fail ) and IsPreXModMorphism( mor )
507                                   and IsXModMorphism( mor ) ) then
508                return mor;
509            fi;
510        od;
511    od;
512    return fail;
513end );
514
515#############################################################################
516##
517#M  AllXModsWithGroups . . . . . . . . all xmods with given source and range
518##
519InstallMethod( AllXModsWithGroups, "generic method for a pair of groups",
520    true, [ IsGroup, IsGroup ], 0,
521function( T, G )
522
523    local list, A, itTG, itGA, b1, a1, obj;
524
525    list := [ ];
526    A := AutomorphismGroup(T);
527    itTG := Iterator( AllHomomorphisms(T,G) );
528    while not IsDoneIterator( itTG ) do
529        b1 := NextIterator( itTG );
530        itGA := Iterator( AllHomomorphisms(G,A) );
531        while not IsDoneIterator( itGA ) do
532            a1 := NextIterator( itGA );
533            obj := PreXModObj( b1, a1 );
534            if ( IsPreXMod( obj ) and IsXMod( obj ) ) then
535                Add( list, obj );
536            fi;
537        od;
538    od;
539    return list;
540end );
541
542InstallMethod( AllXModsWithGroups0, "generic method for a pair of groups",
543    true, [ IsGroup, IsGroup ], 0,
544function( T, G )
545
546    local list, A, allTG, allGA, b1, a1, obj;
547
548    list := [ ];
549    A := AutomorphismGroup(T);
550    allTG := AllHomomorphisms(T,G);
551    allGA := AllHomomorphisms(G,A);
552    for b1 in allTG do
553        for a1 in allGA do
554            obj := PreXModObj( b1, a1 );
555            if ( IsPreXMod( obj ) and IsXMod( obj ) ) then
556                Add( list, obj );
557            fi;
558        od;
559    od;
560    return list;
561end );
562
563InstallMethod( AllXModsWithGroups1, "generic method for a pair of groups",
564    true, [ IsGroup, IsGroup ], 0,
565function( T, G )
566
567    local list, A, itTG, itGA, b1, a1, obj;
568
569    list := [ ];
570    A := AutomorphismGroup(T);
571    itTG := Iterator( AllHomomorphismClasses(T,G) );
572    while not IsDoneIterator( itTG ) do
573        b1 := NextIterator( itTG );
574        itGA := Iterator( AllHomomorphisms(G,A) );
575        while not IsDoneIterator( itGA ) do
576            a1 := NextIterator( itGA );
577            obj := PreXModObj( b1, a1 );
578            if ( IsPreXMod( obj ) and IsXMod( obj ) ) then
579                Add( list, obj );
580            fi;
581        od;
582    od;
583    return list;
584end );
585
586InstallMethod( AllXModsWithGroups2, "generic method for a pair of groups",
587    true, [ IsGroup, IsGroup ], 0,
588function( T, G )
589
590    local list, A, itTG, itGA, b1, a1, obj;
591
592    list := [ ];
593    A := AutomorphismGroup(T);
594    itTG := Iterator( AllHomomorphisms(T,G) );
595    while not IsDoneIterator( itTG ) do
596        b1 := NextIterator( itTG );
597        itGA := Iterator( AllHomomorphismClasses(G,A) );
598        while not IsDoneIterator( itGA ) do
599            a1 := NextIterator( itGA );
600            obj := PreXModObj( b1, a1 );
601            if ( IsPreXMod( obj ) and IsXMod( obj ) ) then
602                Add( list, obj );
603            fi;
604        od;
605    od;
606    return list;
607end );
608
609InstallMethod( AllXModsWithGroups3, "generic method for a pair of groups",
610    true, [ IsGroup, IsGroup ], 0,
611function( T, G )
612
613    local list, A, itTG, itGA, b1, a1, obj;
614
615    list := [ ];
616    A := AutomorphismGroup(T);
617    itTG := Iterator( AllHomomorphismClasses(T,G) );
618    while not IsDoneIterator( itTG ) do
619        b1 := NextIterator( itTG );
620        itGA := Iterator( AllHomomorphismClasses(G,A) );
621        while not IsDoneIterator( itGA ) do
622            a1 := NextIterator( itGA );
623            obj := PreXModObj( b1, a1 );
624            if ( IsPreXMod( obj ) and IsXMod( obj ) ) then
625                Add( list, obj );
626            fi;
627        od;
628    od;
629    return list;
630end );
631
632#############################################################################
633##
634#F  AllXMods( <T>, <G> )             xmods with given source and range
635#F  AllXMods( <size> )               xmods with a given size
636#F  AllXMods( <order> )              xmods whose cat1-group has a given order
637##
638InstallGlobalFunction( AllXMods, function( arg )
639
640    local nargs, a, list, s1, j1, s2, j2, T, G, sizes;
641
642    nargs := Length( arg );
643    if ( nargs = 2 ) then
644        ## given source and range
645        if ( IsGroup( arg[1] ) and IsGroup( arg[2] ) ) then
646            return AllXModsWithGroups( arg[1], arg[2] );
647        fi;
648    elif ( nargs = 1 ) then
649        a := arg[1];
650        ## given size
651        if ( IsList(a) and (Length(a)=2) and IsInt(a[1]) and IsInt(a[2]) ) then
652            list := [ ];
653            s1 := NumberSmallGroups( a[1] );
654            for j1 in [1..s1] do
655                T := SmallGroup( a[1], j1 );
656                s2 := NumberSmallGroups( a[2] );
657                for j2 in [1..s2] do
658                    G := SmallGroup( a[2], j2 );
659                    Append( list, AllXModsWithGroups( T, G ) );
660                od;
661            od;
662            return list;
663        ## given total size
664        elif IsInt(a) then
665            sizes := List( DivisorsInt(a), d -> [d,a/d] );
666            list := [ ];
667            for s1 in sizes do
668                Append( list, AllXMods( s1 ) );
669            od;
670            return list;
671        fi;
672    fi;
673    Error( "standard usage: AllXMods(S,R), AllXMods([n,m]), AllXMods(n)" );
674end );
675
676
677#############################################################################
678#####                FUNCTIONS FOR ISOCLINISM OF GROUPS                 #####
679#############################################################################
680
681#############################################################################
682##
683#M IsStemDomain . . . check that the centre is a subgroup of the derived group
684##
685InstallMethod( IsStemDomain, "generic method for groups", true, [ IsGroup ], 0,
686function(G)
687    return IsSubgroup( DerivedSubgroup(G), Centre(G) );
688end );
689
690#############################################################################
691##
692#M AllStemGroupIds . . . list of all IdGroup's of stem groups of chosen order
693##
694InstallMethod( AllStemGroupIds, "generic method for posint", true,
695    [ IsPosInt ], 0,
696function(a)
697
698    local g, i, j, sonuc, sayi;
699
700    sonuc := [ ];
701    for g in AllSmallGroups( a ) do
702        if IsStemDomain( g ) then
703            Add( sonuc, IdGroup( g ) );
704        fi;
705    od;
706    return sonuc;
707end );
708
709#############################################################################
710##
711#M AllStemGroupFamilies . . . split stem groups of chosen order into families
712##
713InstallMethod( AllStemGroupFamilies, "generic method for posint", true,
714    [ IsPosInt ], 0,
715function(a)
716
717    local ids, len, found, id, gi, g, i, j, sonuc, new, sayi;
718
719    ids := AllStemGroupIds( a );
720    len := Length( ids );
721    found := ListWithIdenticalEntries( len, false );
722    sonuc := [ ];
723    for i in [1..len] do
724        if not found[i] then
725            found[i] := true;
726            id := ids[i];
727            new := [ id ];
728            gi := SmallGroup( id );
729            for j in [i+1..len] do
730                if not found[j] then
731                    if AreIsoclinicDomains( gi, SmallGroup( ids[j] ) ) then
732                        found[j] := true;
733                        Add( new, ids[j] );
734                    fi;
735                fi;
736            od;
737        Add( sonuc, ShallowCopy( new ) );
738        fi;
739    od;
740    return sonuc;
741end );
742
743#############################################################################
744##
745#M CentralQuotient . . . . . . . . . . . . . . . . . . . .  (G -> G/Z(G))
746##
747InstallMethod( CentralQuotient, "generic method for groups", true,
748    [ IsGroup ], 0,
749function( G )
750
751    local ZG, Q, nat, XQ;
752
753    ZG := Centre( G );
754    nat := NaturalHomomorphismByNormalSubgroup( G, ZG );
755    Q := Image( nat );
756    if HasName(G) then
757        if not HasName(ZG) then
758            SetName( ZG, Concatenation( "Z(", Name(G), ")" ) );
759        fi;
760        SetName( Q, Concatenation( Name(G), "/", Name(ZG) ) );
761    fi;
762    XQ := XModByCentralExtension( nat );
763    return XQ;
764end );
765
766InstallMethod( CentralQuotient, "generic method for crossed modules",
767    true, [ IsXMod ], 0,
768function( lt )
769
770    local actlt, zlt, rt, L, M, N, P, nat, kappa, lambda, nu, up, dn, genL,
771          genN, nugenN, agenN, adg, imdelta, delta, dg, map, xp, xs;
772
773    actlt := XModAction( lt );
774    zlt := CentreXMod( lt );
775    nat := NaturalMorphismByNormalSubPreXMod( lt, zlt );
776    kappa := SourceHom( nat );
777    lambda := Boundary( lt );
778    nu := RangeHom( nat );
779    rt := Image( nat );
780    L := Source( lt );
781    N := Range( lt );
782    M := Source( rt );
783    P := Range( rt );
784    if ( HasName( lt ) and not HasName(zlt) ) then
785        SetName( zlt, Concatenation( "Z(", Name( lt ), ")" ) );
786    fi;
787    if HasName( lt ) then
788        if not HasName( zlt ) then
789            SetName( zlt, Concatenation( "Z(", Name( lt ), ")" ) );
790        fi;
791        SetName( rt, Concatenation( Name(lt), "/", Name(zlt) ) );
792    fi;
793    up := XModByCentralExtension( kappa );
794    dn := XModByCentralExtension( nu );
795    genL := GeneratorsOfGroup( L );
796    genN := GeneratorsOfGroup( N );
797    nugenN := List( genN, n -> ImageElm( nu, n ) );
798    agenN := List( genN, n -> ImageElm( actlt, n ) );
799    adg := GroupHomomorphismByImages( P, Range(actlt), nugenN, agenN );
800    imdelta := List( genL, l ->ImageElm( nu, ImageElm( lambda, l ) ) );
801    delta := GroupHomomorphismByImages( L, P, genL, imdelta );
802    dg := XModByBoundaryAndAction( delta, adg );
803    map := Mapping2ArgumentsByFunction( [N,M], L,
804             function(c)
805               local a, l;
806               a := ImageElm( actlt, c[1] );
807               l := PreImagesRepresentative( kappa, c[2] );
808               return ImageElm( a, l^(-1) ) * l;
809             end );
810    xp := CrossedPairingObj( [N,M], L, map );
811    xs := PreCrossedSquareObj( up, lt, rt, dn, dg, xp );
812##    SetIsCrossedSquare( xs, true );
813    if not IsCrossedSquare( xs ) then
814        Error( "xs fails to be a crossed square by central quotient" );
815    fi;
816    return xs;
817end );
818
819#############################################################################
820##
821#M AreIsoclinicDomains . . . . . . . . . . . for two domains: groups or xmods
822##
823InstallMethod( AreIsoclinicDomains, "generic method for two groups or xmods",
824    true, [ IsDomain, IsDomain ], 0,
825function( D1, D2 )
826
827    local iso;
828
829    if not ( ( IsGroup(D1) and IsGroup(D2) ) or
830             ( Is2DimensionalGroup(D1) and Is2DimensionalGroup(D2) ) ) then
831        Error( "D1 and D2 should be groups or 2DimensionalGroups" );
832    fi;
833    iso := Isoclinism( D1, D2 );
834    if ( ( iso = fail ) or ( iso = false ) ) then
835        return false;
836    else
837        return true;
838    fi;
839end );
840
841##############################################################################
842##
843#M Isoclinism . . . . . . . . . . . . . . . . . . . . . . . . . . . for groups
844##
845InstallMethod( Isoclinism, "generic method for two groups", true,
846    [ IsGroup, IsGroup ], 0,
847function( G1, G2 )
848
849    local CQ1, CQ2, Q1, Q2, D1, D2, nhom1, nhom2, sgQ1, lsgQ1, itAQ2, itAD2,
850          isoQ, isoD, p1, q1, p2, q2, i, iq1, iq2, j, g1, h1,
851          g2, h2, gor1, gor2, ok;
852
853    if ( IsomorphismGroups(G1,G2) <> fail ) then
854        Error( "not yet implemented" );
855        return true;
856    fi;
857    CQ1 := CentralQuotient(G1);
858    Q1 := Range(CQ1);
859    CQ2 := CentralQuotient(G2);
860    Q2 := Range(CQ2);
861    D1 := DerivedSubgroup(G1);
862    D2 := DerivedSubgroup(G2);
863    isoQ := IsomorphismGroups(Q1,Q2);
864    isoD := IsomorphismGroups(D1,D2);
865    if ( ( isoQ = fail ) or ( isoD = fail ) ) then
866        return fail;
867    fi;
868    nhom1 := Boundary( CQ1 );
869    nhom2 := Boundary( CQ2 );
870    itAQ2 := Iterator( AllAutomorphisms(Q2) );
871    ## there is a problem here!
872    ## examples have been found where using SmallGeneratingSet
873    ## gives an incorrect answer!
874    ## perhaps GeneratorsOfGroup would be insuffient, but,
875    ## to play safe, we use Elements(Q1) for now, though very slow!
876    ## sgQ1 := SmallGeneratingSet( Q1 );
877    ## sgQ1 := GeneratorsOfGroup( Q1 );
878    sgQ1 := Elements( Q1 );
879    lsgQ1 := Length( sgQ1 );
880    while not IsDoneIterator( itAQ2 ) do
881        i := isoQ * NextIterator( itAQ2 );
882        ok := true;
883        itAD2 := Iterator( AllAutomorphisms(D2) );
884        while not IsDoneIterator( itAD2 ) do
885            j := isoD * NextIterator(itAD2);
886            ok := true;
887            p1 := 0;
888            while ( ok and ( p1 < lsgQ1 ) ) do
889                p1 := p1+1;
890                q1 := sgQ1[p1];
891                g1 := PreImagesRepresentative( nhom1, q1 );
892                iq1 := ImageElm( i, q1 );
893                h1 := PreImagesRepresentative( nhom2, iq1 );
894                p2 := 0;
895                while ( ok and ( p2 < lsgQ1 ) ) do
896                    p2 := p2+1;
897                    q2 := sgQ1[p2];
898                    g2 := PreImagesRepresentative( nhom1, q2 );
899                    iq2 := ImageElm( i, q2 );
900                    h2 := PreImagesRepresentative( nhom2, iq2 );
901                    gor1 := ImageElm( j, Comm(g1,g2) );
902                    gor2 := Comm( h1, h2 );
903                    ok := ( gor1 = gor2 );
904                od;
905            od;
906            if ok then
907                return [i,j];
908            fi;
909        od;
910    od;
911    return fail;
912end );
913
914#############################################################################
915##
916#M IsoclinicStemDomain . . . ?? is this really the best way ??
917##
918InstallMethod( IsoclinicStemDomain, "generic method for a group", true,
919    [ IsGroup ], 0,
920function(G)
921
922    local i, len, divs, id, gi;
923
924    if ( HasIsAbelian(G) and IsAbelian(G) ) then
925        return [ [ 1, 1 ] ];
926    fi;
927    if IsStemDomain(G) then
928        return G;
929    fi;
930    divs := DivisorsInt( Size(G) );
931    len := Length( divs );
932    for i in divs{[2..len-1]} do
933        for gi in AllSmallGroups( i ) do
934            if IsStemDomain( gi ) then
935                if AreIsoclinicDomains( G, gi ) then
936                    return gi;
937                fi;
938            fi;
939        od;
940    od;
941    return fail;
942end );
943
944
945#############################################################################
946#####            FUNCTIONS FOR ISOCLINISM OF CROSSED MODULES            #####
947#############################################################################
948
949#############################################################################
950##
951#M IsStemDomain . check that the centre xmod is a subxmod of the derived xmod
952##
953InstallMethod( IsStemDomain, "generic method for crossed modules", true,
954    [ IsXMod ], 0,
955function(X0)
956    return IsSubXMod( DerivedSubXMod(X0), CentreXMod(X0) );
957end );
958
959InstallMethod( Isoclinism, "generic method for crossed modules", true,
960    [ IsXMod, IsXMod ], 0,
961function( X1, X2 )
962
963    local SX1, RX1, SX2, RX2, D1, D2, isoD, autD2, CX1, Q1, CX2, Q2, isoQ,
964          SQ1, RQ1, SQ2, RQ2, actX1, actX2, autQ2, nhom1, shom1, rhom1,
965          nhom2, shom2, rhom2, sgRQ1, lsgRQ1, sgSQ1, lsgSQ1, a, i, si, ri,
966          ok, b, j, sj, rj, p1, r1, x1, ir1, d1, p2, r2, x2, ir2, d2,
967          gor1, gor2, p3, s1, y1, is1, e1;
968
969    SX1 := Source(X1);
970    RX1 := Range(X1);
971    SX2 := Source(X2);
972    RX2 := Range(X2);
973    actX1 := XModAction( X1 );
974    actX2 := XModAction( X2 );
975    D1 := DerivedSubXMod(X1);
976    D2 := DerivedSubXMod(X2);
977    ## check condition 2 : require D1 ~ D2
978    isoD := IsomorphismXMods( D1, D2 );
979    if ( isoD = fail ) then
980        Info( InfoXMod, 1, "derived subcrossed modules are not isomorphic" );
981        return fail;
982    fi;
983    autD2 := AutomorphismPermGroup( D2 );
984
985    CX1 := CentralQuotient( X1 );
986    Q1 := Right2DimensionalGroup( CX1 );
987    CX2 := CentralQuotient( X2 );
988    Q2 := Right2DimensionalGroup( CX2 );
989    ## check condition 1 : require Q1 ~ Q2
990    isoQ := IsomorphismXMods( Q1, Q2 );
991    if ( isoQ = fail ) then
992        Info( InfoXMod, 1, "factor crossed modules X/ZX are not isomorphic" );
993        return fail;
994    fi;
995
996    SQ1 := Source(Q1);
997    RQ1 := Range(Q1);
998    SQ2 := Source(Q2);
999    RQ2 := Range(Q2);
1000    autQ2 := AutomorphismPermGroup( Q2 );
1001    nhom1 := LeftRightMorphism( CX1 );
1002    shom1 := SourceHom( nhom1 );
1003    rhom1 := RangeHom( nhom1 );
1004    nhom2 := LeftRightMorphism( CX2 );
1005    shom2 := SourceHom( nhom2 );
1006    rhom2 := RangeHom( nhom2 );
1007    sgRQ1 := SmallGeneratingSet( RQ1 );
1008    lsgRQ1 := Length( sgRQ1 );
1009    sgSQ1 := SmallGeneratingSet( SQ1 );
1010    lsgSQ1 := Length( sgSQ1 );
1011
1012    for a in autQ2 do
1013        i := isoQ * PermAutomorphismAsXModMorphism( Q2, a );
1014        si := SourceHom( i );
1015        ri := RangeHom( i );
1016        ok := true;
1017        for b in autD2 do
1018            j := isoD * PermAutomorphismAsXModMorphism( D2, b );
1019            sj := SourceHom( j );
1020            rj := RangeHom( j );
1021            ok := true;
1022            p1 := 0;
1023            while ( ok and ( p1 < lsgRQ1 ) ) do
1024                p1 := p1+1;
1025                r1 := sgRQ1[p1];
1026                x1 := PreImagesRepresentative( rhom1, r1 );
1027                ir1 := ImageElm( ri, r1 );
1028                d1 := PreImagesRepresentative( rhom2, ir1 );
1029                p2 := 0;
1030                while ( ok and ( p2 < lsgRQ1 ) ) do
1031                    p2 := p2+1;
1032                    r2 := sgRQ1[p2];
1033                    x2 := PreImagesRepresentative( rhom1, r2 );
1034                    ir2 := ImageElm( ri, r2 );
1035                    d2 := PreImagesRepresentative( rhom2, ir2 );
1036                    gor1 := ImageElm( rj, Comm(x1,x2) );
1037                    gor2 := Comm( d1, d2 );
1038                    ok := ( gor1 = gor2 );
1039                od;
1040                p3 := 0;
1041                while ( ok and ( p3 < lsgSQ1 ) ) do
1042                    p3 := p3+1;
1043                    s1 := sgSQ1[p3];
1044                    y1 := PreImagesRepresentative( shom1, s1 );
1045                    is1 := ImageElm( si, s1 );
1046                    e1 := PreImagesRepresentative( shom2, is1 );
1047                    gor1 := ImageElm( sj, Displacement( actX1, x1, y1 ) );
1048                    gor2 := Displacement( actX2, d1, e1 );
1049                    ok := ( gor1 = gor2 );
1050                od;
1051            od;
1052            if ok then
1053                return [i,j];
1054            fi;
1055        od;
1056    od;
1057    Info( InfoXMod, 1, "no morphism exists satisfying the conditions" );
1058    return fail;
1059end );
1060
1061
1062#############################################################################
1063##
1064#M  IsoclinicXModFamily  . . . . all xmods in the list isoclinic to the xmod
1065##
1066InstallMethod( IsoclinicXModFamily, "generic method for crossed modules",
1067    true, [ Is2DimensionalGroup, IsList ], 0,
1068function( XM, XM1_ler )
1069
1070    local sonuc, XM1;
1071
1072    sonuc := [ ];
1073    for XM1 in XM1_ler do
1074        if AreIsoclinicDomains( XM, XM1 ) then
1075            Info( InfoXMod, 2, XM, " ~ ", XM1 );
1076            Add( sonuc, Position(XM1_ler,XM1) );
1077        else
1078            Info( InfoXMod, 2, XM, " |~ ", XM1 );
1079        fi;
1080    od;
1081    return sonuc;
1082end );
1083
1084#############################################################################
1085##
1086#M  IsomorphicXModFamily  . . . all xmods in the list isomorphic to the xmod
1087##
1088InstallMethod( IsomorphicXModFamily, "generic method for crossed modules",
1089    true, [ Is2DimensionalGroup, IsList ], 0,
1090function( XM, XM1_ler )
1091
1092    local sonuc, iso, XM1;
1093
1094    sonuc := [ ];
1095    for XM1 in XM1_ler do
1096        iso := IsomorphismXMods( XM, XM1 );
1097        if ( iso <> fail ) then
1098            Add( sonuc, Position(XM1_ler,XM1) );
1099        fi;
1100    od;
1101    return sonuc;
1102end );
1103
1104#############################################################################
1105##
1106#M  AllXModsUpToIsomorphism . . .  . . all crossed modules up to isomorphism
1107##
1108InstallMethod( AllXModsUpToIsomorphism, "generic method for list of xmods",
1109    true, [ IsList ], 0,
1110function( allxmods )
1111
1112    local n, found, all, i, j, k, isolar, list;
1113
1114    n := Length( allxmods );
1115    found := ListWithIdenticalEntries( n, 0 );
1116    all := ShallowCopy( allxmods );
1117    list := [];
1118    for i in [1..n] do
1119        if ( found[i] = 0 ) then
1120            Add( list, allxmods[i] );
1121            isolar := IsomorphicXModFamily( allxmods[i], all );
1122            for j in isolar do
1123                k := Position( allxmods, all[j] );
1124                found[k] := 1;
1125            od;
1126        fi;
1127    od;
1128    return list;
1129end );
1130
1131#############################################################################
1132##
1133#M  IsoclinicMiddleLength . .  the middle length of a group or crossed module
1134#M  IsoclinicRank . . . . . . . . . . . the rank of a group or crossed module
1135##
1136InstallMethod( IsoclinicRank, "generic method for groups", true,
1137    [ IsGroup ], 0,
1138function(G)
1139
1140    local ZG, DG, QG, KG;
1141
1142    if not IsPrimePowerInt( Size(G) ) then
1143        return fail;
1144    fi;
1145    ZG := Centre(G);
1146    DG := DerivedSubgroup(G);
1147    QG := G/ZG;
1148    KG := Intersection( ZG, DG );
1149    return Tau( Size(KG) ) + Tau( Size(QG) ) - 2;
1150end );
1151
1152InstallMethod( IsoclinicRank, "generic method for crossed modules", true,
1153    [ Is2DimensionalGroup ], 0,
1154function( XM )
1155
1156    local size, ZXMod, DXMod, QXMod, KXMod, m1, m2, l1, l2;
1157
1158    size := Size( XM );
1159    if not ( IsPrimePowerInt(size[1]) and IsPrimePowerInt(size[2]) ) then
1160        return fail;
1161    fi;
1162    ZXMod := CentreXMod( XM );
1163    DXMod := DerivedSubXMod( XM );
1164    QXMod := FactorPreXMod( XM, ZXMod );
1165    KXMod := IntersectionSubXMods( XM, ZXMod, DXMod );
1166    m1 := Size( QXMod );
1167    m2 := Size( KXMod );
1168    l1 := Tau( m1[1] ) + Tau( m2[1] ) - 2;
1169    l2 := Tau( m1[2] ) + Tau( m2[2] ) - 2;
1170    return [l1,l2];
1171end );
1172
1173InstallMethod( IsoclinicMiddleLength, "generic method for groups", true,
1174    [ IsGroup ], 0,
1175function(G)
1176
1177    local ZG, DG, QG, KG;
1178
1179    if not IsPrimePowerInt( Size(G) ) then
1180        return fail;
1181    fi;
1182    ZG := Centre( G );
1183    DG := DerivedSubgroup( G );
1184    KG := Intersection( ZG, DG );
1185    QG := DG/KG;
1186    return Tau( Size(QG) ) - 1;
1187end );
1188
1189InstallMethod( IsoclinicMiddleLength,
1190    "generic method for crossed modules", true, [ Is2DimensionalGroup ], 0,
1191function( XM )
1192
1193    local size, ZXMod, DXMod, QXMod, KXMod;
1194
1195    size := Size( XM );
1196    if not ( IsPrimePowerInt(size[1]) and IsPrimePowerInt(size[2]) ) then
1197        Info( InfoXMod, 1, "not a crossed module of prime power order" );
1198        return fail;
1199    fi;
1200    ZXMod := CentreXMod( XM );
1201    DXMod := DerivedSubXMod( XM );
1202    KXMod := IntersectionSubXMods( XM, ZXMod, DXMod );
1203    QXMod := FactorPreXMod( DXMod, KXMod );
1204    size := Size( QXMod );
1205    return [ Tau(size[1])-1, Tau(size[2])-1 ];
1206end );
1207
1208#############################################################################
1209##
1210#M  TableRowXMod  . . . table row for isoclinism families of crossed modules
1211##
1212InstallMethod( TableRowXMod, "generic method for crossed modules", true,
1213    [ Is2DimensionalGroup, IsList ], 0,
1214function( XM, XM_ler )
1215
1216    local Eler, Iler, i, j, sinif, B;
1217
1218    sinif := IsoclinicXModFamily( XM, XM_ler );
1219    B := LowerCentralSeries( XM );
1220
1221Print("---------------------------------------------------------------------------------------------------------------------------------- \n");
1222Print("---------------------------------------------------------------------------------------------------------------------------------- \n");
1223Print("Number","\t","Rank","\t\t","M. L.","\t\t","Class","\t","|G/Z|","\t\t",
1224      "|g2|","\t\t","|g3|","\t\t","|g4|","\t\t","|g5| \n");
1225Print("---------------------------------------------------------------------------------------------------------------------------------- \n");
1226Print( Length(sinif), "\t", IsoclinicRank( XM ), "\t",
1227       IsoclinicMiddleLength( XM ), "\t",
1228       NilpotencyClassOf2DimensionalGroup( XM ), "\t",
1229       Size( FactorPreXMod( XM, CentreXMod( XM ) ) ) );
1230
1231    if Length(B) > 1 then
1232        for i in [2..Length(B)] do
1233            Print( "\t" );
1234            Print( Size( B[i] ) );
1235        od;
1236    fi;
1237Print("\n---------------------------------------------------------------------------------------------------------------------------------- \n");
1238    return sinif;
1239end );
1240