1##############################################################################
2##
3#W  gp3obj.gi                   GAP4 package `XMod'              Chris Wensley
4##                                                                Alper Odabas
5##  This file implements generic methods for (pre-)crossed squares
6##  and (pre-)cat2-groups.
7##
8#Y  Copyright (C) 2001-2019, Chris Wensley et al,
9#Y  School of Computer Science, Bangor University, U.K.
10
11#############################################################################
12##
13#M  IsPerm3DimensionalGroup . .  check whether the 4 sides are perm 2d-groups
14#M  IsFp3DimensionalGroup . . . .  check whether the 4 sides are fp 2d-groups
15#M  IsPc3DimensionalGroup . . . .  check whether the 4 sides are pc 2d-groups
16##
17InstallMethod( IsPerm3DimensionalGroup, "generic method for 3d-group objects",
18    true, [ IsHigherDimensionalGroup ], 0,
19function( obj )
20    return ( IsPermGroup( Up2DimensionalGroup(obj) )
21             and IsPermGroup( Left2DimensionalGroup(obj) )
22             and IsPermGroup( Right2DimensionalGroup(obj) )
23             and IsPermGroup( Down2DimensionalGroup(obj) )
24             and IsPermGroup( Diagonal2DimensionalGroup(obj) ) );
25end );
26
27InstallMethod( IsFp3DimensionalGroup, "generic method for 3d-group objects",
28    true, [ IsHigherDimensionalGroup ], 0,
29function( obj )
30    return ( IsFpGroup( Up2DimensionalGroup(obj) )
31             and IsFpGroup( Left2DimensionalGroup(obj) )
32             and IsFpGroup( Right2DimensionalGroup(obj) )
33             and IsFpGroup( Down2DimensionalGroup(obj) )
34             and IsFpGroup( Diagonal2DimensionalGroup(obj) ) );
35end );
36
37InstallMethod( IsPc3DimensionalGroup, "generic method for 3d-group obj ects",
38    true, [ IsHigherDimensionalGroup ], 0,
39function( obj )
40    return ( IsPcGroup( Up2DimensionalGroup(obj) )
41             and IsPcGroup( Left2DimensionalGroup(obj) )
42             and IsPcGroup( Right2DimensionalGroup(obj) )
43             and IsPcGroup( Down2DimensionalGroup(obj) )
44             and IsPcGroup( Diagonal2DimensionalGroup(obj) ) );
45end );
46
47##############################################################################
48##
49#M  IsCrossedPairing
50#M  CrossedPairingObj( [<src1>,<src2>],<rng>,<map> ) .. make a crossed pairing
51##
52InstallMethod( IsCrossedPairing, "generic method for mappings", true,
53    [ IsGeneralMapping ], 0,
54function( map )
55    return ( HasSource( map ) and HasRange( map )
56             and HasCrossedPairingMap( map ) );
57end );
58
59InstallMethod( CrossedPairingObj, "for a general mapping", true,
60    [ IsList, IsGroup, IsGeneralMapping ], 0,
61function( src, rng, map )
62
63    local obj;
64
65    obj := rec();
66    if not ( Length(src)=2 ) and IsGroup(src[1]) and IsGroup(src[2]) then
67        Error( "the first parameter should be a list of two groups" );
68    fi;
69    ObjectifyWithAttributes( obj, CrossedPairingType,
70        Source, src,
71        Range, rng,
72        CrossedPairingMap, map,
73        IsCrossedPairing, true );
74    return obj;
75end );
76
77InstallMethod( PrintObj, "method for a crossed pairing", true,
78    [ IsCrossedPairing ], 0,
79function( h )
80    local map;
81    map := CrossedPairingMap( h );
82    Print( "crossed pairing: ", Source(map), " -> ", Range(map) );
83end );
84
85#############################################################################
86##
87#M  ImageElmCrossedPairing( <map>, <elm> )  . . . . . . . for crossed pairing
88##
89InstallMethod( ImageElmCrossedPairing, "for crossed pairing", true,
90    [ IsCrossedPairing, IsList ], 0,
91function ( xp, elm )
92    return ImageElmMapping2ArgumentsByFunction( CrossedPairingMap(xp), elm );
93end );
94
95##############################################################################
96##
97#M  CrossedPairingByCommutators( <grp>, <grp>, <grp> ) . . . . . make an xpair
98##
99InstallMethod( CrossedPairingByCommutators, "for three groups", true,
100    [ IsGroup, IsGroup, IsGroup ], 0,
101function( N, M, L )
102
103    local map, xp;
104
105    if not IsSubgroup( L, CommutatorSubgroup(N,M) ) then
106        Error( "require CommutatorSubgroup(N,M) <= L" );
107    fi;
108    map := Mapping2ArgumentsByFunction( [N,M], L,
109               function(c) return Comm( c[1], c[2] ); end );
110    xp := CrossedPairingObj( [N,M], L, map );
111    return xp;
112end );
113
114##############################################################################
115##
116#M  CrossedPairingByConjugators( <grp> ) . . . make an xpair : Inn(M)^2 -> M
117##
118InstallMethod( CrossedPairingByConjugators, "for an inner automorphism group",
119    true, [ IsGroup ], 0,
120function( innM )
121
122    local gens, M, map, xp;
123
124    gens := GeneratorsOfGroup( innM );
125    if not ForAll( gens, g -> HasConjugatorOfConjugatorIsomorphism(g) ) then
126        Error( "innM is not a group of inner automorphisms" );
127    fi;
128    M := Source( gens[1] );
129    map := Mapping2ArgumentsByFunction( [ innM, innM ], M,
130               function(p)
131               local c1, c2;
132               c1 := ConjugatorOfConjugatorIsomorphism( p[1] );
133               c2 := ConjugatorOfConjugatorIsomorphism( p[2] );
134               return Comm( c1, c2 ); end );
135    xp := CrossedPairingObj( [ innM, innM ], M, map );
136    return xp;
137end );
138
139##############################################################################
140##
141#M  CrossedPairingByDerivations( <xmod> ) . . .  make an actor crossed pairing
142##
143InstallMethod( CrossedPairingByDerivations, "for a crossed module", true,
144    [ IsXMod ], 0,
145function( X0 )
146
147    local SX, RX, WX, reg, imlist, map;
148
149    SX := Source( X0 );
150    RX := Range( X0 );
151    WX := WhiteheadPermGroup( X0 );
152    reg := RegularDerivations( X0 );
153    imlist := ImagesList( reg );
154    map := Mapping2ArgumentsByFunction( [RX,WX], SX,
155               function(t)
156                   local pos, chi;
157                   pos := Position( Elements( WX ), t[2] );
158                   chi := DerivationByImages( X0, imlist[pos] );
159                   return DerivationImage( chi, t[1] );
160               end );
161    return CrossedPairingObj( [RX,WX], SX, map );
162end );
163
164##############################################################################
165##
166#M  CrossedPairingByPreImages( <xmod>, <xmod> ) . . . inner autos -> x-pairing
167##
168InstallMethod( CrossedPairingByPreImages, "for two crossed modules",
169    true, [ IsXMod, IsXMod ], 0,
170function( up, lt )
171
172    local L, M, N, kappa, lambda, map, xp;
173
174    L := Source( up );
175    if not ( Source( lt ) = L ) then
176        Error( "up and lt should have the same source" );
177    fi;
178    M := Range( up );
179    N := Range( lt );
180    kappa := Boundary( up );
181    lambda := Boundary( lt );
182    map := Mapping2ArgumentsByFunction( [N,M], L,
183               function( c )
184                   local lm, ln;
185                   lm := PreImagesRepresentative( kappa, c[2] );
186                   ln := PreImagesRepresentative( lambda, c[1] );
187                   return Comm( ln, lm );
188               end );
189    xp := CrossedPairingObj( [N,M], L, map );
190    return xp;
191end );
192
193##############################################################################
194##
195#M  CrossedPairingBySingleXModAction( <xmod>, <subxmod> ) . action -> x-pairing
196#M  PrincipalCrossedPairing( <xmod > )
197##
198InstallMethod( CrossedPairingBySingleXModAction, "for xmod and normal subxmod",
199    true, [ IsXMod, IsXMod ], 0,
200function( rt, lt )
201
202    local M, L, N, act, map, xp;
203
204    if not IsNormalSub2DimensionalDomain( rt, lt ) then
205        Error( "lt not a normal subxmod of rt" );
206    fi;
207    M := Source( rt );
208    L := Source( lt );
209    N := Range( lt );
210    act := XModAction( rt );
211    map := Mapping2ArgumentsByFunction( [N,M], L,
212               function( c )
213                   return ImageElm( ImageElm( act, c[1] ), c[2]^(-1) ) * c[2];
214               end );
215    xp := CrossedPairingObj( [N,M], L, map );
216    return xp;
217end );
218
219InstallMethod( PrincipalCrossedPairing, "for an xmod", true, [ IsXMod ], 0,
220function( X0 )
221    return CrossedPairingBySingleXModAction( X0, X0 );
222end );
223
224#############################################################################
225##
226#M  IsPreCrossedSquare . . . . . . . . . . . . check that the square commutes
227##
228InstallMethod( IsPreCrossedSquare, "generic method for a pre-crossed square",
229    true, [ IsHigherDimensionalGroup ], 0,
230function( PXS )
231
232    local up, lt, rt, dn, dg, L, M, N, P, kappa, lambda, mu, nu, delta,
233          lambdanu, kappamu, ok, actrt, rngactrt, actdn, rngactdn,
234          genN, genM, imactNM, actNM, imactMN, actMN, morupdn, morltrt;
235
236    if not IsPreCrossedSquareObj( PXS ) then
237        return false;
238    fi;
239    up := Up2DimensionalGroup( PXS );
240    lt := Left2DimensionalGroup( PXS );
241    rt := Right2DimensionalGroup( PXS );
242    dn := Down2DimensionalGroup( PXS );
243    dg := Diagonal2DimensionalGroup( PXS );
244    L := Source( up );
245    M := Range( up );
246    N := Source( dn );
247    P := Range( dn );
248    if not ( ( L = Source(lt) ) and ( N = Range(lt) ) and
249             ( L = Source(dg) ) and ( P = Range(dg) ) and
250             ( M = Source(rt) ) and ( P = Range(rt) ) ) then
251        Info( InfoXMod, 2, "Incompatible source/range" );
252        return false;
253    fi;
254    ## checks for the diagonal
255    delta := Boundary( dg );
256    lambda := Boundary( lt );
257    nu := Boundary( dn );
258    lambdanu := lambda * nu;
259    kappa := Boundary( up );
260    mu := Boundary( rt );
261    kappamu := kappa * mu;
262    if not ( lambdanu = delta ) and ( kappamu = delta ) then
263        Info( InfoXMod, 2, "boundaries in square do not commute" );
264        return false;
265    fi;
266    # construct the cross-diagonal actions
267    actrt := XModAction( rt );
268    rngactrt := Range( actrt );
269    actdn := XModAction( dn );
270    rngactdn := Range( actdn );
271    genM := GeneratorsOfGroup( M );
272    genN := GeneratorsOfGroup( N );
273    imactNM := List( genN, n -> ImageElm( actrt, ImageElm( nu, n ) ) );
274    actNM := GroupHomomorphismByImages( N, rngactrt, genN, imactNM );
275    imactMN := List( genM, m -> ImageElm( actdn, ImageElm( mu, m ) ) );
276    actMN := GroupHomomorphismByImages( M, rngactdn, genM, imactMN );
277    SetCrossDiagonalActions( PXS, [ actNM, actMN ] );
278    #? compatible actions to be checked?
279    morupdn := PreXModMorphism( up, dn, lambda, mu );
280    morltrt := PreXModMorphism( lt, rt, kappa, nu );
281    if not ( IsPreXModMorphism(morupdn) and IsPreXModMorphism(morltrt) ) then
282        Info( InfoXMod, 2, "morupdn and/or modltrt not prexmod morphisms" );
283        return false;
284    fi;
285    return true;
286end );
287
288#############################################################################
289##
290#M  IsCrossedSquare . . . . . . . . check all the axioms for a crossed square
291##
292InstallMethod( IsCrossedSquare, "generic method for a crossed square",
293    true, [ IsHigherDimensionalGroup ], 0,
294function( XS )
295
296    local up, lt, rt, dn, L, M, N, P, kappa, lambda, mu, nu,
297          lambdanu, kappamu, autu, autl, actdg, dg, ok, morud, morlr,
298          genL, genM, genN, genP, actup, actlt, actrt, actdn, l, p,
299          xp, x, y, z, m, n, m2, n2, am, an, apdg, aprt, apdn, nboxm;
300
301    if not ( IsPreCrossedSquare( XS ) and HasCrossedPairing( XS ) ) then
302        return false;
303    fi;
304    up := Up2DimensionalGroup( XS );
305    lt := Left2DimensionalGroup( XS );
306    rt := Right2DimensionalGroup( XS );
307    dn := Down2DimensionalGroup( XS );
308    dg := Diagonal2DimensionalGroup( XS );
309    L := Source( up );
310    M := Range( up );
311    N := Source( dn );
312    P := Range( dn );
313    kappa := Boundary( up );
314    lambda := Boundary( lt );
315    mu := Boundary( rt );
316    nu := Boundary( dn );
317    genL := GeneratorsOfGroup( L );
318    genM := GeneratorsOfGroup( M );
319    genN := GeneratorsOfGroup( N );
320    genP := GeneratorsOfGroup( P );
321    actup := XModAction( up );
322    actlt := XModAction( lt );
323    actrt := XModAction( rt );
324    actdn := XModAction( dn );
325    actdg := XModAction( dg );
326    ## check that kappa,lambda preserve the action of P
327    for p in genP do
328        apdg := ImageElm( actdg, p );
329        aprt := ImageElm( actrt, p );
330        apdn := ImageElm( actdn, p );
331        for l in genL do
332            if not ( ImageElm( kappa, ImageElm( apdg, l ) )
333                     = ImageElm( aprt, ImageElm( kappa, l ) ) ) then
334                Info( InfoXMod, 2,  "action of P on up is not preserved" );
335                return false;
336            fi;
337            if not ( ImageElm( lambda, ImageElm( apdg, l ) )
338                     = ImageElm( apdn, ImageElm( lambda, l ) ) ) then
339                Info( InfoXMod, 2, "action of P on lt is not preserved" );
340                return false;
341            fi;
342        od;
343    od;
344    ## check the axioms for a crossed pairing
345    xp := CrossedPairing( XS );
346    for n in genN do
347        for n2 in genN do
348            for m in genM do
349                x := ImageElmCrossedPairing( xp, [ n*n2, m ] );
350                an := ImageElm( actlt, n2 );
351                y := ImageElm( an, ImageElmCrossedPairing( xp, [n,m] ) );
352                z := ImageElmCrossedPairing( xp, [n2,m] );
353                if not x = y * z then
354                    Info( InfoXMod, 2, "n1,n2,m crossed pairing axiom fails" );
355                    return false;
356                fi;
357            od;
358       od;
359    od;
360    for n in genN do
361        for m in genM do
362            for m2 in genM do
363                x := ImageElmCrossedPairing( xp, [ n, m*m2 ] );
364                am := ImageElm( actup, m2 );
365                y := ImageElm( am, ImageElmCrossedPairing( xp, [n,m] ) );
366                if not x = ImageElmCrossedPairing( xp, [n,m2] ) * y then
367                    Info( InfoXMod, 2, "n,m1,m2 crossed pairing axiom fails" );
368                    return false;
369                fi;
370            od;
371       od;
372    od;
373    for p in genP do
374        apdg := ImageElm( actdg, p );
375        aprt := ImageElm( actrt, p );
376        apdn := ImageElm( actdn, p );
377        for n in genN do
378            for m in genM do
379                if not ImageElm( apdg, ImageElmCrossedPairing( xp, [n,m] ) )
380                     = ImageElmCrossedPairing( xp,
381                           [ ImageElm( apdn, n ), ImageElm( aprt, m ) ] ) then
382                    Info( InfoXMod, 2, "n,m,p crossed pairing axiom fails" );
383                    return false;
384                fi;
385            od;
386       od;
387    od;
388    ## check that kappa,lambda correctly map (n box m)
389    for n in genN do
390        an := ImageElm( actrt, ImageElm( nu, n ) );
391        for m in genM do
392            am := ImageElm( actdn, ImageElm( mu, m ) );
393            nboxm := ImageElmCrossedPairing( xp, [n,m] );
394            if not ImageElm( lambda, nboxm ) = n^(-1) * ImageElm( am, n )
395               and ImageElm( kappa, nboxm ) = ImageElm( an, m^(-1) ) * m then
396                Info( InfoXMod, 2,  "kappa,lambda do not map nboxm correctly" );
397                return false;
398            fi;
399        od;
400    od;
401    ## check crossed pairing on images of kappa,lambda
402    for m in genM do
403        ## am := ImageElm( actdg, ImageElm( mu, m ) );
404        am := ImageElm( actup, m );
405        for l in genL do
406            if not ( ImageElmCrossedPairing( xp, [ImageElm(lambda,l),m] )
407                   = l^(-1) * ImageElm( am, l ) ) then
408                Info( InfoXMod, 2, "incorrect image for (lambda(l) box n)" );
409                return false;
410            fi;
411        od;
412    od;
413    for n in genN do
414        ## an := ImageElm( actdg, ImageElm( nu, n ) );
415        an := ImageElm( actlt, n );
416        for l in genL do
417            if not ( ImageElmCrossedPairing( xp, [n,ImageElm(kappa,l)] )
418                   = ImageElm( an, l^(-1) ) * l ) then
419                Info( InfoXMod, 2, "incorrect image for (n box kappa(l))" );
420                return false;
421            fi;
422        od;
423    od;
424    return true;
425end );
426
427##############################################################################
428##
429#M  PreCrossedSquareObj ( <up>, <left>, <right>, <down>, <diag>, <pair> )
430##                                               . . . make a PreCrossedSquare
431##
432InstallMethod( PreCrossedSquareObj, "for prexmods, action and pairing", true,
433    [ IsPreXMod, IsPreXMod, IsPreXMod, IsPreXMod, IsObject, IsObject ], 0,
434function( up, lt, rt, dn, dg, xp )
435
436    local PS;
437
438    ## test commutativity here?
439    PS := rec();
440    ObjectifyWithAttributes( PS, PreCrossedSquareObjType,
441      Up2DimensionalGroup, up,
442      Left2DimensionalGroup, lt,
443      Right2DimensionalGroup, rt,
444      Down2DimensionalGroup, dn,
445      Diagonal2DimensionalGroup, dg,
446      CrossedPairing, xp,
447      HigherDimension, 3,
448      IsHigherDimensionalGroup, true );
449    if not IsPreCrossedSquare( PS ) then
450        Info( InfoXMod, 1, "Warning: not a pre-crossed square." );
451    fi;
452    return PS;
453end );
454
455###############################################################################
456##
457#F  PreCrossedSquare( <up>, <lt>, <rt>, <dn>, <dg>, <xp> ) 5 prexmods + pairing
458#F  PreCrossedSquare( <PC2> )  . . . . . . . . . . . . . . for a pre-cat2-group
459##
460InstallGlobalFunction( PreCrossedSquare, function( arg )
461
462    local nargs, PXS, ok;
463
464    nargs := Length( arg );
465    ok := true;
466    if ( nargs = 1 ) then
467        if ( HasIsPreCat2Group( arg[1] ) and IsPreCat2Group( arg[1] ) ) then
468            Info( InfoXMod, 1, "pre-crossed square of a pre-cat2-group" );
469            PXS := PreCrossedSquareOfPreCat2Group( arg[1] );
470        else
471            ok := false;
472        fi;
473    elif ( nargs = 6  ) then
474        PXS := PreCrossedSquareByPreXMods(
475                   arg[1], arg[2], arg[3], arg[4], arg[5], arg[6] );
476    else
477        ok := false;
478    fi;
479    if not ok then
480        Print( "standard usage for the function PreCrossedSquare:\n" );
481        Print( "    PreCrossedSquare( <up>, <lt>, <rt>, <dn>, <dg>, <xp> );\n" );
482        Print( "             for 5 pre-crossed modules and a crossed pairing\n" );
483        Print( "or: PreCrossedSquare( <PC2G> );  for a pre-cat2-group> );\n" );
484        return fail;
485    fi;
486    return PXS;
487end );
488
489
490#############################################################################
491##
492#F  CrossedSquare( <up>, <lt>, <rt>, <dn>, <dg>, <xp> ) 5 xmods and a pairing
493#F  CrossedSquare( <L>, <M>, <N>, <P> ) . . . . . . . . by normal subgroups
494#F  CrossedSquare( <X0> ) . . . . . . . . . . . . . . . actor crossed square
495#F  CrossedSquare( <X0>, <X1> ) . . . . . . . . . . . . by pullback
496#F  CrossedSquare( <X0>, <X1> ) . . . . . . . . . . . . by normal subxmod
497#F  CrossedSquare( <C2G> )  . . . . . . . . . . . . . . for a cat2-group
498##
499InstallGlobalFunction( CrossedSquare, function( arg )
500
501    local nargs, XS, ok;
502
503    nargs := Length( arg );
504    ok := true;
505    if ( nargs = 1 ) then
506        if ( HasIsXMod( arg[1] ) and IsXMod( arg[1] ) ) then
507            Info( InfoXMod, 1, "crossed square by splitting" );
508            XS := CrossedSquareByXModSplitting( arg[1] );
509        elif ( HasIsCat2Group( arg[1] ) and IsCat2Group( arg[1] ) ) then
510            Info( InfoXMod, 1, "crossed square of a cat2-group" );
511            XS := PreCrossedSquareOfPreCat2Group( arg[1] );
512        else
513            ok := false;
514        fi;
515    elif ( nargs = 2 ) then
516        if ( HasIsXMod( arg[1] ) and IsXMod( arg[1] )
517             and HasIsXMod( arg[2] ) and IsXMod( arg[2] ) ) then
518            if Range( arg[1] ) = Range( arg[2] ) then
519                Info( InfoXMod, 1, "crossed square by pullback" );
520                XS := CrossedSquareByPullback( arg[1], arg[2] );
521            elif IsNormalSub2DimensionalDomain( arg[1], arg[2] ) then
522                Info( InfoXMod, 1, "crossed square by normal subxmod" );
523                XS := CrossedSquareByNormalSubXMod( arg[1], arg[2] );
524            else
525                ok := false;
526            fi;
527        else
528            ok := false;
529        fi;
530    elif ( nargs = 4 ) and ForAll( arg, a -> IsGroup(a) ) then
531        XS := CrossedSquareByNormalSubgroups(arg[1],arg[2],arg[3],arg[4]);
532    elif ( nargs = 6  ) then
533        XS := CrossedSquareByXMods(arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
534    else
535        ok := false;
536    fi;
537    if not ok then
538        Print( "standard usage for the function CrossedSquare:\n" );
539        Print( "    CrossedSquare( <up>, <lt>, <rt>, <dn>, <dg>, <xp> );\n" );
540        Print( "             for 5 crossed modules and a crossed pairing\n" );
541        Print( "or: CrossedSquare( <L>, <M>, <N>, <P> );  " );
542        Print( "for 3 normal subgroups of P\n" );
543        Print( "or: CrossedSquare( <X0>, <X1> );  for a pullback\n" );
544        Print( "or: CrossedSquare( <X0>, <X1> );  for a normal subxmod\n" );
545        Print( "or: CrossedSquare( <X0> );  for splitting an xmod\n" );
546        Print( "or: CrossedSquare( <C2G> );  for a cat2-group> );\n" );
547        return fail;
548    fi;
549    return XS;
550end );
551
552##############################################################################
553##
554#M  PreCrossedSquareByPreXMods . . pre-crossed square from 5 pre-xmods + xpair
555#M  CrossedSquareByXMods . . . . . . . . . crossed square from 5 xmods + xpair
556##
557InstallMethod( PreCrossedSquareByPreXMods, "default pre-crossed square", true,
558    [ IsPreXMod, IsPreXMod, IsPreXMod, IsPreXMod, IsPreXMod, IsCrossedPairing ],
559    0,
560function( up, left, right, down, diag, xp )
561
562    local L, M, N, P, kappa, lambda, mu, nu, delta, PXS;
563
564    L := Source( up );
565    M := Range( up );
566    N := Source( down );
567    P := Range( down );
568    kappa := Boundary( up );
569    lambda := Boundary( left );
570    mu := Boundary( right );
571    nu := Boundary( down );
572    delta := Boundary( diag );
573    ## checks
574    if not ( ( L = Source( left ) ) and ( N = Range( left ) )
575         and ( M = Source( right ) ) and ( P = Range( right ) )
576         and ( L = Source( diag ) ) and ( P = Range( diag ) ) ) then
577        Error( "sources and ranges not matching" );
578    fi;
579    if not ( ( L = Range( xp ) ) and ( [N,M] = Source( xp ) ) ) then
580        Error( "incorrect source/range for crossed pairing" );
581    fi;
582
583    PXS := PreCrossedSquareObj( up, left, right, down, diag, xp );
584    if not IsPreCrossedSquare( PXS ) then
585        Error( "PXS fails to be a crossed square" );
586    fi;
587    return PXS;
588end );
589
590InstallMethod( CrossedSquareByXMods, "default crossed square", true,
591    [ IsXMod, IsXMod, IsXMod, IsXMod, IsXMod, IsCrossedPairing ], 0,
592function( up, left, right, down, diag, xp )
593
594    local XS;
595
596    XS := PreCrossedSquareByPreXMods( up, left, right, down, diag, xp );
597    if not IsCrossedSquare( XS ) then
598        Info( InfoXMod, 1, "XS fails to be a crossed square" );
599        return fail;
600    fi;
601    return XS;
602end );
603
604##############################################################################
605##
606#M  CrossedSquareByNormalSubgroups . . . crossed square from normal L,M,N in P
607##
608InstallMethod( CrossedSquareByNormalSubgroups, "conjugation crossed square",
609    true, [ IsGroup, IsGroup, IsGroup, IsGroup ], 0,
610function( L, M, N, P )
611
612    local XS, up, lt, rt, dn, dg, xp, diag;
613
614    if not ( IsNormal( P, M ) and IsNormal( P, N ) and IsNormal( L, P ) ) then
615        Error( "M,N,L fail to be normal subgroups of P" );
616    fi;
617    if not ( IsNormal( M, L ) and IsNormal( N, L ) ) then
618        Error( "L fails to be a normal subgroup of both M and N" );
619    fi;
620    if not ( IsSubgroup( Intersection(M,N), L )
621         and IsSubgroup( L, CommutatorSubgroup(M,N) ) ) then
622        Error( "require CommutatorSubgroup(M,N) <= L <= Intersection(M,N)" );
623    fi;
624    up := XModByNormalSubgroup( M, L );
625    lt := XModByNormalSubgroup( N, L );
626    rt := XModByNormalSubgroup( P, M );
627    dn := XModByNormalSubgroup( P, N );
628    dg := XModByNormalSubgroup( P, L );
629    ##  define the pairing as a commutator
630    xp := CrossedPairingByCommutators( N, M, L );
631    XS := PreCrossedSquareObj( up, lt, rt, dn, dg, xp );
632##    SetIsCrossedSquare( XS, true );
633##    SetIs3DimensionalGroup( XS, true );
634    SetDiagonal2DimensionalGroup( XS, dg );
635    if not IsCrossedSquare( XS ) then
636        Error( "XS fails to be a crossed square by normal subgroups" );
637    fi;
638    return XS;
639end );
640
641InstallMethod( CrossedSquareByNormalSubgroups,
642    "conjugation crossed square", true, [ IsGroup, IsGroup, IsGroup ], 0,
643function( M, N, P )
644
645    local XS, genP, genM, genN, L, genL, u, d, l, r, a, p, diag;
646
647    if not ( IsNormal( P, M ) and IsNormal( P, N ) ) then
648        return fail;
649    fi;
650    L := Intersection( M, N );
651    return CrossedSquareByNormalSubgroups( L, M, N, P );
652end );
653
654###############################################################################
655##
656#M  CrossedSquareByNormalSubXMod . crossed square from xmod and normal subxmod
657##
658InstallMethod( CrossedSquareByNormalSubXMod, "for an xmod and normal subxmod",
659    true, [ IsXMod, IsXMod ], 0,
660function( rt, lt )
661
662    local M, L, up, P, N, dn, xp, dg, XS;
663
664    if not IsNormalSub2DimensionalDomain( rt, lt ) then
665        return fail;
666    fi;
667    M := Source( rt );
668    L := Source( lt );
669    up := XModByNormalSubgroup( M, L );
670    P := Range( rt );
671    N := Range( lt );
672    dn := XModByNormalSubgroup( P, N );
673    xp := CrossedPairingBySingleXModAction( rt, lt );
674    dg := SubXMod( rt, L, P );
675    XS := PreCrossedSquareObj( up, lt, rt, dn, dg, xp );
676    if not IsCrossedSquare( XS ) then
677        Error( "XS fails to be a crossed square by normal subxmod" );
678    fi;
679    return XS;
680end );
681
682###############################################################################
683##
684#M  CrossedSquareByXModSplitting . . . xsq by surjection followed by injection
685##
686InstallMethod( CrossedSquareByXModSplitting, "for an xmod", true, [ IsXMod ], 0,
687function( X0 )
688
689    local S, R, bdy, Q, up, dn, xp, XS;
690
691    S := Source( X0 );
692    R := Range( X0 );
693    Q := ImagesSource( Boundary( X0 ) );
694    up := SubXMod( X0, S, Q );
695    dn := XModByNormalSubgroup( R, Q );
696    xp := CrossedPairingByPreImages( up, up );
697    XS := PreCrossedSquareObj( up, up, dn, dn, X0, xp );
698##    SetIsCrossedSquare( XS, true );
699    if not IsCrossedSquare( XS ) then
700        Error( "XS fails to be a crossed square by xmod splitting" );
701    fi;
702    return XS;
703end );
704
705##############################################################################
706##
707#M  CrossedSquareByPullback . . . . . . . . for two xmods with a common range
708##
709InstallMethod( CrossedSquareByPullback, "for 2 xmods with a common range",
710    true, [ IsXMod, IsXMod ], 0,
711function( dn, rt )
712
713    local M, N, P, actM, actN, mu, nu, L, genL, lenL, Linfo, dp, dpinfo,
714          embM, embN, kappa, lambda, map, xp, autL, genLN, genLM, genLNP,
715          genLMP, genP, lenP, imactPL, i, g, ima, a, actPL, genN, lenN,
716          imactNL, actNL, lt, genM, lenM, imactML, actML, up,
717          imdelta, delta, dg, XS;
718
719    M := Source( rt );
720    N := Source( dn );
721    P := Range( rt );
722    if not ( Range( dn ) = P ) then
723        Error( "the two xmods should have a common range" );
724    fi;
725    actM := XModAction( rt );
726    actN := XModAction( dn );
727    mu := Boundary( rt );
728    nu := Boundary( dn );
729    L := Pullback( nu, mu );
730    genL := GeneratorsOfGroup( L );
731    lenL := Length( genL );
732    Linfo := PullbackInfo( L );
733    if HasName(M) and HasName(N) and HasName(P) then
734        SetName( L, Concatenation("(",Name(N)," x_",Name(P)," ",Name(M),")") );
735    fi;
736    dp := Linfo!.directProduct;
737    dpinfo := DirectProductInfo( dp );
738    embN := Embedding( dp, 1 );
739    embM := Embedding( dp, 2 );
740    lambda := Linfo!.projections[1];
741    genLN := List( genL, l -> ImageElm( lambda, l ) );
742    kappa := Linfo!.projections[2];
743    genLM := List( genL, l -> ImageElm( kappa, l ) );
744    ## construct the crossed pairing
745    map := Mapping2ArgumentsByFunction( [N,M], L,
746               function( c )
747                   local n, m, nun, mum, n2, m2, l;
748                   n := c[1];
749                   m := c[2];
750                   nun := ImageElm( nu, n );
751                   mum := ImageElm( mu, m );
752                   ## h(n,m) = (n^{-1}.n^mum, (m^{-1})^nun.m)
753                   n2 := n^(-1) * ImageElm(ImageElm(actN,mum),n);
754                   m2 := ImageElm(ImageElm(actM,nun),m^(-1)) * m;
755                   l := ImageElm( embN, n2 ) * ImageElm( embM, m2 );
756                   if not ( l in L ) then
757                       Error( "element l appears not to be in L" );
758                   fi;
759                   return l;
760               end );
761    xp := CrossedPairingObj( [N,M], L, map );
762    autL := AutomorphismGroup( L );
763    genP := GeneratorsOfGroup( P );
764    lenP := Length( genP );
765    imactPL := ListWithIdenticalEntries( lenP, 0 );
766    for i in [1..lenP] do
767        g := genP[i];
768        genLNP := List( genLN, n -> ImageElm( ImageElm( actN, g ), n ) );
769        genLMP := List( genLM, m -> ImageElm( ImageElm( actM, g ), m ) );
770        ima := List( [1..lenL], j -> ImageElm( embN, genLNP[j] )
771                                     * ImageElm( embM, genLMP[j] ) );
772        a := GroupHomomorphismByImages( L, L, genL, ima );
773        imactPL[i] := a;
774    od;
775    actPL := GroupHomomorphismByImages( P, autL, genP, imactPL );
776    imdelta := List( genL, l -> ImageElm( nu, ImageElm( lambda, l ) ) );
777    delta := GroupHomomorphismByImages( L, P, genL, imdelta );
778    dg := XModByBoundaryAndAction( delta, actPL );
779    genN := GeneratorsOfGroup( N );
780    lenN := Length( genN );
781    imactNL := ListWithIdenticalEntries( lenN, 0 );
782    for i in [1..lenN] do
783        g := ImageElm( nu, genN[i] );
784        a := ImageElm( actPL, g );
785        imactNL[i] := a;
786    od;
787    actNL := GroupHomomorphismByImages( N, autL, genN, imactNL );
788    lt := XMod( lambda, actNL );
789    genM := GeneratorsOfGroup( M );
790    lenM := Length( genM );
791    imactML := ListWithIdenticalEntries( lenM, 0 );
792    for i in [1..lenM] do
793        g := ImageElm( mu, genM[i] );
794        a := ImageElm( actPL, g );
795        imactML[i] := a;
796    od;
797    actML := GroupHomomorphismByImages( M, autL, genM, imactML );
798    up := XMod( kappa, actML );
799    XS := PreCrossedSquareObj( up, lt, rt, dn, dg, xp );
800##    SetIsCrossedSquare( XS, true );
801    if not IsCrossedSquare( XS ) then
802        Error( "XS fails to be a crossed square by pullback" );
803    fi;
804    return XS;
805end );
806
807###############################################################################
808##
809#M  ActorCrossedSquare . . . create a crossed square from an xmod and its actor
810##
811InstallMethod( ActorCrossedSquare, "actor crossed square", true, [ IsXMod ], 0,
812function( X0 )
813
814    local XS, WX, LX, NX, AX, xp;
815
816    AX := ActorXMod( X0 );
817    WX := WhiteheadXMod( X0 );
818    NX := NorrieXMod( X0 );
819    LX := LueXMod( X0 );
820    ##  define the pairing as evaluation of a derivation
821    xp := CrossedPairingByDerivations( X0 );
822    ## XS := PreCrossedSquareObj( X0, WX, NX, AX, da, xp );
823    XS := PreCrossedSquareObj( WX, X0, AX, NX, LX, xp );
824##    SetIsCrossedSquare( XS, true );
825    if not IsCrossedSquare( XS ) then
826        Error( "XS fails to be an actor crossed square" );
827    fi;
828    return XS;
829end );
830
831###############################################################################
832##
833#M  CrossedSquareByAutomorphismGroup . . . crossed square G -> Inn(G) -> Aut(G)
834##
835InstallMethod( CrossedSquareByAutomorphismGroup, "G -> Inn(G) -> Aut(G)",
836    true, [ IsGroup ], 0,
837function( G )
838
839    local genG, innG, up, autG, lt, dg, xp, XS;
840
841    genG := GeneratorsOfGroup( G );
842    innG := InnerAutomorphismsByNormalSubgroup( G, G );
843    if ( not HasName( innG ) and HasName( G ) ) then
844        SetName( innG, Concatenation( "Inn(", Name( G ), ")" ) );
845    fi;
846    SetIsGroupOfAutomorphisms( innG, true );
847    up := XModByGroupOfAutomorphisms( G, innG );
848    autG := AutomorphismGroup( G );
849    if ( not HasName( autG ) and HasName( G ) ) then
850        SetName( autG, Concatenation( "Aut(", Name( G ), ")" ) );
851    fi;
852    if not IsSubgroup( autG, innG ) then
853        Error( "innG is not a subgroup of autG" );
854    fi;
855    dg := XModByAutomorphismGroup( G );
856    lt := XModByNormalSubgroup( autG, innG );
857    ##  define the pairing
858    xp := CrossedPairingByConjugators( innG );
859    XS := PreCrossedSquareObj( up, up, lt, lt, dg, xp );
860##    SetIsCrossedSquare( XS, true );
861    if not IsCrossedSquare( XS ) then
862        Error( "XS fails to be a crossed square by automorphism group" );
863    fi;
864    return XS;
865end );
866
867#############################################################################
868##
869#M  Name . . . . . . . . . . . . . . . . . . . . .  for a 3-dimensional group
870##
871InstallOtherMethod( Name, "method for a pre-crossed square", true,
872    [ IsHigherDimensionalGroup ], 0,
873function( PS )
874
875    local nul, nur, ndl, ndr, name, mor;
876
877    if not ( HigherDimension( PS ) = 3 ) then
878        TryNextMethod();
879    else
880        if HasName( Source( Up2DimensionalGroup( PS ) ) ) then
881            nul := Name( Source( Up2DimensionalGroup( PS ) ) );
882        else
883            nul := "..";
884        fi;
885        if HasName( Range( Up2DimensionalGroup( PS ) ) ) then
886            nur := Name( Range( Up2DimensionalGroup( PS ) ) );
887        else
888            nur := "..";
889        fi;
890        if HasName( Source( Down2DimensionalGroup( PS ) ) ) then
891            ndl := Name( Source( Down2DimensionalGroup( PS ) ) );
892        else
893            ndl := "..";
894        fi;
895        if HasName( Range( Down2DimensionalGroup( PS ) ) ) then
896            ndr := Name( Range( Down2DimensionalGroup( PS ) ) );
897        else
898            ndr := "..";
899        fi;
900        name := Concatenation( "[", nul, "->", nur, ",", ndl, "->", ndr, "]" );
901        SetName( PS, name );
902        return name;
903    fi;
904end );
905
906#############################################################################
907##
908#M  Size . . . . . . . . . . . . . . . . . . . . .  for a 3-dimensional group
909##
910InstallOtherMethod( Size, "method for a 3-dimensional group", true,
911    [ IsHigherDimensionalGroup ], 0,
912function( PS )
913    return [ Size( Source( Up2DimensionalGroup( PS ) ) ),
914             Size( Range( Up2DimensionalGroup( PS ) ) ),
915             Size( Source( Down2DimensionalGroup( PS ) ) ),
916             Size( Range( Down2DimensionalGroup( PS ) ) ) ];
917end );
918
919#############################################################################
920##
921#M  IdGroup . . . . . . . . . . . . . . . . . . . . for a 3-dimensional group
922##
923InstallOtherMethod( IdGroup, "method for a 3-dimensional group", true,
924    [ IsHigherDimensionalGroup ], 0,
925function( PS )
926    return [ IdGroup( Source( Up2DimensionalGroup( PS ) ) ),
927             IdGroup( Range( Up2DimensionalGroup( PS ) ) ),
928             IdGroup( Source( Down2DimensionalGroup( PS ) ) ),
929             IdGroup( Range( Down2DimensionalGroup( PS ) ) ) ];
930end );
931
932#############################################################################
933##
934#M  StructureDescription  . . . . . . . . . . . . . for a 3-dimensional group
935##
936InstallOtherMethod( StructureDescription, "method for a 3-dimensional group",
937    true, [ IsHigherDimensionalGroup ], 0,
938function( PS )
939    return [ StructureDescription( Source( Up2DimensionalGroup( PS ) ) ),
940             StructureDescription( Range( Up2DimensionalGroup( PS ) ) ),
941             StructureDescription( Source( Down2DimensionalGroup( PS ) ) ),
942             StructureDescription( Range( Down2DimensionalGroup( PS ) ) ) ];
943end );
944
945##############################################################################
946##
947#M  \=( <dom1>, <dom2> ) . . . . . . . . . . test if two 3d-objects are equal
948##
949InstallMethod( \=,
950    "generic method for two 3d-domains",
951    IsIdenticalObj, [ IsHigherDimensionalGroup, IsHigherDimensionalGroup ], 0,
952function ( dom1, dom2 )
953    if not ( ( HigherDimension( dom1 ) = 3 )
954           and ( HigherDimension( dom2 ) = 3 ) ) then
955        TryNextMethod();
956    else
957        return(
958            ( Up2DimensionalGroup(dom1) = Up2DimensionalGroup(dom2) )
959        and ( Left2DimensionalGroup(dom1) = Left2DimensionalGroup(dom2) )
960        and ( Right2DimensionalGroup(dom1) = Right2DimensionalGroup(dom2) )
961        and ( Down2DimensionalGroup(dom1) = Down2DimensionalGroup(dom2) )
962        and ( Diagonal2DimensionalGroup(dom1)
963              = Diagonal2DimensionalGroup(dom2) ) );
964    fi;
965end );
966
967#############################################################################
968##
969#M  String, ViewString, PrintString, ViewObj, PrintObj . . . . for a 3d-group
970##
971InstallMethod( String, "for a 3d-group", true, [ IsPreCrossedSquare ], 0,
972function( g3d )
973    return( STRINGIFY( "pre-crossed square" ) );
974end );
975
976InstallMethod( ViewString, "for a 3d-group", true, [ IsPreCrossedSquare ],
977    0, String );
978
979InstallMethod( PrintString, "for a 3d-group", true, [ IsPreCrossedSquare ],
980    0, String );
981
982InstallMethod( PrintObj, "method for a 3d-group", true,
983    [ IsPreCrossedSquare ], 0,
984function( g3d )
985
986    local L, M, N, P, lenL, lenM, lenN, lenP, len1, len2, j, q1, q2,
987           ispsq, arrow, ok, n, i;
988
989    if HasName( g3d ) then
990        Print( Name( g3d ), "\n" );
991    else
992        if ( HasIsPreCrossedSquare( g3d ) and IsPreCrossedSquare( g3d ) ) then
993            ispsq := true;
994            arrow := " -> ";
995        else
996            ispsq := false;
997            arrow := " => ";
998        fi;
999        L := Source( Up2DimensionalGroup( g3d ) );
1000        M := Range( Up2DimensionalGroup( g3d ) );
1001        N := Source( Down2DimensionalGroup( g3d ) );
1002        P := Range( Down2DimensionalGroup( g3d ) );
1003        ok := HasName(L) and HasName(M) and HasName(N) and HasName(P);
1004        if ok then
1005            lenL := Length( Name( L ) );
1006            lenM := Length( Name( M ) );
1007            lenN := Length( Name( N ) );
1008            lenP := Length( Name( P ) );
1009            len1 := Maximum( lenL, lenN );
1010            len2 := Maximum( lenM, lenP );
1011            q1 := QuoInt( len1, 2 );
1012            q2 := QuoInt( len2, 2 );
1013            Print( "[ " );
1014            for j in [1..lenN-lenL] do Print(" "); od;
1015            Print( Name(L), arrow, Name(M) );
1016            for j in [1..lenP-lenM] do Print(" "); od;
1017            Print( " ]\n[ " );
1018            for j in [1..q1] do Print(" "); od;
1019            Print( "|" );
1020            for j in [1..q1+RemInt(len1,2)+2+q2+RemInt(len2,2)] do
1021                Print(" ");
1022            od;
1023            Print( "|" );
1024            for j in [1..q2] do Print(" "); od;
1025            Print( " ]\n" );
1026            Print( "[ " );
1027            for j in [1..lenL-lenN] do Print(" "); od;
1028            Print( Name(N), " -> ", Name(P) );
1029            for j in [1..lenM-lenP] do Print(" "); od;
1030            Print( " ]\n" );
1031        else
1032            if ispsq then
1033                if ( HasIsCrossedSquare(g3d) and IsCrossedSquare(g3d) ) then
1034                    Print( "crossed square with crossed modules:\n" );
1035                else
1036                    Print( "pre-crossed square with pre-crossed modules:\n" );
1037                fi;
1038            fi;
1039            Print( "      up = ",    Up2DimensionalGroup( g3d ), "\n" );
1040            Print( "    left = ",  Left2DimensionalGroup( g3d ), "\n" );
1041            Print( "   right = ", Right2DimensionalGroup( g3d ), "\n" );
1042            Print( "    down = ",  Down2DimensionalGroup( g3d ), "\n" );
1043        fi;
1044    fi;
1045end );
1046
1047InstallMethod( ViewObj, "method for a 3d-group", true, [ IsPreCrossedSquare ],
1048    0, PrintObj );
1049
1050#############################################################################
1051##
1052#M Display( <g3d> . . . . . . . . . . . . . . . . . . . . display a 3d-group
1053##
1054InstallMethod( Display, "method for a pre-cat2-group", true,
1055    [ IsPreCat2Group ], 0,
1056function( g3d )
1057
1058    local up, tup, hup, lt, tlt, hlt, rt, trt, hrt, dn, tdn, hdn;
1059
1060    up := Up2DimensionalGroup( g3d );
1061    tup := TailMap( up );
1062    hup := HeadMap( up );
1063    lt := Left2DimensionalGroup( g3d );
1064    tlt := TailMap( lt );
1065    hlt := HeadMap( lt );
1066    rt := Right2DimensionalGroup( g3d );
1067    trt := TailMap( rt );
1068    hrt := HeadMap( rt );
1069    dn := Down2DimensionalGroup( g3d );
1070    tdn := TailMap( dn );
1071    hdn := HeadMap( dn );
1072    Print( "cat2-group with groups: ",
1073           [ Source(up), Range(up), Range(lt), Range(dn) ], "\n" );
1074    if ( tup = hup ) then
1075        Print( "   up tail=head: ",
1076           MappingGeneratorsImages( tup ), "\n" );
1077    else
1078        Print( "   up tail/head: ",
1079           MappingGeneratorsImages( tup ),
1080           MappingGeneratorsImages( hup ), "\n" );
1081    fi;
1082    if ( tlt = hlt ) then
1083        Print( " left tail=head: ",
1084           MappingGeneratorsImages( tlt ), "\n" );
1085    else
1086        Print( " left tail/head: ",
1087           MappingGeneratorsImages( tlt ),
1088           MappingGeneratorsImages( hlt ), "\n" );
1089    fi;
1090    if ( trt = hrt ) then
1091        Print( " left tail=head: ",
1092           MappingGeneratorsImages( trt ), "\n" );
1093    else
1094        Print( "right tail/head: ",
1095           MappingGeneratorsImages( trt ),
1096           MappingGeneratorsImages( hrt ), "\n" );
1097    fi;
1098    if ( tdn = hdn ) then
1099        Print( " left tail=head: ",
1100           MappingGeneratorsImages( tdn ), "\n" );
1101    else
1102        Print( " down tail/head: ",
1103           MappingGeneratorsImages( tdn ),
1104           MappingGeneratorsImages( hdn ), "\n" );
1105    fi;
1106end );
1107
1108InstallMethod( Display, "method for a pre-crossed square", true,
1109    [ IsPreCrossedSquare ], 0,
1110function( g3d )
1111
1112    local L, M, N, P, lenL, lenM, lenN, lenP, len1, len2, j, q1, q2,
1113          ispsq, arrow, ok, n, i;
1114
1115    arrow := " -> ";
1116    L := Source( Up2DimensionalGroup( g3d ) );
1117    M := Range( Up2DimensionalGroup( g3d ) );
1118    N := Source( Down2DimensionalGroup( g3d ) );
1119    P := Range( Down2DimensionalGroup( g3d ) );
1120    ok := HasName(L) and HasName(M) and HasName(N) and HasName(P);
1121    if ok then
1122        lenL := Length( Name( L ) );
1123        lenM := Length( Name( M ) );
1124        lenN := Length( Name( N ) );
1125        lenP := Length( Name( P ) );
1126        len1 := Maximum( lenL, lenN );
1127        len2 := Maximum( lenM, lenP );
1128        q1 := QuoInt( len1, 2 );
1129        q2 := QuoInt( len2, 2 );
1130        Print( "[ " );
1131        for j in [1..lenN-lenL] do Print(" "); od;
1132        Print( Name(L), arrow, Name(M) );
1133        for j in [1..lenP-lenM] do Print(" "); od;
1134        Print( " ]\n[ " );
1135        for j in [1..q1] do Print(" "); od;
1136        Print( "|" );
1137        for j in [1..q1+RemInt(len1,2)+2+q2+RemInt(len2,2)] do
1138            Print(" ");
1139        od;
1140        Print( "|" );
1141        for j in [1..q2] do Print(" "); od;
1142        Print( " ]\n" );
1143        Print( "[ " );
1144        for j in [1..lenL-lenN] do Print(" "); od;
1145        Print( Name(N), " -> ", Name(P) );
1146        for j in [1..lenM-lenP] do Print(" "); od;
1147        Print( " ]\n" );
1148    else
1149        Print( "(pre-)crossed square with (pre-)crossed modules:\n" );
1150        Print( "      up = ",    Up2DimensionalGroup( g3d ), "\n" );
1151        Print( "    left = ",  Left2DimensionalGroup( g3d ), "\n" );
1152        Print( "   right = ", Right2DimensionalGroup( g3d ), "\n" );
1153        Print( "    down = ",  Down2DimensionalGroup( g3d ), "\n" );
1154    fi;
1155end );
1156
1157#############################################################################
1158##
1159#M  IsPreCat2Group . . . . . . . . . . .  check that this is a pre-cat2-group
1160#M  IsCat2Group . . . . . . . . . . . . check that the object is a cat2-group
1161##
1162InstallMethod( IsPreCat2Group, "generic method for a pre-cat2-group",
1163    true, [ IsHigherDimensionalGroup ], 0,
1164function( P )
1165    if not ( IsPreCatnObj( P )  ) then
1166        return false;
1167    fi;
1168    if ( IsPreCatnGroup( P ) and ( HigherDimension( P ) = 3 )  ) then
1169        return true;
1170    else
1171        return false;
1172    fi;
1173end );
1174
1175InstallMethod( IsCat2Group, "generic method for a cat2-group",
1176    true, [ IsHigherDimensionalGroup ], 0,
1177function( P )
1178    local ok;
1179    ok := ( HigherDimension( P ) = 3 )
1180        and IsCat1Group( Up2DimensionalGroup( P ) )
1181        and IsCat1Group( Left2DimensionalGroup( P ) )
1182        and IsCat1Group( Right2DimensionalGroup( P ) )
1183        and IsCat1Group( Down2DimensionalGroup( P ) )
1184        and IsPreCat1Group( Diagonal2DimensionalGroup( P ) );
1185    return ok;
1186end );
1187
1188##############################################################################
1189##
1190#M  PreCat2GroupObj( [<up>,<left>,<right>,<down>,<diag>] )
1191##
1192InstallMethod( PreCat2GroupObj, "for a list of pre-cat1-groups", true,
1193    [ IsList ], 0,
1194function( L )
1195
1196    local PC, ok;
1197
1198    if not ( Length( L ) = 5 ) then
1199        Error( "there should be 5 pre-cat1-groups in the list L" );
1200    fi;
1201    PC := rec();
1202    ObjectifyWithAttributes( PC, PreCat2GroupObjType,
1203      Up2DimensionalGroup, L[1],
1204      Left2DimensionalGroup, L[2],
1205      Right2DimensionalGroup, L[3],
1206      Down2DimensionalGroup, L[4],
1207      Diagonal2DimensionalGroup, L[5],
1208      GeneratingCat1Groups, [ L[1], L[2] ],
1209      HigherDimension, 3,
1210      IsHigherDimensionalGroup, true,
1211      IsPreCat2Group, true,
1212      IsPreCatnGroup, true );
1213    ok := IsCat2Group( PC );
1214    return PC;
1215end );
1216
1217#############################################################################
1218##
1219#F  (Pre)Cat2Group( [ up, lt (,diag) )   cat2-group from 2/3 (pre)cat1-groups
1220#F  (Pre)Cat2Group( XS )                 cat2-group from (pre)crossed square
1221##
1222InstallGlobalFunction( PreCat2Group, function( arg )
1223
1224    local nargs, up, left, diag, C2G, G1, G2, G3, isoG, genG,
1225          imt, t12, imh, h12, e12, idQ, isoleft, drd, ok;
1226
1227    nargs := Length( arg );
1228    if not ( nargs in [1,2] ) then
1229        Print( "standard usage: (Pre)Cat2Group( up, left );\n" );
1230        Print( "            or: (Pre)Cat2Group( XS );\n" );
1231        return fail;
1232    fi;
1233    if ( nargs = 1 ) then
1234        C2G := PreCat2GroupOfPreCrossedSquare( arg[1] );
1235    else
1236        up := arg[1];
1237        left := arg[2];
1238        G1 := Source( up );
1239        G2 := Source( left );
1240        ## if the two sources are unequal but isomorphic then make
1241        ## an isomorphic copy of left with the same source as up
1242        if not ( G1 = G2 ) then
1243            isoG := IsomorphismGroups( G2, G1 );
1244            if ( isoG = fail ) then
1245                Error( "the two arguments do now have the same source" );
1246            else
1247                idQ := IdentityMapping( Range( left ) );
1248                isoleft := IsomorphismByIsomorphisms( left, [ isoG, idQ ] );
1249                left := Range( isoleft );
1250            fi;
1251        fi;
1252        drd := DetermineRemainingCat1Groups( up, left );
1253        if ( drd = fail ) then
1254            Info( InfoXMod, 2, "failure determining remaining cat1-groups" );
1255            return fail;
1256        fi;
1257        C2G := PreCat2GroupByPreCat1Groups( up, left, drd[1], drd[2], drd[3] );
1258        if ( C2G = fail ) then
1259            return fail;   ## Error( "C2G fails to be a PreCat2Group" );
1260        fi;
1261    fi;
1262    ok := IsPreCat2Group( C2G );
1263    if ok then
1264        ok := IsCat2Group( C2G );
1265        return C2G;
1266    else
1267        return fail;
1268    fi;
1269end );
1270
1271InstallGlobalFunction( Cat2Group, function( arg )
1272
1273    local C2G, ok;
1274
1275    C2G := PreCat2Group( arg[1], arg[2] );
1276    ok := not ( C2G = fail ) and IsCat2Group( C2G );
1277    if ok then
1278        return C2G;
1279    else
1280        return fail;
1281    fi;
1282end );
1283
1284##############################################################################
1285##
1286#M  DetermineRemainingCat1Groups . . . . . . . . . . . . for 2 pre-cat1-groups
1287##
1288InstallMethod( DetermineRemainingCat1Groups, "for up, left pre-cat1-groups",
1289    true, [ IsPreCat1Group, IsPreCat1Group ], 0,
1290function( up, left )
1291
1292    local G, genG, Q, genQ, R, genR, tu, hu, eu, tl, hl, el, tea, hea,
1293          P, genP, diag, imtd, td, imhd, hd, imed, ed, down,
1294          imtr, tr, imhr, hr, imer, er, right;
1295
1296    G := Source( up );
1297    if not ( G = Source( left ) ) then
1298        Print( "the two pre-cat1-groups should have the same source\n" );
1299    fi;
1300    genG := GeneratorsOfGroup( G );
1301    R := Range( up );
1302    genR := GeneratorsOfGroup( R );
1303    Q := Range( left );
1304    genQ := GeneratorsOfGroup( Q );
1305    tu := TailMap( up );
1306    hu := HeadMap( up );
1307    eu := RangeEmbedding( up );
1308    tl := TailMap( left );
1309    hl := HeadMap( left );
1310    el := RangeEmbedding( left );
1311    ## check that the 1-maps commute with the 2-maps
1312    tea := tu*eu*tl*el;
1313    hea := hu*eu*hl*el;
1314    if not ( ( tea = tl*el*tu*eu )
1315         and ( hea = hl*el*hu*eu )
1316         and ( tu*eu*hl*el = hl*el*tu*eu )
1317         and ( hu*eu*tl*el = tl*el*hu*eu ) )  then
1318        Info( InfoXMod, 2, "1-maps do not commute with 2-maps" );
1319        return fail;
1320    fi;
1321    Info( InfoXMod, 2, "yes : 1-maps do commute with the 2-maps" );
1322    ## more checks?
1323    ## determine the group P
1324    P := Image( tea );
1325    if not ( Image( hea ) = P ) then
1326        Error( "t*e*a and h*e*a do not have the same range" );
1327    fi;
1328    genP := GeneratorsOfGroup( P );
1329    diag := PreCat1GroupByEndomorphisms( tea, hea );
1330    if ( diag = fail ) then
1331        Print( "diag fails to be a cat1-group\n" );
1332        return fail;
1333    fi;
1334    ## now construct down
1335    imtd := List( genQ, q -> ImageElm( el * tea, q ) );
1336    td := GroupHomomorphismByImages( Q, P, genQ, imtd );
1337    imhd := List( genQ, q -> ImageElm( el * hea, q ) );
1338    hd := GroupHomomorphismByImages( Q, P, genQ, imhd );
1339    imed := List( genP, p -> ImageElm( tl, p ) );
1340    ed := GroupHomomorphismByImages( P, Q, genP, imed );
1341    down := PreCat1GroupByTailHeadEmbedding( td, hd, ed );
1342    ## now construct right
1343    imtr := List( genR, r -> ImageElm( eu * tea, r ) );
1344    tr := GroupHomomorphismByImages( R, P, genR, imtr );
1345    imhr := List( genR, r -> ImageElm( eu * hea, r ) );
1346    hr := GroupHomomorphismByImages( R, P, genR, imhr );
1347    imer := List( genP, p -> ImageElm( tu, p ) );
1348    er := GroupHomomorphismByImages( P, R, genP, imer );
1349    right := PreCat1GroupByTailHeadEmbedding( tr, hr, er );
1350    if ( ( right = fail ) or ( down = fail) ) then
1351        Info( InfoXMod, 2, "right or down fail to be cat1-groups" );
1352        return fail;
1353    fi;
1354    return [ right, down, diag ];
1355end );
1356
1357##############################################################################
1358##
1359#M  PreCat2GroupByPreCat1Groups . . . . . . . . . . . for five pre-cat1-groups
1360##
1361InstallMethod( PreCat2GroupByPreCat1Groups, "for five pre-cat1-groups",
1362    true, [ IsPreCat1Group, IsPreCat1Group, IsPreCat1Group,
1363            IsPreCat1Group, IsPreCat1Group ], 0,
1364function( up, left, right, down, diag )
1365
1366    local G, R, Q, P, genG, tu, hu, tl, hl, tr, hr, td, hd, ta, ha,
1367          imtld, imtur, imhld, imhur, dtld, dtur, dhld, dhur, PC2, ok;
1368
1369    G := Source( up );
1370    genG := GeneratorsOfGroup( G );
1371    R := Range( up );
1372    Q := Range( left );
1373    P := Range( diag );
1374    if not ( ( G = Source( left ) ) and ( G = Source( diag ) )
1375             and ( R = Source( right ) ) and ( P = Range( right ) )
1376             and ( Q = Source( down ) ) and ( P = Range( down ) ) ) then
1377        Info( InfoXMod, 2, "sources and/or ranges do not agree" );
1378        return fail;
1379    fi;
1380    tu := TailMap( up );
1381    hu := HeadMap( up );
1382    tl := TailMap( left );
1383    hl := HeadMap( left );
1384    tr := TailMap( right );
1385    hr := HeadMap( right );
1386    td := TailMap( down );
1387    hd := HeadMap( down );
1388    ta := TailMap( diag );
1389    ha := HeadMap( diag );
1390
1391    imtld := List( genG, g -> ImageElm( td, ImageElm( tl, g ) ) );
1392    dtld := GroupHomomorphismByImages( G, P, genG, imtld );
1393    imtur := List( genG, g -> ImageElm( tr, ImageElm( tu, g ) ) );
1394    dtur := GroupHomomorphismByImages( G, P, genG, imtur );
1395    imhld := List( genG, g -> ImageElm( hd, ImageElm( hl, g ) ) );
1396    dhld := GroupHomomorphismByImages( G, P, genG, imhld );
1397    imhur := List( genG, g -> ImageElm( hr, ImageElm( hu, g ) ) );
1398    dhur := GroupHomomorphismByImages( G, P, genG, imhur );
1399    if not ( ( dtld = ta ) and ( dtur= ta )
1400             and ( dhld = ha ) and ( dhur = ha ) ) then
1401        Info( InfoXMod, 2, "tail and head maps are inconsistent" );
1402        return fail;
1403    fi;
1404    PC2 := PreCat2GroupObj( [ up, left, right, down, diag ] );
1405    SetIsPreCat2Group( PC2, true );
1406    SetIsPreCatnGroup( PC2, true );
1407    SetHigherDimension( PC2, 3 );
1408    ok := IsCat2Group( PC2 );
1409    ok := IsPreCatnGroupByEndomorphisms( PC2 );
1410    return PC2;
1411end );
1412
1413##############################################################################
1414##
1415#M  AllCat2GroupsWithImagesIterator . . . cat2-groups with given up,left range
1416#M  DoAllCat2GroupsWithImagesIterator
1417#M  AllCat2GroupsWithImages . . . cat2-groups with specified range for up,left
1418#M  AllCat2GroupsWithImagesNumber . . . . # cat2-groups with specified up,left
1419#M  AllCat2GroupsWithImagesUpToIsomorphism . . . iso class reps of cat2-groups
1420##
1421BindGlobal( "NextIterator_AllCat2GroupsWithImages", function ( iter )
1422
1423    local ok, pair, C;
1424
1425    ok := false;
1426    while ( not ok ) and ( not IsDoneIterator( iter ) ) do
1427        pair := NextIterator( iter!.pairsIterator );
1428        Info( InfoXMod, 1, pair );
1429        if ( fail in pair ) then
1430            return fail;
1431        fi;
1432        C := Cat2Group( pair[1], pair[2] );
1433        if ( not ( C = fail ) and IsCat2Group( C ) ) then
1434            return C;
1435        fi;
1436    od;
1437    return fail;
1438end );
1439
1440BindGlobal( "IsDoneIterator_AllCat2GroupsWithImages",
1441    iter -> IsDoneIterator( iter!.pairsIterator )
1442);
1443
1444BindGlobal( "ShallowCopy_AllCat2GroupsWithImages",
1445    iter -> rec(      group := iter!.group,
1446              pairsIterator := ShallowCopy( iter!.pairsIterator )
1447    )
1448);
1449
1450InstallGlobalFunction( "DoAllCat2GroupsWithImagesIterator",
1451function( G, R, Q )
1452
1453    local upIterator, pairsIterator, ltIterator, iter;
1454
1455    upIterator := AllCat1GroupsWithImageIterator( G, R );
1456    if ( R = Q ) then
1457        pairsIterator := UnorderedPairsIterator( upIterator );
1458    else
1459           ltIterator := AllCat1GroupsWithImageIterator( G, Q );
1460        pairsIterator := CartesianIterator( upIterator, ltIterator );
1461    fi;
1462    iter := IteratorByFunctions(
1463        rec(      group := G,
1464          pairsIterator := ShallowCopy( pairsIterator ),
1465           NextIterator := NextIterator_AllCat2GroupsWithImages,
1466         IsDoneIterator := IsDoneIterator_AllCat2GroupsWithImages,
1467            ShallowCopy := ShallowCopy_AllCat2GroupsWithImages ) );
1468    return iter;
1469end );
1470
1471InstallMethod( AllCat2GroupsWithImagesIterator,
1472    "for a group and two subgroups", [ IsGroup, IsGroup, IsGroup ], 0,
1473function ( G, R, Q )
1474    if not ( IsSubgroup( G, R ) and IsSubgroup( G, Q ) ) then
1475        Error( "R,Q are not subgroups of G" );
1476    fi;
1477    return DoAllCat2GroupsWithImagesIterator( G, R, Q );
1478end );
1479
1480InstallMethod( AllCat2GroupsWithImages,
1481    "for a group and two subgroups", [ IsGroup, IsGroup, IsGroup ], 0,
1482function ( G, R, Q )
1483
1484    local L0, C;
1485
1486    if not ( IsSubgroup( G, R ) and IsSubgroup( G, Q ) ) then
1487        Error( "R,Q are not subgroups of G" );
1488    fi;
1489    L0 := [ ];
1490    for C in AllCat2GroupsWithImagesIterator( G, R, Q ) do
1491        if not ( C = fail ) then
1492            Add( L0, C );
1493        fi;
1494    od;
1495    return L0;
1496end );
1497
1498InstallMethod( AllCat2GroupsWithImagesNumber,
1499    "for a group and two subgroups", [ IsGroup, IsGroup, IsGroup ], 0,
1500function ( G, R, Q )
1501
1502    local num, C;
1503
1504    if not ( IsSubgroup( G, R ) and IsSubgroup( G, Q ) ) then
1505        Error( "R,Q are not subgroups of G" );
1506    fi;
1507    num := 0;
1508    for C in AllCat2GroupsWithImagesIterator( G, R, Q ) do
1509        if not ( C = fail ) then
1510            num := num+1;
1511        fi;
1512    od;
1513    return num;
1514end );
1515
1516InstallMethod( AllCat2GroupsWithImagesUpToIsomorphism,
1517    "for a group and two subgroups", [ IsGroup, IsGroup, IsGroup ], 0,
1518function ( G, R, Q )
1519
1520    local L0, len0, num, GRiter, upiter, up, GQiter, leftiter, left,
1521          C, j, found, iso;
1522
1523    if not ( IsSubgroup( G, R ) and IsSubgroup( G, Q ) ) then
1524        Error( "R,Q are not subgroups of G" );
1525    fi;
1526    L0 := [ ];
1527    len0 := 0;
1528    num := 0;
1529    GRiter := AllCat1GroupsWithImageIterator( G, R );
1530    GQiter := AllCat1GroupsWithImageIterator( G, Q );
1531    upiter := ShallowCopy( GRiter );
1532    for up in upiter do
1533        leftiter := ShallowCopy( GQiter );
1534        for left in leftiter do
1535            C := Cat2Group( up, left );
1536            if ( not ( C = fail ) and IsCat2Group( C ) ) then
1537                num := num+1;
1538                j := 0;
1539                found := false;
1540                while ( not found ) and ( j < len0 ) do
1541                    j := j+1;
1542                    iso := IsomorphismPreCat2Groups( C, L0[j] );
1543                    if not ( iso = fail ) then
1544                        found := true;
1545                    fi;
1546                od;
1547                if not found then
1548                    Add( L0, C );
1549                    len0 := len0+1;
1550                    if ( InfoLevel( InfoXMod ) > 0 ) then
1551                        Display( C );
1552                        Print( "-------------------------------------\n" );
1553                    fi;
1554                fi;
1555            fi;
1556        od;
1557    od;
1558    Info( InfoXMod, 1, "cat2-groups: ", num, " found, ", len0, " classes" );
1559    return L0;
1560end );
1561
1562##############################################################################
1563##
1564#M  AllCat2Groups . . . . . . . list of cat2-group structures on a given group
1565#O  AllCat2GroupsIterator( <gp> ) . . . . . . . iterator for the previous list
1566#F  NextIterator_AllCat2Groups( <iter> )
1567#F  IsDoneIterator_AllCat2Groups( <iter> )
1568#F  ShallowCopy_AllCat2Groups( <iter> )
1569#A  AllCat2GroupsNumber( <gp> ) . . . . . . . . .  number of these cat2-groups
1570#M  AllCat2GroupsUpToIsomorphism . . . iso class reps of cat2-group structures
1571##
1572BindGlobal( "NextIterator_AllCat2Groups", function ( iter )
1573    local pair, next;
1574    if IsDoneIterator( iter!.imagesIterator ) then
1575        pair := NextIterator( iter!.pairsIterator );
1576        iter!.imagesIterator :=
1577            AllCat2GroupsWithImagesIterator( iter!.group, pair[1], pair[2] );
1578    fi;
1579    next := NextIterator( iter!.imagesIterator );
1580    if ( next <> fail ) then
1581        iter!.count := iter!.count + 1;
1582    fi;
1583    return next;
1584end );
1585
1586BindGlobal( "IsDoneIterator_AllCat2Groups",
1587    iter -> ( IsDoneIterator( iter!.pairsIterator )
1588              and IsDoneIterator( iter!.imagesIterator ) )
1589);
1590
1591BindGlobal( "ShallowCopy_AllCat2Groups",
1592    iter -> rec( group := iter!.group,
1593                 count := iter!.count,
1594         pairsIterator := ShallowCopy( iter!.pairsIterator ),
1595        imagesIterator := ShallowCopy( iter!.imagesIterator )
1596    )
1597);
1598
1599BindGlobal( "DoAllCat2GroupsIterator",
1600function( G )
1601
1602    local subsIterator, pairsIterator, imagesIterator, iter;
1603
1604    subsIterator := AllSubgroupsIterator( G );
1605    pairsIterator := UnorderedPairsIterator( subsIterator );
1606    imagesIterator := IteratorList( [ ] );
1607    iter := IteratorByFunctions(
1608        rec(     group := G,
1609                 count := 0,
1610          subsIterator := ShallowCopy( subsIterator ),
1611         pairsIterator := ShallowCopy( pairsIterator ),
1612        imagesIterator := ShallowCopy( imagesIterator ),
1613          NextIterator := NextIterator_AllCat2Groups,
1614        IsDoneIterator := IsDoneIterator_AllCat2Groups,
1615           ShallowCopy := ShallowCopy_AllCat2Groups ) );
1616    return iter;
1617end );
1618
1619InstallMethod( AllCat2GroupsIterator, "for a group", [ IsGroup ], 0,
1620    G -> DoAllCat2GroupsIterator( G ) );
1621
1622InstallMethod( AllCat2Groups, "for a group", [ IsGroup ], 0,
1623function( G )
1624
1625    local L, omit, pairs, all1, C, genC;
1626
1627    InitCatnGroupRecords( G );
1628    L := [ ];
1629    omit := CatnGroupLists( G ).omit;
1630    if not omit then
1631        all1 := AllCat1Groups( G );
1632        pairs := [ ];
1633    fi;
1634    for C in AllCat2GroupsIterator( G ) do
1635        if not ( C = fail ) then
1636            Add( L, C );
1637            if not omit then
1638                genC := GeneratingCat1Groups( C );
1639                Add( pairs,
1640                    [ Position( all1, genC[1] ), Position( all1, genC[2] ) ] );
1641            fi;
1642        fi;
1643    od;
1644    if not IsBound( CatnGroupNumbers( G ).cat2 ) then
1645        CatnGroupNumbers( G ).cat2 := Length( L );
1646    fi;
1647    if not omit then
1648        Sort( pairs );
1649        CatnGroupLists( G ).cat2pairs := pairs;
1650    fi;
1651    return L;
1652end );
1653
1654InstallMethod( AllCat2GroupsNumber, "for a group", [ IsGroup ], 0,
1655function( G )
1656
1657    local n, C, all;
1658
1659    InitCatnGroupRecords( G );
1660    if IsBound( CatnGroupNumbers( G ).cat2 ) then
1661        return CatnGroupNumbers( G ).cat2;
1662    fi;
1663    ## not already known, so perform the calculation
1664    all := AllCat2Groups( G );
1665    return CatnGroupNumbers( G ).cat2;
1666end );
1667
1668InstallMethod( AllCat2GroupsUpToIsomorphism, "iso class reps of cat2-groups",
1669    true, [ IsGroup ], 0,
1670function( G )
1671
1672    local all1, iso1, omit, classes, L, numL, posL, symmnum, symmpos,
1673          prediag, prediagpos, i, C, k, found, iso, genC, perm;
1674
1675    InitCatnGroupRecords( G );
1676    if not IsBound( CatnGroupNumbers( G ).iso1 ) then
1677        iso1 := AllCat1GroupsUpToIsomorphism( G );
1678    fi;
1679    all1 := AllCat1Groups( G );
1680    omit := CatnGroupLists( G ).omit;
1681    if not omit then
1682        classes := [ ];
1683    fi;
1684    L := [ ];
1685    numL := 0;
1686    posL := [ ];
1687    symmnum := 0;
1688    symmpos := [ ];
1689    prediag := 0;
1690    prediagpos := [ ];
1691    i := 0;
1692    for C in AllCat2GroupsIterator( G ) do
1693        if not ( C = fail ) then
1694            genC := GeneratingCat1Groups( C );
1695            i := i+1;
1696            k := 0;
1697            found := false;
1698            while ( not found ) and ( k < numL ) do
1699                k := k+1;
1700                iso := IsomorphismCat2Groups( C, L[k] );
1701                if ( iso <> fail ) then
1702                     found := true;
1703                     if not omit then
1704                         Add( classes[k], [ Position( all1, genC[1] ),
1705                                            Position( all1, genC[2] ) ] );
1706                     fi;
1707                fi;
1708            od;
1709            if not found then
1710                Add( L, C );
1711                Add( posL, i );
1712                numL := numL + 1;
1713                if ( genC[1] = genC[2] ) then
1714                    symmnum := symmnum + 1;
1715                    Add( symmpos, numL );
1716                fi;
1717                if not IsCat1Group( Diagonal2DimensionalGroup( C ) ) then
1718                    prediag := prediag + 1;
1719                    Add( prediagpos, numL );
1720                fi;
1721                if not omit then
1722                    Add( classes,
1723                      [ [ Position(all1,genC[1]), Position(all1,genC[2]) ] ] );
1724                fi;
1725            fi;
1726        fi;
1727    od;
1728    if not IsBound( CatnGroupNumbers( G ).cat2 ) then
1729        CatnGroupNumbers( G ).cat2 := i;
1730    fi;
1731    if not IsBound( CatnGroupLists( G ).allcat2pos ) then
1732        CatnGroupLists( G ).allcat2pos := posL;
1733    fi;
1734    if not IsBound( CatnGroupNumbers( G ).iso2 ) then
1735        CatnGroupNumbers( G ).iso2 := numL;
1736        CatnGroupNumbers( G ).symm2 := symmnum;
1737        if ( prediag > 0 ) then
1738            CatnGroupNumbers( G ).prediag2 := prediag;
1739        fi;
1740    fi;
1741    Info( InfoXMod, 1, "reps found at positions ", posL );
1742    if not omit then
1743        perm := Sortex( classes );
1744        L := Permuted( L, perm );
1745        CatnGroupLists( G ).cat2classes := classes;
1746        symmpos := List( symmpos, i -> i^perm );
1747        prediagpos := List( prediagpos, i -> i^perm );
1748        CatnGroupLists( G ).symmpos := symmpos;
1749        if ( prediag > 0 ) then
1750            CatnGroupLists( G ).prediagpos := prediagpos;
1751        fi;
1752    fi;
1753    return L;
1754end );
1755
1756InstallMethod( AllCat2GroupFamilies, "gives lists of isomorphic cat2-groups",
1757    true, [ IsGroup ], 0,
1758function( G )
1759
1760    local reps, cat2, iso2, classes, i, C, k, found, iso;
1761
1762    reps := AllCat2GroupsUpToIsomorphism( G );
1763    cat2 := CatnGroupNumbers( G ).cat2;
1764    iso2 := CatnGroupNumbers( G ).iso2;
1765    classes := ListWithIdenticalEntries( iso2, 0 );
1766    for k in [1..iso2] do
1767        classes[k] := [ ];
1768    od;
1769    i := 0;
1770    for C in AllCat2GroupsIterator( G ) do
1771        if not ( C = fail ) then
1772            i := i+1;
1773            k := 0;
1774            found := false;
1775            while ( not found ) do
1776                k := k+1;
1777                iso := IsomorphismCat2Groups( C, reps[k] );
1778                if ( iso <> fail ) then
1779                    found := true;
1780                    Add( classes[k], i );
1781                fi;
1782            od;
1783        fi;
1784    od;
1785    return classes;
1786end );
1787
1788##############################################################################
1789##
1790#M  TableRowForCat1Groups   . . . . . . . . cat1-structure data for a group G
1791#M  TableRowForCat2Groups   . . . . . . . . cat2-structure data for a group G
1792##
1793InstallMethod( TableRowForCat1Groups, "for a group G", true, [ IsGroup ], 0,
1794function( G )
1795
1796    local Eler, Iler, i, j, allprecat1, allcat1, B;
1797
1798    allprecat1 := [];
1799    Eler := AllHomomorphisms( G, G );
1800    Iler := Filtered( Eler, h -> CompositionMapping( h, h ) = h );
1801    for i in [1..Length(Iler)] do
1802        for j in [1..Length(Iler)] do
1803            if PreCat1GroupByEndomorphisms(Iler[i],Iler[j]) <> fail then
1804                Add(allprecat1,PreCat1GroupByEndomorphisms(Iler[i],Iler[j]));
1805            else
1806                continue;
1807            fi;
1808        od;
1809    od;
1810    allcat1 := Filtered( allprecat1,IsCat1Group );
1811    B := AllCat1GroupsUpToIsomorphism( G );
1812    Print( "-----------------------------------------------------------",
1813           "-------------------------------- \n" );
1814    Print( "-----------------------------------------------------------",
1815           "-------------------------------- \n" );
1816    Print( "GAP id", "\t\t", "Group Name", "\t", "|End(G)|", "\t",
1817           "|IE(G)|", "\t\t", "C(G)", "\t\t", "|C/~| \n" );
1818    Print( "-----------------------------------------------------------",
1819           "-------------------------------- \n" );
1820    Print( "-----------------------------------------------------------",
1821           "-------------------------------- \n" );
1822    Print( IdGroup(G), "\t", StructureDescription(G), "\t\t",
1823           Length(Eler), "\t\t", Length(Iler), "\t\t", Length(allcat1),
1824           "\t\t", Length(B), "\n" );
1825    Print( "-----------------------------------------------------------",
1826           "-------------------------------- \n" );
1827    Print( "-----------------------------------------------------------",
1828           "-------------------------------- \n" );
1829    return B;
1830end );
1831
1832InstallMethod( TableRowForCat2Groups, "for a group G", true, [ IsGroup ], 0,
1833function( G )
1834
1835    local Eler, Iler, i, j, allcat1, Cat2_ler, B, a, n, C1, c1, c2,
1836          PreCat2_ler, Cat2_ler2;
1837
1838    i := IdGroup(G)[1];
1839    j := IdGroup(G)[2];
1840    n := Cat1Select(i,j,0);;
1841    Cat2_ler := AllCat2Groups(G);
1842    B := AllCat2GroupsUpToIsomorphism(G);;
1843    Print( "-----------------------------------------------------------",
1844           "-------------------------------- \n" );
1845    Print( "-----------------------------------------------------------",
1846           "-------------------------------- \n" );
1847    Print( "GAP id", "\t\t", "Group Name", "\t\t", "C2(G)", "\t\t",
1848           "|C2/~| \n");
1849    Print( "-----------------------------------------------------------",
1850           "-------------------------------- \n" );
1851    Print( "-----------------------------------------------------------",
1852           "-------------------------------- \n" );
1853    Print( IdGroup(G), "\t", StructureDescription(G), "\t\t\t",
1854           Length(Cat2_ler), "\t\t", Length(B), "\n" );
1855    Print( "-----------------------------------------------------------",
1856           "-------------------------------- \n" );
1857    Print( "-----------------------------------------------------------",
1858           "-------------------------------- \n" );
1859    return B;
1860end );
1861
1862##############################################################################
1863##
1864#M  ConjugationActionForCrossedSquare
1865##  . . . . conjugation action for crossed square from cat2-group
1866##
1867InstallMethod( ConjugationActionForCrossedSquare,
1868    "conjugation action for crossed square with G acting on N",
1869    true, [ IsGroup, IsGroup ], 0,
1870function( G, N )
1871
1872    local genG, genN, autgen, g, imautgen, a, idN, aut, act;
1873
1874    genG := GeneratorsOfGroup( G );
1875    genN := GeneratorsOfGroup( N );
1876    autgen := [ ];
1877    for g in genG do
1878        imautgen := List( genN, n -> n^g );
1879        a := GroupHomomorphismByImages( N, N, genN, imautgen );
1880        Add( autgen, a );
1881    od;
1882    if ( Length( genG ) = 0 ) then
1883        idN := IdentityMapping( N );
1884        aut := Group( idN );
1885    else
1886        aut := Group( autgen );
1887    fi;
1888    SetIsGroupOfAutomorphisms( aut, true );
1889    act := GroupHomomorphismByImages( G, aut, genG, autgen );
1890    return act;
1891end );
1892
1893#############################################################################
1894##
1895#M  PreCrossedSquareOfPreCat2Group
1896#M  PreCat2GroupOfPreCrossedSquare
1897#M  CrossedSquareOfCat2Group
1898#M  Cat2GroupOfCrossedSquare
1899##
1900InstallMethod( PreCrossedSquareOfPreCat2Group, true,
1901    [ IsPreCat2Group ], 0,
1902function( C2G )
1903
1904    local n, l, i, j, k, up, down, left, right, isolar, liste1, liste2,
1905          G, gensrc, x, C1, C2, h1, t1, h2, t2, L, M, N, P, XS,
1906          diag, genL, imdelta, delta, liste, partial, action, aut, actML,
1907          XM, kappa, CM1, CM2, lambda, actNL, CM3, mu, actPM, CM4, nu, actPN,
1908          xp, actPL;
1909
1910    C1 := GeneratingCat1Groups( C2G )[1];
1911    C2 := GeneratingCat1Groups( C2G )[2];
1912    if not ( IsPerm2DimensionalGroup( C1 ) ) then
1913        C1 := Image(IsomorphismPermObject( C1 ) );
1914    fi;
1915    if not ( IsPerm2DimensionalGroup( C2 ) ) then
1916        C2 := Image(IsomorphismPermObject( C2 ) );
1917    fi;
1918    h1 := HeadMap( C1 );
1919    t1 := TailMap( C1 );
1920    h2 := HeadMap( C2 );
1921    t2 := TailMap( C2 );
1922    G := Image( IsomorphismPermObject( Source( t1 ) ) );
1923    gensrc := GeneratorsOfGroup( G );
1924    t1 := GroupHomomorphismByImagesNC( G, G, gensrc,
1925              List(gensrc, x -> ImageElm( t1, x ) ) );
1926    h1 := GroupHomomorphismByImagesNC( G, G, gensrc,
1927              List(gensrc, x -> ImageElm( h1, x ) ) );
1928    t2 := GroupHomomorphismByImagesNC( G, G, gensrc,
1929              List(gensrc, x -> ImageElm( t2, x ) ) );
1930    h2 := GroupHomomorphismByImagesNC( G, G, gensrc,
1931              List(gensrc, x -> ImageElm( h2, x ) ) );
1932    L := Intersection( Kernel( t1 ), Kernel( t2 ) ) ;
1933    M := Intersection( Image( t1 ), Kernel( t2 ) );
1934    N := Intersection( Kernel ( t1 ), Image( t2 ) );
1935    P := Intersection( Image( t1 ), Image( t2 ) )  ;
1936    Info( InfoXMod, 4, "G = ", G );
1937    Info( InfoXMod, 4, "L = ", L );
1938    Info( InfoXMod, 4, "M = ", M );
1939    Info( InfoXMod, 4, "N = ", N );
1940    Info( InfoXMod, 4, "P = ", P );
1941    kappa := GroupHomomorphismByFunction( L, M, x -> ImageElm(h1,x) );
1942    actML := ConjugationActionForCrossedSquare( M, L );
1943    up := XModByBoundaryAndAction( kappa, actML );
1944    lambda := GroupHomomorphismByFunction( L, N, x -> ImageElm(h2,x) );
1945    actNL := ConjugationActionForCrossedSquare( N, L );
1946    left := XModByBoundaryAndAction( lambda, actNL );
1947    mu := GroupHomomorphismByFunction( M, P, x -> ImageElm(h2,x) );
1948    actPM := ConjugationActionForCrossedSquare( P, M );
1949    right := XModByBoundaryAndAction( mu, actPM );
1950    nu := GroupHomomorphismByFunction( N, P, x -> ImageElm(h1,x) );
1951    actPN := ConjugationActionForCrossedSquare( P, N );
1952    down := XModByBoundaryAndAction( nu, actPN );
1953    Info( InfoXMod, 3, "   up = ", up );
1954    Info( InfoXMod, 3, " left = ", left );
1955    Info( InfoXMod, 3, "right = ", right );
1956    Info( InfoXMod, 3, " down = ", down );
1957    actPL := ConjugationActionForCrossedSquare( P, L );
1958    genL := GeneratorsOfGroup( L );
1959    imdelta := List( genL, l -> ImageElm( nu, ImageElm( lambda, l ) ) );
1960    delta := GroupHomomorphismByImages( L, P, genL, imdelta );
1961    diag := XModByBoundaryAndAction( delta, actPL );
1962    xp := CrossedPairingByCommutators( N, M, L );
1963    XS := PreCrossedSquareObj( up, left, right, down, diag, xp );
1964##     SetIsCrossedSquare( XS, true );
1965    if ( HasIsCat2Group( C2G ) and IsCat2Group( C2G ) ) then
1966        if not IsCrossedSquare( XS ) then
1967            Error( "XS fails to be the crossed square of a cat2-group" );
1968        fi;
1969    fi;
1970    if HasName( C2G ) then
1971        SetName( XS, Concatenation( "xsq(", Name( C2G ), ")" ) );
1972    fi;
1973    return XS;
1974end );
1975
1976InstallMethod( PreCat2GroupOfPreCrossedSquare, true,
1977    [ IsPreCrossedSquare ], 0,
1978function( XS )
1979
1980    local up, left, right, down, diag, L, M, N, P, genL, genM, genN, genP,
1981          kappa, lambda, nu, mu,
1982          act_up, act_lt, act_dn, act_rt, act_dg, xpair,
1983          Cup, NxL, genNxL, e1NxL, e2NxL, Cleft, MxL, genMxL, e1MxL, e2MxL,
1984          Cdown, PxM, genPxM, e1PxM, e2PxM, Cright, PxN, genPxN, e1PxN, e2PxN,
1985          MxLbyP, MxLbyN, autgenMxL, autMxL, actPNML, NxLbyP, NxLbyM,
1986          autgenNxL, autNxL, actPMNL, imPNML, bdyPNML, XPNML, CPNML, PNML,
1987          e1PNML, e2PNML, genPNML, imPMNL, bdyPMNL, XPMNL, CPMNL, PMNL,
1988          e1PMNL, e2PMNL, genPMNL, imiso, iso, inv, iminv, tup, hup, eup,
1989          C2PNML, tlt, hlt, elt, tdn, hdn, edn, trt, hrt, ert, tdi, hdi, edi,
1990          PC, Cdiag, imnukappa, nukappa, morCleftCright, immulambda, mulambda,
1991          morCupCdown;
1992
1993    Info( InfoXMod, 1, "these conversion functions are under development\n" );
1994
1995    up := Up2DimensionalGroup( XS );
1996    left := Left2DimensionalGroup( XS );
1997    right := Right2DimensionalGroup( XS );
1998    down := Down2DimensionalGroup( XS );
1999    diag := Diagonal2DimensionalGroup( XS );
2000    L := Source( up );
2001    M := Range( up );
2002    N := Source( down );
2003    P := Range( down );
2004    genL := GeneratorsOfGroup( L );
2005    genM := GeneratorsOfGroup( M );
2006    genN := GeneratorsOfGroup( N );
2007    genP := GeneratorsOfGroup( P );
2008    Info( InfoXMod, 4, "L = ", L );
2009    Info( InfoXMod, 4, "M = ", M );
2010    Info( InfoXMod, 4, "N = ", N );
2011    Info( InfoXMod, 4, "P = ", P );
2012    kappa := Boundary( up );
2013    lambda := Boundary( left );
2014    mu := Boundary( right );
2015    nu := Boundary( down );
2016    act_up := XModAction( up );
2017    act_lt := XModAction( left );
2018    act_rt := XModAction( right );
2019    act_dn := XModAction( down );
2020    act_dg := XModAction( diag );
2021    xpair := CrossedPairing( XS );
2022
2023    Cup := Cat1GroupOfXMod( up );
2024    MxL := Source( Cup );
2025    e1MxL := Embedding( MxL, 1 );
2026    e2MxL := Embedding( MxL, 2 );
2027    genMxL := Concatenation( List( genM, m -> ImageElm( e1MxL, m ) ),
2028                             List( genL, l -> ImageElm( e2MxL, l ) ) );
2029    Cleft := Cat1GroupOfXMod( left );
2030    NxL := Source( Cleft );
2031    e1NxL := Embedding( NxL, 1 );
2032    e2NxL := Embedding( NxL, 2 );
2033    genNxL := Concatenation( List( genN, n -> ImageElm( e1NxL, n ) ),
2034                             List( genL, l -> ImageElm( e2NxL, l ) ) );
2035    Cright := Cat1GroupOfXMod( right );
2036    PxM := Source( Cright );
2037    e1PxM := Embedding( PxM, 1 );
2038    e2PxM := Embedding( PxM, 2 );
2039    genPxM := Concatenation( List( genP, p -> ImageElm( e1PxM, p ) ),
2040                             List( genM, m -> ImageElm( e2PxM, m ) ) );
2041
2042    ## construct the cat1-morphism Cleft => Cright
2043    imnukappa := Concatenation(
2044        List( genN, n -> ImageElm( e1PxM, ImageElm( nu, n ) ) ),
2045        List( genL, l -> ImageElm( e2PxM, ImageElm( kappa, l ) ) ) );
2046    nukappa := GroupHomomorphismByImages( NxL, PxM, genNxL, imnukappa );
2047    morCleftCright := Cat1GroupMorphism( Cleft, Cright, nukappa, nu );
2048    if ( InfoLevel( InfoXMod ) > 2 ) then
2049        Display( morCleftCright );
2050    fi;
2051    Cdown := Cat1GroupOfXMod( down );
2052    PxN := Source( Cdown );
2053    e1PxN := Embedding( PxN, 1 );
2054    e2PxN := Embedding( PxN, 2 );
2055    genPxN := Concatenation( List( genP, p -> ImageElm( e1PxN, p ) ),
2056                             List( genN, n -> ImageElm( e2PxN, n ) ) );
2057
2058    ## construct the cat1-morphism Cup => Cdown
2059    immulambda := Concatenation(
2060        List( genM, m -> ImageElm( e1PxN, ImageElm( mu, m ) ) ),
2061        List( genL, l -> ImageElm( e2PxN, ImageElm( lambda, l ) ) ) );
2062    mulambda := GroupHomomorphismByImages( MxL, PxN, genMxL, immulambda );
2063    morCupCdown := Cat1GroupMorphism( Cup, Cdown, mulambda, mu );
2064    if ( InfoLevel( InfoXMod ) > 2 ) then
2065        Display( morCupCdown );
2066    fi;
2067    ## construct the action of PxM on NxL using:
2068    ## (n,l)^(p,m) = ( n^p, (n^p \box m).l^{pm} )
2069    NxLbyP := List( genP, p -> GroupHomomorphismByImages( NxL, NxL, genNxL,
2070            Concatenation(
2071                List( genN, n -> ImageElm( e1NxL,
2072                                 ImageElm( ImageElm( act_dn, p ), n ) )),
2073                List( genL, l -> ImageElm( e2NxL,
2074                                 ImageElm( ImageElm( act_dg, p ), l ))) )));
2075    NxLbyM := List( genM, m -> GroupHomomorphismByImages( NxL, NxL, genNxL,
2076            Concatenation(
2077                List( genN, n -> ImageElm( e1NxL, n ) *
2078                                 ImageElm( e2NxL,
2079                                 ImageElmCrossedPairing( xpair, [n,m] ))),
2080                List( genL, l -> ImageElm( e2NxL,
2081                                 ImageElm( ImageElm( act_up, m ), l ))) )));
2082    autgenNxL := Concatenation( NxLbyP, NxLbyM );
2083    Info( InfoXMod, 2, "autgenNxL = ", autgenNxL );
2084    autNxL := Group( autgenNxL );
2085    Info( InfoXMod, 2, "autNxL has size ", Size( autNxL ) );
2086    SetIsGroupOfAutomorphisms( autNxL, true );
2087    actPMNL := GroupHomomorphismByImages( PxM, autNxL, genPxM, autgenNxL );
2088    imPMNL := Concatenation(
2089                List( genN, n -> ImageElm( e1PxM, ImageElm( nu, n ) ) ),
2090                List( genL, l -> ImageElm( e2PxM, ImageElm( kappa, l ) ) ) );
2091    Info( InfoXMod, 2, "imPMNL = ", imPMNL );
2092    bdyPMNL := GroupHomomorphismByImages( NxL, PxM, genNxL, imPMNL );
2093    XPMNL := XModByBoundaryAndAction( bdyPMNL, actPMNL );
2094    if ( InfoLevel( InfoXMod ) > 1 ) then
2095        Print( "crossed module XPMNL:\n" );
2096        Display( XPMNL );
2097    fi;
2098    CPMNL := Cat1GroupOfXMod( XPMNL );
2099    Info( InfoXMod, 2, "cat1-group CPMNL: ", StructureDescription(CPMNL) );
2100    PMNL := Source( CPMNL );
2101    e1PMNL := Embedding( PMNL, 1 );
2102    e2PMNL := Embedding( PMNL, 2 );
2103    genPMNL := Concatenation( List( genPxM, g -> ImageElm( e1PMNL, g ) ),
2104                              List( genNxL, g -> ImageElm( e2PMNL, g ) ) );
2105    ## construct the action of PxN on MxL using the transpose action:
2106    ## (m,l)^(p,n) = (m^p, (n \box m^p)^{-1}.l^{pn} )
2107    MxLbyP := List( genP, p -> GroupHomomorphismByImages( MxL, MxL, genMxL,
2108            Concatenation(
2109                List( genM, m -> ImageElm( e1MxL,
2110                                 ImageElm( ImageElm( act_rt, p ), m ) )),
2111                List( genL, l -> ImageElm( e2MxL,
2112                                 ImageElm( ImageElm( act_dg, p ), l ))) )));
2113    MxLbyN := List( genN, n -> GroupHomomorphismByImages( MxL, MxL, genMxL,
2114            Concatenation(
2115                List( genM, m -> ImageElm( e1MxL, m ) *
2116                                 ImageElm( e2MxL,
2117                                 ImageElmCrossedPairing( xpair, [n,m] )^(-1) )),
2118                List( genL, l -> ImageElm( e2MxL,
2119                                 ImageElm( ImageElm( act_lt, n ), l ))) )));
2120    autgenMxL := Concatenation( MxLbyP, MxLbyN );
2121    Info( InfoXMod, 2, "autgenMxL = ", autgenMxL );
2122    autMxL := Group( autgenMxL );
2123    SetIsGroupOfAutomorphisms( autMxL, true );
2124    actPNML := GroupHomomorphismByImages( PxN, autMxL, genPxN, autgenMxL );
2125    imPNML := Concatenation(
2126                List( genM, m -> ImageElm( e1PxN, ImageElm( mu, m ) ) ),
2127                List( genL, l -> ImageElm( e2PxN, ImageElm( lambda, l ) ) ) );
2128    bdyPNML := GroupHomomorphismByImages( MxL, PxN, genMxL, imPNML );
2129    XPNML := XModByBoundaryAndAction( bdyPNML, actPNML );
2130    if ( InfoLevel( InfoXMod ) > 2 ) then
2131        Print( "crossed module XPNML:\n" );
2132        Display( XPNML );
2133    fi;
2134    CPNML := Cat1GroupOfXMod( XPNML );
2135    Info( InfoXMod, 2, "cat1-group CPNML: ", StructureDescription(CPNML) );
2136    PNML := Source( CPNML );
2137    e1PNML := Embedding( PNML, 1 );
2138    e2PNML := Embedding( PNML, 2 );
2139    genPNML := Concatenation( List( genPxN, g -> ImageElm( e1PNML, g ) ),
2140                              List( genMxL, g -> ImageElm( e2PNML, g ) ) );
2141    ## now find the isomorphism between the sources PMNL and PNML
2142    imiso := Concatenation(
2143           List( genP, p -> ImageElm( e1PNML, ImageElm( e1PxN, p ) ) ),
2144           List( genM, m -> ImageElm( e2PNML, ImageElm( e1MxL, m ) ) ),
2145           List( genN, n -> ImageElm( e1PNML, ImageElm( e2PxN, n ) ) ),
2146           List( genL, l -> ImageElm( e2PNML, ImageElm( e2MxL, l ) ) ) );
2147    iso := GroupHomomorphismByImages( PMNL, PNML, genPMNL, imiso );
2148    inv := InverseGeneralMapping( iso );
2149    iminv := List( genPNML, g -> ImageElm( inv, g ) );
2150    Info( InfoXMod, 2, "iminv = ", iminv );
2151
2152    ##  construct an isomorphic up cat1-group
2153    tup := iso * TailMap( CPNML );
2154    hup := iso * HeadMap( CPNML );
2155    eup := e1PNML * inv;
2156    C2PNML := PreCat1GroupByTailHeadEmbedding( tup, hup, eup );
2157
2158    ##  now see if a cat2-group has been constructed
2159    tlt := TailMap( CPMNL );
2160    hlt := HeadMap( CPMNL );
2161    elt := e1PMNL;
2162    tdn := TailMap( Cright );
2163    hdn := HeadMap( Cright );
2164    edn := e1PxM;
2165    trt := TailMap( Cdown );
2166    hrt := HeadMap( Cdown );
2167    ert := e1PxN;
2168    tdi := tlt * tdn;
2169    if not ( tdi = tup * trt ) then
2170        Error( "tlt * tdn <> tup * trt" );
2171    fi;
2172    hdi := hlt * hdn;
2173    if not ( hdi = hup * hrt ) then
2174        Error( "hlt * hdn <> hup * hrt" );
2175    fi;
2176    edi := edn * elt;
2177    if not ( edi = ert * eup ) then
2178        Error( "edn * elt <> ert * eup" );
2179    fi;
2180    Cdiag := PreCat1GroupByTailHeadEmbedding( tdi, hdi, edi );
2181    PC := PreCat2GroupByPreCat1Groups( CPMNL, C2PNML, Cright, Cdown, Cdiag );
2182    return PC;
2183end );
2184
2185InstallMethod( CrossedSquareOfCat2Group, "generic method for cat2-groups",
2186    true, [ IsCat2Group ], 0,
2187function( C2 )
2188
2189    local XS;
2190    XS := PreCrossedSquareOfPreCat2Group( C2 );
2191##    SetIsCrossedSquare( XS, true );
2192    if not IsCrossedSquare( XS ) then
2193        Error( "XS fails to be the crossed square of a cat2-group" );
2194    fi;
2195    SetCrossedSquareOfCat2Group( C2, XS );
2196##    SetCat2GroupOfCrossedSquare( XS, C2 );
2197    return XS;
2198end );
2199
2200InstallMethod( Cat2GroupOfCrossedSquare, "generic method for crossed squares",
2201    true, [ IsCrossedSquare ], 0,
2202function( XS )
2203
2204    local C2;
2205    C2 := PreCat2GroupOfPreCrossedSquare( XS );
2206    SetCrossedSquareOfCat2Group( C2, XS );
2207    SetCat2GroupOfCrossedSquare( XS, C2 );
2208    return C2;
2209end );
2210
2211##############################################################################
2212##
2213#M  Transpose3DimensionalGroup . . transpose of a crossed square or cat2-group
2214##
2215InstallMethod( Transpose3DimensionalGroup, "transposed crossed square", true,
2216    [ IsCrossedSquare ], 0,
2217function( XS )
2218
2219    local xpS, NxM, L, map, xpT, XT;
2220
2221    xpS := CrossedPairing( XS );
2222    NxM := Reversed( Source( xpS ) );
2223    L := Range( xpS );
2224    map := Mapping2ArgumentsByFunction( NxM, L,
2225        function(c)
2226            return ImageElmCrossedPairing( xpS, Reversed(c) )^(-1);
2227        end );
2228    xpT := CrossedPairingObj( NxM, L, map );
2229    XT := PreCrossedSquareObj( Left2DimensionalGroup(XS),
2230              Up2DimensionalGroup(XS), Down2DimensionalGroup(XS),
2231           Right2DimensionalGroup(XS), Diagonal2DimensionalGroup(XS), xpT );
2232##    SetIsCrossedSquare( XT, true );
2233    return XT;
2234end );
2235
2236InstallMethod( Transpose3DimensionalGroup, "transposed cat2-group", true,
2237    [ IsCat2Group ], 0,
2238function( C2G )
2239    return PreCat2GroupByPreCat1Groups(
2240               Left2DimensionalGroup( C2G ),
2241               Up2DimensionalGroup( C2G ),
2242               Down2DimensionalGroup( C2G ),
2243               Right2DimensionalGroup( C2G ),
2244               Diagonal2DimensionalGroup( C2G ) );
2245end );
2246
2247##############################################################################
2248##
2249#M  LeftRightMorphism . . . . . . . . . . . . . . . . for a precrossed square
2250#M  UpDownMorphism  . . . . . . . . . . . . . . . . . for a precrossed square
2251##
2252InstallMethod( LeftRightMorphism, "for a precrossed square", true,
2253    [ IsPreCrossedSquare ], 0,
2254function( s )
2255    return XModMorphismByGroupHomomorphisms(
2256        Left2DimensionalGroup(s), Right2DimensionalGroup(s),
2257        Boundary( Up2DimensionalGroup(s) ),
2258        Boundary( Down2DimensionalGroup(s) ) );
2259end );
2260
2261InstallMethod( UpDownMorphism, "for a precrossed square", true,
2262    [ IsPreCrossedSquare ], 0,
2263function( s )
2264    return XModMorphismByGroupHomomorphisms(
2265           Up2DimensionalGroup(s), Down2DimensionalGroup(s),
2266           Boundary( Left2DimensionalGroup(s) ),
2267           Boundary( Right2DimensionalGroup(s) ) );
2268end );
2269
2270##############################################################################
2271##
2272#M  IsSymmetric3DimensionalGroup . . . . check whether a 3d-group is symmetric
2273##
2274InstallMethod( IsSymmetric3DimensionalGroup,
2275    "generic method for 3d-groups", true, [ IsHigherDimensionalGroup ], 0,
2276function( XS )
2277    return IsHigherDimensionalGroup( XS )
2278           and HigherDimension( XS ) = 3
2279           and ( Up2DimensionalGroup( XS ) = Left2DimensionalGroup( XS ) )
2280           and ( Right2DimensionalGroup( XS ) = Down2DimensionalGroup( XS ) );
2281end );
2282