##############################################################################
##
#W  actor2.gi                      XMOD Package                  Chris Wensley
#W                                                                 & Murat Alp
##
##  Declaration file for functions of the XMOD package.
##
#H  @(#)$Id: actor2.gi,v 2.006 2004/09/06 gap Exp $
##
#Y  Copyright (C) 1999,2001 University of St. Andrews, North Haugh,
#Y                          St. Andrews, Fife KY16 9SS, Scotland
##
Revision.("xmod/gap/actor2_gd") := 
   "@(#)$Id: actor2.gi,v 2.004 2004/04/24 gap Exp $";


#############################################################################
##
#M  AutomorphismPermGroup( <XM> )  subgroup of Aut(Source(XM))xAut(Range(XM))
##
InstallMethod( AutomorphismPermGroup, "automorphism perm group of xmod", 
    true, [ IsXMod ], 0, 
function( XM )

    local  S, genS, ngS, R, genR, ngR, bdy, AS, genAS, PAS, genPAS, a2pS, p2aS,
           AR, genAR, PAR, genPAR, a2pR, p2aR, EPAS, EPAR, autogens, 
           D, genD, infoD, P, genP, p2, p2i, imsrc, imrng, 
           as0, imas, as, ar0, imar, ar, num, es, er, e, mor, ismor, 
           act, actr, ok, r, s, i, j, s2r, ass, arr, actarr, ass2arr, ass2r,
           projS, projR, egenS, egenR, ePAS, ePAR, newS, oldS, newR, oldR;

    S := Source( XM );
    genS := GeneratorsOfGroup( S );
    ngS := Length( genS );
    R := Range( XM );
    genR := GeneratorsOfGroup( R );
    ngR := Length( genR );
    bdy := Boundary( XM );
    act := XModAction( XM );

    ## IsomorphismSmallPermGroup added 08/01/04
    AS := AutomorphismGroup( S );
    genAS := GeneratorsOfGroup( AS );
    a2pS := IsomorphismSmallPermGroup( AS );
    ## a2pS := NiceMonomorphism( AS );
    PAS := Image( a2pS );
    ## PAS := NiceObject( AS );
    genPAS := Image( a2pS, genAS );

    ####  the NC added 06/01/04
    p2aS := GroupHomomorphismByImagesNC( PAS, AS, genPAS, genAS );
    SetIsomorphismAutoGroup( PAS, p2aS );
    AR := AutomorphismGroup( R );
    genAR := GeneratorsOfGroup( AR );
    a2pR := IsomorphismSmallPermGroup( AR );
    ## a2pR := NiceMonomorphism( AR );
    PAR := Image( a2pR );
    ## PAR := NiceObject( AR );
    genPAR := Image( a2pR, genAR );
    p2aR := GroupHomomorphismByImagesNC( PAR, AR, genPAR, genAR );
    SetIsomorphismAutoGroup( PAR, p2aR );

    EPAS := Elements( PAS );
    EPAR := Elements( PAR );
    D := DirectProduct( PAS, PAR );
    genD := GeneratorsOfGroup( D );
    if ( HasName( PAS ) and HasName( PAR ) ) then
        SetName( D, Concatenation( Name(PAS), "x", Name(PAR) ) );
    fi;
    infoD := DirectProductInfo( D );
    p2 := infoD.perms[2];
    p2i := p2^(-1);
    newS := infoD.news[1];  oldS := infoD.olds[1];
    newR := infoD.news[2];  oldR := infoD.olds[2];
    P := Subgroup( D, [ ] );
    num := 0;
    autogens := [ ];
    for es in EPAS do
        as0 := Image( p2aS, es );
        ## ?? use ImagesSource here ??
        imas := List( genS, s -> Image( as0, s ) );
        ## ?? in what way do as0 and as differ, and does it matter ??
        as := GroupHomomorphismByImages( S, S, genS, imas );
        for er in EPAR do
            ar0 := Image( p2aR, er );
            imar := List( genR, r -> Image( ar0, r ) );
            ar := GroupHomomorphismByImages( R, R, genR, imar );
            ok := ( bdy*ar  =  as*bdy );
            ## added (07/01/04) : now need to test that, 
            ## for all generators,  as(s^r) = (as s)^(ar r) ##
            i := 0;
            while ( ok and ( i < ngS ) ) do
                i := i+1;  s := genS[i];
                ass := Image( as, s );
                j := 0;
                while( ok and ( j < ngR ) ) do
                    j := j+1;  r := genR[j];
                    actr := Image( act, r );
                    s2r := Image( actr, s );
                    ass2r := Image( as, s2r ); 
                    arr := Image( ar, r );
                    actarr := Image( act, arr );
                    ass2arr := Image( actarr, ass );
                    ok := ( ass2r = ass2arr );
                    if not ok then
                        Info( InfoXMod, 1, "sigma(s^r) <> (sigma s)^(rho r)" );
                        Info( InfoXMod, 1, [r,s,ass2r,ass2arr] );
                    fi;
                od;
            od;
            ## end of addition ##
            if ok then
                num := num + 1;
                e := es * er^p2;
                if not ( e in P ) then
                    mor := Make2dMapping( XM, XM, as, ar );
                    ismor := IsXModMorphism( mor );
                    if ismor then
                        Add( autogens, mor );
                        ## Add( autogens, [ as, ar ] );
                        P := ClosureGroup( P, e );
                    fi;
                fi;
            fi;
        od;
    od;
    genP := GeneratorsOfGroup( P );
    ## changed 30/09/03 from PermList to MappingPermListList
    ## imsrc := List( genP, g -> PermList( List( newS, x->x^g) ) );
    imsrc := List( genP, g -> 
                   MappingPermListList( oldS, List( newS, x->(x^g) ) ) );
    ## imrng := List( genP, g -> PermList( List( newR, x->(x^g)^p2i ) ) );
    imrng := List( genP, g -> 
                   MappingPermListList( oldR, List( newR, x->(x^g)^p2i ) ) );
    projS := GroupHomomorphismByImages( P, PAS, genP, imsrc );
    projR := GroupHomomorphismByImages( P, PAR, genP, imrng );
    genPAS := GeneratorsOfGroup( PAS );
    ePAS := GroupHomomorphismByImages( PAS, D, genPAS, genPAS );
    genPAR := GeneratorsOfGroup( PAR );
    egenR := List( genPAR, p -> p^p2 );
    ePAR := GroupHomomorphismByImages( PAR, D, genPAR, egenR );
#    P.autogens := autogens;
#    Arec := ActorSquareRecord( XM );
#    Arec.automorphismPermGroup := P;
    SetGeneratingAutomorphisms( XM, autogens );
    SetIsAutomorphismPermGroupOfXMod( P, true );
    SetEmbedSourceAutos( P, ePAS );
    SetEmbedRangeAutos( P, ePAR );
    SetSourceProjection( P, projS );
    SetRangeProjection( P, projR );
    SetXModActedUpon( P, XM );
    return P;
end );

#############################################################################
##
#M  PermAutomorphismAsXModMorphism( <xmod>, <permaut> )
##
InstallMethod( PermAutomorphismAsXModMorphism, 
    "xmod morphism coresponding to an element of the AutomorphismPermGroup",
    true, [ IsXMod, IsPerm ], 0, 
function( XM, a )

    local APXM, sp, rp, sa, ra, si, ri, smor, rmor, mor;

    APXM := AutomorphismPermGroup( XM );
    sp := SourceProjection( APXM );
    sa := Image( sp, a );
    si := IsomorphismAutoGroup( Range( sp ) );
    smor := Image( si, sa );
    rp := RangeProjection( APXM );
    ra := Image( rp, a );
    ri := IsomorphismAutoGroup( Range( rp ) );
    rmor := Image( ri, ra );
    mor := XModMorphism( XM, XM, smor, rmor ); 
    return mor;
end );

#############################################################################
##
#M  ImageAutomorphismDerivation( <mor>, <chi> )
##
InstallMethod( ImageAutomorphismDerivation, "image of derivation under action",
    true, [ IsXModMorphism, IsDerivation ], 0, 
function( mor, chi )

    local  XM, R, genR, imj, rho, imrho, sigma, invrho,
           rngR, k, r, rr, crr, chj;

    XM := Source( mor );
    sigma := SourceHom( mor );
    rho := RangeHom( mor );
    R := Range( XM );
    genR := StrongGeneratorsStabChain( StabChain( R ) );
    rngR := [ 1..Length( genR ) ];
    imrho := List( genR, r -> Image( rho, r ) );
    invrho := GroupHomomorphismByImages( R, R, imrho, genR );
    imj := 0 * rngR;
    for k in rngR do
        r := genR[k];
        rr := Image( invrho, r );
        crr := DerivationImage( chi, rr );
        imj[k] := Image( sigma, crr );
    od;
    chj := DerivationByImages( XM, imj );
    return chj;
end );

#############################################################################
##
#M  WhiteheadXMod( <XM> )     (InnerSourceHom : Range(XM) -> Whitehead Group)
##
InstallMethod( WhiteheadXMod, "Whitehead crossed module", true, 
    [ IsXMod ], 0, 
function( XM )
    local  S, genS, reg, imreg, W, WT, posW, nposW, genW, imiota,
           s, chi, poschi, iota, autS, genchi, j, sigma, ima, a, 
           imact, act, WX, name;

    S := Source( XM );
    genS := GeneratorsOfGroup( S );
    reg := RegularDerivations( XM );
    imreg := ImagesList( reg );
    W := WhiteheadPermGroup( XM );
    WT := WhiteheadGroupTable( XM );
    posW := WhiteheadGroupGeneratorPositions( XM );
    nposW := Length( posW );
    genW := GeneratorsOfGroup( W );
    # determine the boundary map iota = PrincipalSourceHom
    imiota := [ ];
    for s in genS do
        chi := PrincipalDerivation( XM, s );
        poschi := Position( imreg, GeneratorImages( chi ) );
        Add( imiota, PermList( WT[poschi] ) );
    od;
    iota := GroupHomomorphismByImages( S, W, genS, imiota );
    ##  ????? should this be a general mapping ????????????????????
    if not IsGroupHomomorphism( iota ) then
        Error( "Whitehead boundary fails to be a homomorphism" );
    fi;
    # now calculate the action homomorphism
    autS := AutomorphismGroup( S );
    genchi := WhiteheadGroupGeneratingDerivations( XM );
    imact := [ 1..nposW ];
    for j in [1..nposW] do
        chi := genchi[j];
        sigma := SourceEndomorphism( chi );
        ima := List( genS, s -> Image( sigma, s ) );
        a := GroupHomomorphismByImages( S, S, genS, ima );
        imact[j] := a;
    od;
    act := GroupHomomorphismByImages( W, autS, genW, imact );
    WX := XMod( iota, act );
    name := Name( XM );
    SetName( WX, Concatenation( "Whitehead", name ) );
    ## SetIsWhiteheadXMod( WX, true );
    return WX;
end );

#############################################################################
##
#M  NorrieXMod( <XM> )
##
InstallMethod( NorrieXMod, "Norrie crossed module", true,
    [ IsXMod ], 0, 
function( XM )

    local  S, R, genR, PX, DX, genP, Prng, AS, AR, a2pS, a2pR, PAR, p2aR, 
           im, r, autr, psrc, emsrc, conjr, prng, emrng, bdy, ok,
           imact, p, projp, proja, ima, a, act, i, f, NX, name;

    S := Source( XM );
    R := Range( XM );
    genR := GeneratorsOfGroup( R );
    PX := AutomorphismPermGroup( XM );
    DX := Parent( PX );
    genP := GeneratorsOfGroup( PX );
    Prng := [ 1..Length( genP ) ];
    AS := AutomorphismGroup( S );
    AR := AutomorphismGroup( R );
    a2pS := IsomorphismSmallPermGroup( AS );
    a2pR := IsomorphismSmallPermGroup( AR );
    PAR := Image( a2pR );
    p2aR := IsomorphismAutoGroup( PAR );
    # determine the boundary map
    im := [ ]; 
    for r in genR do
        autr := Image( XModAction( XM ), r );
        psrc := Image( a2pS, autr );
        emsrc := Image( EmbedSourceAutos( PX ), psrc );
        conjr := InnerAutomorphism( R, r );
        prng := Image( a2pR, conjr );
        emrng := Image( EmbedRangeAutos( PX ), prng );
        Add( im, emrng * emsrc );
    od;
    bdy := GroupHomomorphismByImages( R, PX, genR, im );
    # determine the action
    imact := 0 * Prng;
    for i in Prng do
        p := genP[i];
        projp := Image( RangeProjection( PX ), p );
        proja := Image( p2aR, projp );
        ima := List( genR, r -> Image( proja, r ) );
        a := GroupHomomorphismByImages( R, R, genR, ima );
        imact[i] := a;
    od;
    act := GroupHomomorphismByImages( PX, AR, genP, imact );
    for f in MappingGeneratorsImages( act )[2] do
        if ( f = IdentityMapping( R ) ) then
            f := InclusionMappingGroups( R, R );
        fi;
    od;
    ## create the crossed module
    NX := XMod( bdy, act );
    name := Name( XM );
    SetName( NX, Concatenation( "Norrie", name ) );
    return NX;
end );

#############################################################################
##
#M  LueXMod( <XM> )
##
InstallMethod( LueXMod, "Lue crossed module", true,
    [ IsXMod ], 0, 
function( XM )

    local  NX, Nbdy, Xbdy, Lbdy, PX, genPX, PXrng, S, genS, AS, a2pS, PAS, 
           p2aS, imact, i, p, projp, proja, ima, a, act, f, LX, name;

    NX := NorrieXMod( XM );
    Nbdy := Boundary( NX );
    Xbdy := Boundary( XM );
    Lbdy := Xbdy * Nbdy;
    PX := AutomorphismPermGroup( XM );
    genPX := GeneratorsOfGroup( PX );
    PXrng := [ 1..Length( genPX ) ];
    S := Source( XM );
    genS := GeneratorsOfGroup( S );
    AS := AutomorphismGroup( S );
    a2pS := IsomorphismSmallPermGroup( AS );
    PAS := Image( a2pS );
    p2aS := IsomorphismAutoGroup( PAS );
    imact := 0 * PXrng;
    for i in PXrng  do
        p := genPX[i];
        projp := Image( SourceProjection( PX ), p );
        proja := Image( p2aS, projp );
        ima := List( genS, s -> Image( proja, s ) );
        a := GroupHomomorphismByImages( S, S, genS, ima );
        imact[i] := a;
    od;
    act := GroupHomomorphismByImages( PX, AS, genPX, imact );
    for f in MappingGeneratorsImages( act )[2] do
        if ( f = IdentityMapping( S ) ) then
            f := InclusionMappingGroups( S, S );
        fi;
    od;
    LX := XMod( Lbdy, act );
    name := Name( XM );
    SetName( LX, Concatenation( "Lue", name ) );
    return LX;
end );


#############################################################################
##
#M  ActorXMod( <XM> )
##
InstallMethod( ActorXMod, "actor crossed module", true,
    [ IsXMod ], 0, 
function( XM )

    local  D, L, W, eW, PX, genPX, genpos, ngW, genW, invW, imdelta, 
           S, R, AS, AR, a2pS, a2pR, emsrc, emrng, i, j, k, mor, 
           imsrc, imrng, delta, GA, nGA, imact, rho, invrho, 
           impos, chi, chj, imgen, phi, id, aut, act, ActX, name;

    D := RegularDerivations( XM );
    L := ImagesList( D );
    W := WhiteheadPermGroup( XM );
    eW := Elements( W );
    PX := AutomorphismPermGroup( XM );
    genPX := GeneratorsOfGroup( PX );
    genpos := WhiteheadGroupGeneratorPositions( XM );
    ngW := Length( genpos );
    # determine the boundary map
    genW := List( genpos, i -> eW[i] );
    invW := List( genW, g -> g^-1 );
    imdelta := ListWithIdenticalEntries( ngW, 0 );
    S := Source( XM );
    R := Range( XM );
    AS := AutomorphismGroup( S );
    AR := AutomorphismGroup( R );
    a2pS := IsomorphismSmallPermGroup( AS );
    a2pR := IsomorphismSmallPermGroup( AR );
    ##PAR := Image( a2pR );
    emsrc := EmbedSourceAutos( PX );
    emrng := EmbedRangeAutos( PX );
    for i in [1..ngW] do
        j := genpos[i];
        chj := DerivationByImages( XM, L[j] );
        mor := Object2dEndomorphism( chj );
        imsrc := Image( emsrc, Image( a2pS, SourceHom( mor ) ) );
        imrng := Image( emrng, Image( a2pR, RangeHom( mor ) ) );
        imdelta[i] := imsrc * imrng;
    od;
    delta := GroupHomomorphismByImages( W, PX, genW, imdelta );
    Info( InfoXMod, 3, "delta: ", MappingGeneratorsImages( delta ) );

    # determine the action
    GA := GeneratingAutomorphisms( XM );
    nGA := Length( GA );
    imact := ListWithIdenticalEntries( nGA, 0 );
    for k in [1..nGA] do
        mor := GA[k];
        rho := RangeHom( mor );
        invrho := rho^(-1);
        impos := ListWithIdenticalEntries( ngW, 0);
        for i in [1..ngW] do
            j := genpos[i];
            chi := DerivationByImages( XM, L[j] );
            chj := ImageAutomorphismDerivation( mor, chi );
            impos[i] := Position( L, GeneratorImages( chj ) );
        od;
        imgen := List( impos, i -> eW[i] );
        phi := GroupHomomorphismByImages( W, W, genW, imgen );
        imact[k] := phi;
    od;
    id := InclusionMappingGroups( W, W );
    aut := Group( imact, id );
    SetName( aut, "Aut(W)" );
    act := GroupHomomorphismByImages( PX, aut, genPX, imact );
    ActX := XMod( delta, act );
    name := Name( XM );
    SetName( ActX, Concatenation( "Actor", name ) );
    return ActX;
end );

#############################################################################
##
#M  ActorCat1( <C> )
##
InstallMethod( ActorCat1, "actor cat1-group", true, [ IsCat1 ], 0, 
function( C )
    return 0;
end );

#############################################################################
##
#M  InnerMorphism( <XM> )
##
InstallMethod( InnerMorphism, "inner morphism of xmod", true,
    [ IsXMod ], 0, 
function( XM )

    local  WX, NX, ActX, mor;

    WX := WhiteheadXMod( XM );
    NX := NorrieXMod( XM );
    ActX := ActorXMod( XM );
    mor := XModMorphismByHoms( XM, ActX, Boundary(WX), Boundary(NX) );
    return mor;
end );

#############################################################################
##
#M  Centre( <XM> )
##
InstallOtherMethod( Centre, "centre of an xmod", true, [ IsXMod ], 0, 
function( XM )
    return Kernel( InnerMorphism( XM ) );
end );

#############################################################################
##
#M  ImagesSource( <mor> )
##
InstallOtherMethod( ImagesSource, "xmod image for an xmod morphism", true, 
    [ IsPreXModMorphism ], 0, 
function( mor )
    
    local  S, R, Shom, Rhom, imS, imR, SX;

    Shom := SourceHom( mor );
    Rhom := RangeHom( mor );
    imS := ImagesSource( Shom );
    imR := ImagesSource( Rhom );
    SX := SubPreXMod( Range(mor), imS, imR );
    return SX;
end );

#############################################################################
##
#M  InnerActorXMod( <XM> )
##
InstallMethod( InnerActorXMod, "inner actor crossed module", true,
    [ IsXMod ], 0, 
function( XM )

    local  InnX, mor, name, ActX;
    
    ActX := ActorXMod( XM );
    mor := InnerMorphism( XM );
    InnX := ImagesSource( mor );
    if ( InnX = ActX ) then
        InnX := ActX;
    else
        name := Name( XM );
        SetName( InnX, Concatenation( "InnerActor", name ) );
    fi;
    return InnX;
end );


#############################################################################
##
#E  actor2.gi . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
