Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/groupoids/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 11.8.2025 mit Größe 39 kB image not shown  

Quelle  gpdaut.gi   Sprache: unbekannt

 
#############################################################################
##
#W  gpdaut.gi              GAP4 package `groupoids'            Chris Wensley
#W                                                              & Emma Moore

#############################################################################
##
#M  GroupoidAutomorphismByObjectPermNC  
#M  GroupoidAutomorphismByObjectPerm 
##
InstallMethod( GroupoidAutomorphismByObjectPermNC , 
    "for a single piece groupoid and a permutation of objects", true, 
    [ IsGroupoid and IsDirectProductWithCompleteDigraphDomain, 
      IsHomogeneousList ], 0,
function( gpd, oims ) 

    local obs, gens, ngens, images, i, a, pt, ph, mor, L; 

    obs := gpd!.objects; 
    gens := GeneratorsOfGroupoid( gpd ); 
    ngens := Length( gens ); 
    images := [1..ngens]; 
    for i in [1..ngens] do 
        a := gens[i]; 
        pt := Position( obs, a![3] ); 
        ph := Position( obs, a![4] );
        images[i] := Arrow( gpd, a![2], oims[pt], oims[ph] ); 
    od; 
    if ( fail in images ) then 
        Error( "the set of images contains 'fail'" ); 
    fi;
    mor := GroupoidHomomorphismFromSinglePiece( gpd, gpd, gens, images );
    SetIsInjectiveOnObjects( mor, true ); 
    SetIsSurjectiveOnObjects( mor, true ); 
    L := [1..Length(obs)]; 
    SortParallel( ShallowCopy( oims ), L );  
    SetOrder( mor, Order( PermList( L ) ) ); 
    SetIsGroupoidAutomorphismByObjectPerm( mor, true ); 
    SetAutomorphismDomain( mor, gpd ); 
    return mor; 
end ); 

InstallMethod( GroupoidAutomorphismByObjectPermNC , 
    "for a single piece groupoid with rays rep", true, 
    [ IsGroupoid and IsSinglePieceRaysRep, IsHomogeneousList ], 0,
function( gpd, oims ) 

    local iso, inv, sgpd, aut; 

    iso := IsomorphismStandardGroupoid( gpd, ObjectList( gpd ) ); 
    inv := InverseGeneralMapping( iso ); 
    sgpd := Image( iso ); 
    aut := GroupoidAutomorphismByObjectPermNC( sgpd, oims ); 
    return iso * aut * inv; 
end ); 

InstallMethod( GroupoidAutomorphismByObjectPermNC,  
    "for a hom discrete groupoid and a permutation of objects", true, 
    [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0,
function( gpd, oims )

    local gpd1, gp, id, homs, mor, L; 

    gpd1 := Pieces( gpd )[1]; 
    gp := gpd1!.magma; 
    id := IdentityMapping( gp ); 
    homs := List( oims, o -> id ); 
    mor := GroupoidHomomorphismFromHomogeneousDiscreteNC
               ( gpd, gpd, homs, oims ); 
    SetIsInjectiveOnObjects( mor, true ); 
    SetIsSurjectiveOnObjects( mor, true ); 
    L := [1..Length(oims)]; 
    SortParallel( ShallowCopy( oims ), L );  
    SetOrder( mor, Order( PermList( L ) ) );
    SetIsGroupoidAutomorphismByObjectPerm( mor, true ); 
    SetAutomorphismDomain( mor, gpd ); 
    return mor; 
end ); 

InstallMethod( GroupoidAutomorphismByObjectPerm, 
    "for a groupoid and a permutation of objects", true, 
    [ IsGroupoid, IsHomogeneousList ], 0,
function( gpd, oims ) 

    local obs, pos; 

    obs := ObjectList( gpd ); 
    pos := PermList( List( oims, o -> Position( obs, o ) ) ); 
    if ( pos = fail ) then 
        Error( "object images not a permutation of the objects" ); 
    fi; 
    return GroupoidAutomorphismByObjectPermNC( gpd, oims ); 
end ); 

#############################################################################
##
#M  GroupoidAutomorphismByGroupAutoNC  
#M  GroupoidAutomorphismByGroupAuto 
##
InstallMethod( GroupoidAutomorphismByGroupAutoNC , 
    "for a groupoid and an automorphism of the root group", true, 
    [ IsGroupoid and IsSinglePiece, IsGroupHomomorphism and IsBijective ], 0,
function( gpd, hom ) 

    local gens, images, i, a, mor; 

    gens := GeneratorsOfGroupoid( gpd ); 
    images := ShallowCopy( gens );
    for i in [1..Length(gens) - Length(ObjectList(gpd)) + 1] do 
        a := gens[i];
        images[i] := Arrow( gpd, ImageElm(hom,a![2]), a![3], a![4] ); 
    od;
    mor := GroupoidHomomorphismFromSinglePiece( gpd, gpd, gens, images ); 
    SetIsInjectiveOnObjects( mor, true ); 
    SetIsSurjectiveOnObjects( mor, true ); 
    SetOrder( mor, Order( hom ) ); 
    SetIsGroupoidAutomorphismByGroupAuto( mor, true ); 
    SetAutomorphismDomain( mor, gpd ); 
    return mor; 
end ); 

InstallMethod( GroupoidAutomorphismByGroupAuto, 
    "for a groupoid and an automorphism of the root group", true, 
    [ IsGroupoid and IsSinglePiece, IsGroupHomomorphism ], 0,
function( gpd, hom ) 

    local rgp; 

    rgp := gpd!.magma; 
    if not ( (Source(hom) = rgp) and (Range(hom) = rgp) ) then 
        Error( "hom not an endomorphism of the root group" ); 
    fi; 
    if not IsBijective( hom ) then 
        Error( "hom is not an automorphism" ); 
    fi;
    return GroupoidAutomorphismByGroupAutoNC( gpd, hom ); 
end ); 

#############################################################################
##
#M  GroupoidAutomorphismByGroupAutosNC  
#M  GroupoidAutomorphismByGroupAutos 
##
InstallMethod( GroupoidAutomorphismByGroupAutosNC , 
    "for homogeneous discrete groupoid and automorphism list", true, 
    [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0,
function( gpd, homs ) 

    local obs, orders, m; 

    obs := ObjectList( gpd );
    m := GroupoidHomomorphismFromHomogeneousDiscreteNC( gpd, gpd, homs, obs ); 
    SetIsEndoGeneralMapping( m, true ); 
    SetIsInjectiveOnObjects( m, true ); 
    SetIsSurjectiveOnObjects( m, true ); 
    orders := List( homs, Order ); 
    SetOrder( m, Lcm( orders ) ); 
    SetAutomorphismDomain( m, gpd ); 
    return m; 
end ); 

InstallMethod( GroupoidAutomorphismByGroupAutos, 
    "for homogeneous discrete groupoid and automorphism list", true, 
    [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0,
function( gpd, homs )  

    local pieces, len, i, p, g, h; 

    pieces := Pieces( gpd ); 
    len := Length( pieces ); 
    if not ( len = Length( homs ) ) then 
        Error( "length of <homs> not equal to number of objects on <gpd>," ); 
    fi; 
    for i in [1..len] do 
        p := pieces[i];  
        g := p!.magma; 
        h := homs[i]; 
        if not ( (Source(h) = g) and (Range(h) = g) ) then 
            Error( "<h> not an endomorphism of group <g> at object <i>," ); 
        fi; 
        if not IsBijective( h ) then 
            Error( "<h> not an automorphism of group <g> at object <i>," ); 
        fi; 
    od; 
    return GroupoidAutomorphismByGroupAutosNC( gpd, homs ); 
end ); 

#############################################################################
##
#M  GroupoidAutomorphismByNtupleNC  
#M  GroupoidAutomorphismByNtuple 
##
InstallMethod( GroupoidAutomorphismByNtupleNC , 
    "for a groupoid and a list of elements of the root group", true, 
    [ IsGroupoid and IsSinglePiece, IsHomogeneousList ], 0,
function( gpd, shifts )

    local gens, ngens, obs, images, i, p, q, a, mor; 

    gens := GeneratorsOfGroupoid( gpd ); 
    ngens := Length( gens ); 
    obs := gpd!.objects;
    images := ShallowCopy( gens ); 
    for i in [1..ngens] do 
        a := gens[i];
        p := Position( obs, a![3] );
        q := Position( obs, a![4] );
        images[i] := Arrow( gpd, (shifts[p])^-1*a![2]*shifts[q], a![3], a![4] );
    od; 
    mor := GroupoidHomomorphismFromSinglePiece( gpd, gpd, gens, images ); 
    SetOrder( mor, Lcm( List( shifts, Order ) ) ); 
    SetIsInjectiveOnObjects( mor, true ); 
    SetIsSurjectiveOnObjects( mor, true ); 
    SetIsGroupoidAutomorphismByRayShifts( mor, true ); 
    return mor;
end ); 

InstallMethod( GroupoidAutomorphismByNtuple, 
    "for a groupoid and a list of elements of the root group", true, 
    [ IsGroupoid and IsSinglePiece, IsHomogeneousList ], 0,
function( gpd, shifts ) 

    local rgp, rays, nobs, conj; 

    rgp := gpd!.magma; 
    rays := gpd!.rays; 
    nobs := Length( gpd!.objects );
    if not ForAll( shifts, s -> s in rgp ) then  
        Error( "ray shifts not all in the root group" ); 
    fi; 
    return GroupoidAutomorphismByNtupleNC( gpd, shifts ); 
end ); 

#############################################################################
##
#M  GroupoidAutomorphismByRayShiftsNC  
#M  GroupoidAutomorphismByRayShifts 
##
InstallMethod( GroupoidAutomorphismByRayShiftsNC , 
    "for a groupoid and a list of elements of the root group", true, 
    [ IsGroupoid and IsSinglePiece, IsHomogeneousList ], 0,
function( gpd, shifts ) 
    if not ( shifts[1] = One( gpd!.magma ) ) then 
        Error( "the first ray shift is not the identity" ); 
    fi; 
    return GroupoidAutomorphismByNtupleNC( gpd, shifts );
end );

InstallMethod( GroupoidAutomorphismByRayShifts, 
    "for a groupoid and a list of elements of the root group", true, 
    [ IsGroupoid and IsSinglePiece, IsHomogeneousList ], 0,
function( gpd, shifts ) 
    if not ( shifts[1] = One( gpd!.magma ) ) then 
        Error( "the first ray shift is not the identity" ); 
    fi; 
    return GroupoidAutomorphismByNtuple( gpd, shifts ); 
end ); 

#############################################################################
##
#M  GroupoidInnerAutomorphism 
#M  GroupoidInnerAutomorphismNormalSubgroupoid
##
InstallMethod( GroupoidInnerAutomorphism, 
    "for a groupoid and an element", true,
    [ IsGroupoid, IsGroupoidElement ], 0,
function( gpd, e ) 
    Error( "not yet implemented for unions of groupoids" );
end );

InstallMethod( GroupoidInnerAutomorphism, 
    "for a groupoid and an element", true, 
    [ IsGroupoid and IsSinglePieceDomain, IsGroupoidElement ], 0,
function( gpd, e ) 

    local gens, images; 

    Info( InfoGroupoids, 3, "GroupoidInnerAutomorphism from single piece" );  
    gens := GeneratorsOfGroupoid( gpd ); 
    images := List( gens, g -> g^e ); 
    return GroupoidHomomorphism( gpd, gpd, gens, images );
end );

InstallMethod( GroupoidInnerAutomorphism, 
    "for a groupoid and an element", true, 
    [ IsGroupoid and IsDiscreteDomainWithObjects, IsGroupoidElement ], 0,
function( gpd, e ) 

    local obs, nobs, pos, id, auts; 

    Info( InfoGroupoids, 3, "GroupoidInnerAutomorphism from discrete domain" );  
    obs := gpd!.objects; 
    nobs := Length( obs );
    pos := Position( obs, e![3] ); 
    id := IdentityMapping( gpd!.magma );
    auts := List( [1..nobs], i -> id ); 
    auts[pos] := InnerAutomorphism( gpd!.magma, e![2] ); 
    return GroupoidAutomorphismByGroupAutosNC( gpd, auts ); 
end );

InstallMethod( GroupoidInnerAutomorphismNormalSubgroupoid, 
    "for a groupoid, a subgroupoid, and an element", true, 
    [ IsGroupoid and IsSinglePieceDomain, IsGroupoid, IsGroupoidElement ], 0,
function( gpd, sub, e ) 

    local obs, gens, images, pieces, n, homs, oims, i, p, o, q, h; 

    Info( InfoGroupoids, 3, "GroupoidInnerAutomorphismNormalSubgroupoid" ); 
    if not IsWideSubgroupoid( gpd, sub ) then 
        Error( "sub is not a subgroupoid of gpd" ); 
    fi;
    if IsSinglePiece( sub ) then
        if not ( e![2] in RootGroup( sub ) ) then
            Error( "element e![2] in not in the root group of sub" );
        fi;
    elif IsHomogeneousDomainWithObjects( sub ) then
        if not ( e![2] in RootGroup( Pieces(sub)[1] ) ) then 
            Error( "element e![2] in not in the root groups of sub" );
        fi;
    else
        Error( "invalid subgroupoid sub" );
    fi;
    obs := gpd!.objects;
    if IsSinglePiece( sub ) then
        gens := GeneratorsOfGroupoid( sub );
        images := List( gens, g -> g^e );
        return GroupoidHomomorphism( sub, sub, gens, images );
    elif IsHomogeneousDomainWithObjects( sub ) then
        pieces := Pieces( sub );
        n := Length( pieces );
        homs := ListWithIdenticalEntries( n, 0 );
        oims := ListWithIdenticalEntries( n, 0 );
        for i in [1..n] do
            p := pieces[i];
            gens := GeneratorsOfGroupoid( p );
            images := List( gens, g -> g^e );
            o := images[1]![3];
            oims[i] := o;
            q := pieces[ Position( obs, o ) ];
            h := GroupoidHomomorphism( p, q, gens, images );
            homs[i] := RootGroupHomomorphism( h );
        od;
        return GroupoidHomomorphismFromHomogeneousDiscrete( sub, sub, homs, oims );
    else
        return fail;
    fi;
end );

#############################################################################
##
#M  Size( <agpd> ) . . . . . . . . . . . . . . . . . for a connected groupoid
##
InstallMethod( Size, "for a groupoid automorphism group", true,  
    [ IsAutomorphismGroupOfGroupoid ], 0,
function( agpd ) 

    local gpd, gp, n, aut; 

    gpd := AutomorphismDomain( agpd ); 
    gp := gpd!.magma; 
    if IsSinglePieceDomain( gpd ) then  
        n := Length( ObjectList( gpd ) ); 
        aut := AutomorphismGroup( gpd!.magma );
        return Factorial( n ) * Size( aut ) * Size( gp )^(n-1); 
    elif IsDiscreteDomainWithObjects( gpd ) 
             and IsHomogeneousDomainWithObjects( gpd ) then 
        n := Length( ObjectList( gpd ) ); 
        aut := AutomorphismGroup( gpd!.magma ); 
        return Factorial( n ) * Size( aut )^n;             
    fi;
    return fail; 
end ); 

##############################################################################
##
#M  NiceObjectAutoGroupGroupoid( <gpd>, <aut> ) . . create a nice monomorphism 
##
InstallMethod( NiceObjectAutoGroupGroupoid, "for a single piece groupoid", true, 
    [ IsGroupoid and IsSinglePieceDomain, IsAutomorphismGroupOfGroupoid ], 0,
function( gpd, aut ) 

    local genaut, rgp, genrgp, nrgp, agp, genagp, nagp, iso1, im1, iso2, 
          pagp, iso, obs, n, L, symm, gensymm, nsymm, ngp, genngp, nngp, 
          ninfo, nemb, gens1, i, pi, imi, j, gens2, k, krgp, ikrgp, 
          pasy, esymm, epagp, genpasy, gens12, actgp, ok, action, sdp, 
          sinfo, siso, ssdp, epasy, engp, gennorm, norm, a, c, c1, c2, c12, 
          agens1, agens2, agens3, agens, nat, autgen, eno, gim1, gim2, gim3, 
          niceob, nicemap; 

    genaut := GeneratorsOfGroup( aut );
    ## first: automorphisms of the root group 
    rgp := gpd!.magma; 
    genrgp := GeneratorsOfGroup( rgp );
    nrgp := Length( genrgp ); 
    agp := AutomorphismGroup( rgp ); 
    genagp := SmallGeneratingSet( agp ); 
    nagp := Length( genagp ); 
    iso1 := IsomorphismPermGroup( agp ); 
    im1 := Image( iso1 );
    iso2 := SmallerDegreePermutationRepresentation( im1 );
    pagp := Image( iso2 ); 
    iso := iso1*iso2; 
    agens1 := List( genagp, a -> ImageElm( iso, a ) ); 
    ## second: permutations of the objects 
    obs := gpd!.objects; 
    n := Length( obs );
    if ( n = 1 ) then 
        return pagp; 
    elif ( n = 2 ) then 
        gensymm := [ (1,2) ]; 
    else 
        L := [2..n]; 
        Append( L, [1] ); 
        gensymm := [ PermList(L), (1,2) ];  #? replace (1,2) with (n-1,n) ?? 
    fi;
    symm := Group( gensymm ); 
    nsymm := Length( gensymm ); 
    ## third: ray products 
    ngp := DirectProduct( ListWithIdenticalEntries( n, rgp ) ); 
    genngp := GeneratorsOfGroup( ngp ); 
    nngp := Length( genngp );
    ninfo := DirectProductInfo( ngp ); 
    ## force construction of the n embeddings 
    for i in [1..n] do 
        k := Embedding( ngp, i ); 
    od; 
    nemb := ninfo!.embeddings; 
    # action of agp on ngp 
    gens1 := [1..nagp]; 
    for i in [1..nagp] do 
        k := genagp[i]; 
        krgp := List( genrgp, r -> ImageElm( k, r ) ); 
        ikrgp := [ ]; 
        for j in [1..n] do 
            Append( ikrgp, List( krgp, x -> ImageElm( nemb[j], x ) ) ); 
        od; 
        gens1[i] := GroupHomomorphismByImages( ngp, ngp, genngp, ikrgp ); 
    od; 
    ## action of symm on ngp = rgp^n 
    gens2 := [1..nsymm]; 
    for i in [1..nsymm] do 
        pi := gensymm[i]^-1; 
        gens2[i] := GroupHomomorphismByImages( ngp, ngp, genngp,  
            List( [1..nngp], j -> genngp[ RemInt( j-1, nrgp ) + 1  
            + nrgp * (( QuoInt( j-1, nrgp ) + 1 )^pi - 1 ) ] ) ); 
    od; 
    pasy := DirectProduct( pagp, symm ); 
    epagp := Embedding( pasy, 1 ); 
    agens1 := List( agens1, g -> ImageElm( epagp, g ) ); 
    esymm := Embedding( pasy, 2 ); 
    agens2 := List( gensymm, g -> ImageElm( esymm, g ) ); 
    ## genpasy := GeneratorsOfGroup( pasy ); 
    genpasy := Concatenation( agens1, agens2 );
    #  construct the semidirect product 
    gens12 := Concatenation( gens1, gens2 ); 
    actgp := Group( gens12 ); 
    ok := IsGroupOfAutomorphisms( actgp ); 
    action := GroupHomomorphismByImages( pasy, actgp, genpasy, gens12 ); 
    sdp := SemidirectProduct( pasy, action, ngp ); 
    Info( InfoGroupoids, 2, "sdp has ", 
          Length(GeneratorsOfGroup(sdp)), " gens." ); 
    sinfo := SemidirectProductInfo( sdp ); 
    siso := SmallerDegreePermutationRepresentation( sdp ); 
    ssdp := Image( siso ); 
    epasy := Embedding( sdp, 1 ) * siso; 
    agens1 := List( agens1, g -> ImageElm( epasy, g ) );  
    agens2 := List( agens2, g -> ImageElm( epasy, g ) ); 
    engp := Embedding( sdp, 2 ) * siso; 
    #  why [3..nngp]?  no doubt because Sn has two generators? 
    agens3 := List( genngp{[3..nngp]}, g -> ImageElm( engp, g ) ); 
    #  construct the normal subgroup 
    gennorm := [1..nrgp ]; 
    for i in [1..nrgp] do 
        c := genrgp[i]; 
        a := GroupHomomorphismByImages( rgp, rgp, genrgp, 
                                        List( genrgp, x->x^c ) );
        c1 := ImageElm( epasy, ImageElm( epagp, ImageElm( iso, a ) ) );
        c := c^-1; 
        c2 := ImageElm( engp, 
            Product( List( [1..n], j->ImageElm( nemb[j], c ) ) ) ); 
        gennorm[i] := c1 * c2; 
    od; 
    norm := Subgroup( ssdp, gennorm ); 
    ok := IsNormal( ssdp, norm ); 
    if not ok then 
        Error( "norm should be a normal subgroup of ssdp" ); 
    fi; 
    nat := NaturalHomomorphismByNormalSubgroup( ssdp, norm ); 
    niceob := Image( nat ); 
    eno := ListWithIdenticalEntries( n+2, 0 );
    eno[1] := iso * epagp * epasy * nat;   ## agp->pagp->pasy->ssdp->niceob
    eno[2] := esymm * epasy * nat;         ##      symm->pasy->ssdp->niceob
    for i in [1..n] do 
        gim1 := List( genrgp, g -> ImageElm( nemb[i], g ) ); 
        gim2 := List( gim1, g -> ImageElm( engp, g ) ); 
        gim3 := List( gim2, g -> ImageElm( nat, g ) ); 
        eno[i+2] := GroupHomomorphismByImages( rgp, niceob, genrgp, gim3 ); 
    od; 
    autgen := Concatenation( agens1, agens2, agens3 ); 
    agens := List( autgen, g -> ImageElm( nat, g ) ); 
    return [ niceob, eno ]; 
end );

InstallMethod( NiceObjectAutoGroupGroupoid, "for a hom discrete groupoid", true,
    [ IsHomogeneousDiscreteGroupoid, IsAutomorphismGroupOfGroupoid ], 0,
function( gpd, aut ) 

    local pieces, obs, m, p1, g1, geng1, ng1, ag1, genag1, nag, 
          iso1, ag2, genag2, mag2, genmag2, nmag2, minfo, i, k, memb, 
          K, L, symm, gensymm, imact, pi, actgp, ok, action, sdp, sinfo, 
          siso, ssdp, esymm, egensymm, emag2, egenmag2, agens, 
          im1, im2, im3, eno;  

    pieces := Pieces( gpd ); 
    obs := ObjectList( gpd ); 
    m := Length( obs );
    ## first: automorphisms of the object groups 
    p1 := pieces[1]; 
    g1 := p1!.magma; 
    geng1 := GeneratorsOfGroup( g1 );
    ng1 := Length( geng1 ); 
    ag1 := AutomorphismGroup( g1 ); 
    genag1 := SmallGeneratingSet( ag1 ); 
    nag := Length( genag1 ); 
    iso1 := IsomorphismPermGroup( ag1 ); 
    genag2 := List( genag1, g -> ImageElm( iso1, g ) ); 
    ag2 := Group( genag2 ); 
    mag2 := DirectProduct( ListWithIdenticalEntries( m, ag2 ) ); 
    genmag2 := GeneratorsOfGroup( mag2 ); 
    nmag2 := Length( genmag2 );
    minfo := DirectProductInfo( mag2 ); 
    ## force construction of the m embeddings 
    for i in [1..m] do 
        k := Embedding( mag2, i ); 
    od; 
    memb := minfo!.embeddings; 
    ## second: permutations of the objects 
    if ( m = 1 ) then 
        Error( "only one object, so no permutations" ); 
    elif ( m = 2 ) then 
        K := [1]; 
        gensymm := [ (1,2) ]; 
    else 
        K := [1,2]; 
        L := [2..m]; 
        Append( L, [1] ); 
        gensymm := [ PermList(L), (1,2) ];  #? replace (1,2) with (m-1,m) ?? 
    fi;
    symm := Group( gensymm ); 
    ## action of symm on mag2 = ag2^m 
    imact := ShallowCopy( K ); 
    for i in K do 
        pi := gensymm[i]^-1; 
        imact[i] := GroupHomomorphismByImages( mag2, mag2, genmag2,  
            List( [1..nmag2], j -> genmag2[ RemInt( j-1, nag ) + 1  
            + nag * (( QuoInt( j-1, nag ) + 1 )^pi - 1 ) ] ) ); 
    od; 
    #  construct the semidirect product: symm acting on mag2
    actgp := Group( imact ); 
    ok := IsGroupOfAutomorphisms( actgp ); 
    action := GroupHomomorphismByImages( symm, actgp, gensymm, imact ); 
    sdp := SemidirectProduct( symm, action, mag2 ); 
    Info( InfoGroupoids, 2, "sdp has ", 
          Length(GeneratorsOfGroup(sdp)), " gens." ); 
    sinfo := SemidirectProductInfo( sdp ); 
    ## (13/04/16) comment this out for the moment and replace with identity 
    ## siso := SmallerDegreePermutationRepresentation( sdp ); 
    siso := IdentityMapping( sdp ); 
    ssdp := Image( siso ); 
    esymm := Embedding( sdp, 1 ) * siso; 
    egensymm := List( gensymm, g -> ImageElm( esymm, g ) );  
    emag2 := Embedding( sdp, 2 ) * siso; 
    egenmag2 := List( genmag2{[1..nag]}, g -> ImageElm( emag2, g ) ); 
    eno := ListWithIdenticalEntries( m+1, 0 );
    eno[1] := esymm; 
    for i in [1..m] do 
        im1 := List( genag1, g -> ImageElm( iso1, g ) ); 
        im2 := List( im1, g -> ImageElm( memb[i], g ) ); 
        im3 := List( im2, g -> ImageElm( emag2, g ) ); 
        eno[i+1] := GroupHomomorphismByImages( ag1, ssdp, genag1, im3 ); 
    od; 
    agens := Concatenation( egensymm, egenmag2 ); 
    return [ ssdp, agens, eno ]; 
end );

#############################################################################
##
#M  AutomorphismGroupOfGroupoid( <gpd> )
##
InstallMethod( AutomorphismGroupOfGroupoid, "for one-object groupoid", true, 
    [ IsGroupoid and IsSinglePieceDomain and IsDiscreteDomainWithObjects ], 0,
function( gpd ) 

    local autgen, rgp, agp, genagp, a, a0, ok, id, aut;  

    Info( InfoGroupoids, 2, 
          "AutomorphismGroupOfGroupoid for one-object groupoids" ); 
    autgen := [ ]; 
    rgp := gpd!.magma; 
    agp := AutomorphismGroup( rgp ); 
    genagp := SmallGeneratingSet( agp ); 
    for a in genagp do  
        a0 := GroupoidAutomorphismByGroupAutoNC( gpd, a ); 
        ok := IsAutomorphismWithObjects( a0 ); 
        Add( autgen, a0 );  
    od; 
    id := IdentityMapping( gpd ); 
    aut := GroupWithGenerators( autgen, id ); 
    SetIsAutomorphismGroup( aut, true ); 
    SetIsFinite( aut, true ); 
    SetIsAutomorphismGroupOfGroupoid( aut, true ); 
    SetAutomorphismGroup( gpd, aut );
    SetAutomorphismDomain( aut, gpd );
    Info( InfoGroupoids, 2, "nice object not yet coded in this case" ); 
    return aut; 
end ); 

InstallMethod( AutomorphismGroupOfGroupoid, "for a single piece groupoid", 
    true, [ IsGroupoid and IsSinglePieceDomain ], 0,
function( gpd ) 

    local autgen, nautgen, rgp, genrgp, agp, genagp, a, obs, n, imobs, 
          L, ok, id, ids, cids, i, c, aut, niceob, nicemap, rgh, ioo, ior;  

    Info( InfoGroupoids, 2, 
          "AutomorphismGroupOfGroupoid for single piece groupoids" ); 
    ##  first: automorphisms of the root group 
    autgen := [ ]; 
    rgp := gpd!.magma; 
    genrgp := GeneratorsOfGroup( rgp ); 
    agp := AutomorphismGroup( rgp ); 
    genagp := SmallGeneratingSet( agp ); 
    for a in genagp do  
        Add( autgen, GroupoidAutomorphismByGroupAutoNC( gpd, a ) );  
    od; 
    ##  second: permutations of the objects 
    obs := gpd!.objects; 
    n := Length( obs );
    if ( n = 2 ) then 
        imobs := [ obs[2], obs[1] ]; 
        Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) );
    else 
        L := [2..n]; 
        Append( L, [1] ); 
        imobs := List( L, i -> obs[i] ); 
        Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) );
        imobs := ShallowCopy( obs ); 
        imobs[1] := obs[2]; 
        imobs[2] := obs[1]; 
        Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) );
    fi; 
    ##  third: add in the ray prods 
    ids := List( obs, o -> One( rgp ) ); 
    for i in [2..n] do 
        for c in genrgp do 
            cids := ShallowCopy( ids ); 
            cids[i] := c; 
            Add( autgen, GroupoidAutomorphismByRayShifts( gpd, cids ) ); 
        od; 
    od; 
    nautgen := Length( autgen ); 
    ##  generating set for the automorphism group now complete 
    for a in autgen do 
        ok := IsAutomorphismWithObjects( a ); 
    od; 
    id := IdentityMapping( gpd ); 
    ## imobs := L[0]; 
    aut := GroupWithGenerators( autgen, id ); 
    SetIsAutomorphismGroup( aut, true ); 
    SetIsFinite( aut, true ); 
    SetIsAutomorphismGroupOfGroupoid( aut, true );
    niceob := NiceObjectAutoGroupGroupoid( gpd, aut ); 
    SetNiceObject( aut, niceob[1] ); 
    SetEmbeddingsInNiceObject( aut, niceob[2] ); 
    #?  SetInnerAutomorphismsAutomorphismGroup( aut, ?? ); 
    SetAutomorphismGroup( gpd, aut );
    SetAutomorphismDomain( aut, gpd );

    ## now construct nicemap using GroupHomomorphismByFunction 
    nicemap := GroupHomomorphismByFunction( aut, niceob[1], 
        function( alpha ) 
            local G, autG, q, eno, obG, nobG, oha, j, ioa, Lpos, Lmap; 
            G := Source( alpha ); 
            autG := AutomorphismGroup( G ); 
            q := One( NiceObject( autG ) );
            eno := EmbeddingsInNiceObject( autG ); 
            obG := ObjectList( G ); 
            nobG := Length( obG ); 
            rgh := RootGroupHomomorphism( alpha ); 
            q := ImageElm( eno[1], rgh ); 
            ior := ImageElementsOfRays( alpha ); 
            for j in [1..nobG] do 
                q := q * ImageElm( eno[j+2], ior[j] ); 
            od;
            ioo := ImagesOfObjects( alpha ); 
            Lpos := List( ioo, j -> Position( obG, j ) ); 
            Lmap := MappingPermListList( [1..nobG], Lpos ); 
            q := q * ImageElm( eno[2], Lmap ); 
            return q;             
        end); 

    SetIsInjective( nicemap, true );
    SetNiceMonomorphism( aut, nicemap ); 
    ## SetIsHandledByNiceMonomorphism( aut, true ); 
    SetIsCommutative( aut, IsCommutative( niceob[1] ) );
    if HasName( gpd ) then 
        SetName( aut, Concatenation( "Aut(", Name( gpd ), ")" ) ); 
    fi;
    return aut; 
end ); 

InstallMethod( AutomorphismGroupOfGroupoid, "for a hom. discrete groupoid", 
    true, [ IsHomogeneousDiscreteGroupoid ], 0,
function( gpd ) 

    local pieces, autgen, nautgen, p1, g1, ag1, id1, genag1, a, b, auts, 
          obs, n, imobs, L, ok, id, ids, aut, niceob, nicemap;  

    Info( InfoGroupoids, 2, 
          "AutomorphismGroupOfGroupoid for homogeneous discrete groupoids" ); 
    pieces := Pieces( gpd ); 
    obs := ObjectList( gpd ); 
    n := Length( obs );
    ##  first: automorphisms of the first object group 
    autgen := [ ]; 
    p1 := pieces[1]; 
    g1 := p1!.magma; 
    ag1 := AutomorphismGroup( g1 ); 
    id1 := IdentityMapping( g1 ); 
    auts := ListWithIdenticalEntries( n, id1 ); 
    genag1 := SmallGeneratingSet( ag1 ); 
    for a in genag1 do 
        auts[1] := a; 
        b := GroupoidAutomorphismByGroupAutos( gpd, auts ); 
        SetIsGroupWithObjectsHomomorphism( b, true ); 
        Add( autgen, b );  
    od; 
    ##  second: permutations of the objects 
    if ( n = 2 ) then 
        imobs := [ obs[2], obs[1] ]; 
        Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) );
    else 
        L := [2..n]; 
        Append( L, [1] ); 
        imobs := List( L, i -> obs[i] ); 
        Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) );
        imobs := ShallowCopy( obs ); 
        imobs[1] := obs[2]; 
        imobs[2] := obs[1]; 
        Add( autgen, GroupoidAutomorphismByObjectPerm( gpd, imobs ) );
    fi; 
    ##  generating set for the automorphism group now complete 
    nautgen := Length( autgen ); 
    for a in autgen do 
        ok := IsAutomorphismWithObjects( a ); 
    od; 
    id := IdentityMapping( gpd ); 
    ## imobs := L[0];
    aut := GroupWithGenerators( autgen, id ); 
    SetIsAutomorphismGroup( aut, true ); 
    SetIsFinite( aut, true ); 
    SetIsAutomorphismGroupOfGroupoid( aut, true );
    niceob := NiceObjectAutoGroupGroupoid( gpd, aut ); 
    SetNiceObject( aut, niceob[1] ); 
    SetEmbeddingsInNiceObject( aut, niceob[3] ); 
    SetAutomorphismGroup( gpd, aut ); 
    SetAutomorphismDomain( aut, gpd );

    ## now construct nicemap using GroupHomomorphismByFunction 
    nicemap := GroupHomomorphismByFunction( aut, niceob[1], 
        function( alpha ) 
            local G, autG, q, eno, obG, nobG, oha, j, ioa, Lpos, Lmap; 
            G := Source( alpha ); 
            autG := AutomorphismGroup( G ); 
            q := One( NiceObject( autG ) );
            eno := EmbeddingsInNiceObject( autG ); 
            obG := ObjectList( G ); 
            nobG := Length( obG ); 
            oha := ObjectHomomorphisms( alpha ); 
            for j in [1..nobG] do 
                q := q * ImageElm( eno[j+1], oha[j] ); 
            od;
            ioa := ImagesOfObjects( alpha ); 
            Lpos := List( ioa, j -> Position( obG, j ) ); 
            Lmap := MappingPermListList( Lpos, [1..nobG] ); 
            q := q * ImageElm( eno[1], Lmap ); 
            return q;             
        end); 

    SetIsInjective( nicemap, true );
    SetNiceMonomorphism( aut, nicemap ); 
    ## SetIsHandledByNiceMonomorphism( aut, true ); 
    #?  SetInnerAutomorphismsAutomorphismGroup( aut, ?? );  
    SetIsCommutative( aut, IsCommutative( niceob[1] ) );
    if HasName( gpd ) then 
        SetName( aut, Concatenation( "Aut(", Name( gpd ), ")" ) ); 
    fi;
    return aut; 
end ); 

InstallMethod( AutomorphismGroupOfGroupoid, "for an arbitrary groupoid", 
    true, [ IsGroupoid ], 0,
function( gpd ) 
    Info( InfoGroupoids, 1, 
          "use AutomorphismGroupoidOfGroupoid for a union of pieces" ); 
    return fail; 
end ); 

## ========================================================================
##                     Homogeneous groupoid automorphisms                  
## ======================================================================== ##

## ????? more work to be done here 

InstallMethod( \in,
    "method for an automorphism of a single object groupoid", true,
    [ IsGroupWithObjectsHomomorphism, IsGroup ], 
    0,
function( a0, agp )

    local gens, src, obs, rng, mgi, rgp, argp;

    gens := GeneratorsOfGroup( agp ); 
    if not ForAll( gens, g -> IsGroupoidHomomorphism(g) 
                              and IsAutomorphismWithObjects(g) ) then 
        return false; 
    fi; 
    src := Source( a0 ); 
    obs := ObjectList( src ); 
    if ( Length( obs ) = 1 ) then 
        rng := Range( a0 ); 
        if not ( src = rng ) then 
            return false; 
        fi; 
        mgi := MappingGeneratorsImages( a0 ); 
        rgp := RootGroup( src ); 
        argp := AutomorphismGroup( rgp ); 
        return ForAll( mgi, g -> g in argp ); 
    else 
        Error( "method not yet implemented" ); 
    fi;
end ); 

InstallMethod( \in,
    "method for an automorphism of a single piece groupoid", true,
    [ IsGroupWithObjectsHomomorphism, IsAutomorphismGroupOfGroupoid ], 
    0,
function( a, aut )

    local gpd, gp, data;

    gpd := AutomorphismDomain( aut ); 
    gp := gpd!.magma; 
    data := MappingToSinglePieceData( a )[1];
    if not ( data[1] in AutomorphismGroup( gp ) ) then 
        return false; 
    fi; 
    if not ForAll( data[2], o -> o in ObjectList( gpd ) ) then 
        return false; 
    fi; 
    if not ForAll( data[3], e -> e in gp ) then 
        return false; 
    fi;
    return true; 
end ); 

InstallMethod( \in,
    "for groupoid hom and automorphism group : discrete", true, 
    [ IsGroupoidHomomorphismFromHomogeneousDiscrete and IsGroupoidHomomorphism,
      IsAutomorphismGroupOfGroupoid ], 0, 
function( a, aut ) 

    local gens, g1, gpd, obs, imobs, G, AG; 

    gens := GeneratorsOfGroup( aut ); 
    gpd := AutomorphismDomain( aut ); 
    if not ( ( Source(a) = gpd ) and ( Range(a) = gpd ) ) then 
        Info( InfoGroupoids, 2, "require Source(a) = Range(a) = gpd" ); 
        return false; 
    fi; 
    obs := ObjectList( gpd );
    imobs := ShallowCopy( ImagesOfObjects( a ) ); 
    Sort( imobs ); 
    if not ( obs = imobs ) then 
        Info( InfoGroupoids, 2, "incorrect images of objects" ); 
        return false;  
    fi; 
    G := Source(a)!.magma; 
    AG := AutomorphismGroup( G ); 
    if not ForAll( ObjectHomomorphisms(a), h -> h in AG ) then 
        Info( InfoGroupoids, 2, "object homomorphisms incorrect" ); 
        return false; 
    fi; 
    #? is there anything else to test? 
    return true; 
end ); 

############################################################################## 
##  methods added 11/09/18 for automorphisms of homogeneous groupoids 

InstallMethod( GroupoidAutomorphismByPiecesPermNC,  
    "for a homogeneous groupoid and a permutation of the pieces", true, 
    [ IsGroupoid and IsHomogeneousDomainWithObjects, IsPerm ], 0,
function( gpd, p )

    local pieces, n, isos, mor; 

    pieces := Pieces( gpd ); 
    n := Length( pieces ); 
    isos := List( [1..n], 
              i -> IsomorphismNewObjects( pieces[i], pieces[i^p]!.objects ) );
    mor := HomomorphismByUnion( gpd, gpd, isos );
    SetOrder( mor, Order( p ) );
    SetIsGroupoidAutomorphismByPiecesPerm( mor, true ); 
    return mor; 
end ); 

InstallMethod( GroupoidAutomorphismByPiecesPerm, 
    "for a homogeneous groupoid and a permutation of pieces", true, 
    [ IsGroupoid and IsHomogeneousDomainWithObjects, IsPerm ], 0,
function( gpd, p ) 

    local pieces, n, obs, pos; 

    pieces := Pieces( gpd ); 
    n := Length( pieces ); 
    if ( LargestMovedPoint( p ) > n ) then 
        Error( "degree of permutation too large" ); 
    fi; 
    return GroupoidAutomorphismByPiecesPermNC( gpd, p ); 
end ); 

#############################################################################
##
#M  IsomorphismClassPositionsOfGroupoid
##
InstallMethod( IsomorphismClassPositionsOfGroupoid, "for a gpd with pieces", 
    true, [ IsGroupoid ], 0,
function( gpd ) 

    local P, lenP, found, i, classes, L, j, iso;  

    P := Pieces( gpd );
    lenP := Length( P );
    found := ListWithIdenticalEntries( lenP, false ); 
    i := 0; 
    classes := [ ];
    while ( i < lenP ) do 
        i := i+1; 
        while ( ( i <= lenP ) and found[i] ) do 
            i := i + 1; 
        od;
        if ( i <= lenP ) then 
            L := [ i ]; 
            found[i] := true;
            for j in [i+1..lenP] do 
                if not found[j] then 
                    iso := IsomorphismGroupoids( P[i], P[j] ); 
                    if not ( iso = fail ) then 
                        Add( L, j );
                        found[j] := true;
                        fi;
                    fi;
                od;
            Add( classes, L );                     
        fi;
    od; 
    return classes; 
end );

#############################################################################
##
#M  AutomorphismGroupoidOfGroupoid
##
InstallMethod( AutomorphismGroupoidOfGroupoid, "for a single piece groupoid", 
    true, [ IsGroupoid and IsSinglePieceDomain ], 0,
function( gpd ) 

    local obs, A; 

    A := AutomorphismGroupOfGroupoid( gpd ); 
    obs := ObjectList( gpd );
    return MagmaWithSingleObject( A, obs ); 
end );

InstallMethod( AutomorphismGroupoidOfGroupoid, "for a homogeneous groupoid", 
    true, [ IsGroupoid and IsHomogeneousDomainWithObjects ], 0,
function( gpd ) 

    local pieces, obs, n, p1, ap1, rays, aut, niceob, nicemap;  

    Info( InfoGroupoids, 2, 
          "AutomorphismGroupoidOfGroupoid for homogeneous groupoids" ); 
    pieces := Pieces( gpd ); 
    obs := List( pieces, p -> p!.objects ); 
    n := Length( pieces );
    p1 := pieces[1]; 
    ap1 := AutomorphismGroupOfGroupoid( p1 ); 
    rays := Concatenation( [ One( ap1 ) ], 
            List( [1..n-1], i -> IsomorphismNewObjects( p1, obs[i+1] ) ) ); 
    aut := SinglePieceGroupoidWithRays( ap1, obs, rays ); 
    if HasName( gpd ) then 
        SetName( aut, Concatenation( "Aut(", Name( gpd ), ")" ) ); 
    fi;
    SetAutomorphismDomain( aut, gpd );
    return aut; 
end );

InstallMethod( AutomorphismGroupoidOfGroupoid, "for a groupoid", true, 
    [ IsGroupoid ], 0,
function( gpd ) 

    local pieces, cpos, numc, obs, comp, i, lenc, pos, pi, auti, geni, 
          lenpi, idp, isos, obsi, j, pj, isoj, invj, genj, autj, isosj; 

    pieces := Pieces( gpd ); 
    cpos := IsomorphismClassPositionsOfGroupoid( gpd ); 
    numc := Length( cpos );
    obs := List( pieces, p -> p!.objects ); 
    obs := List( cpos, K -> obs{K} ); 
    obs := List( obs, K -> Set( Flat( K ) ) ); 
    comp := ListWithIdenticalEntries( numc, 0 );
    for i in [1..numc] do 
        pos := cpos[i]; 
        lenc := Length( pos ); 
        pi := pieces[ pos[1] ]; 
        auti := AutomorphismGroupOfGroupoid( pi ); 
        if HasName( pi ) then 
            SetName( auti, Concatenation( "Aut(", Name(pi), ")" ) ); 
        fi; 
        geni := GeneratorsOfGroup( auti ); 
        lenpi := Length( pi!.objects ); 
        if ( lenc = 1 ) then 
            comp[i] := MagmaWithSingleObject( auti, pi!.objects ); 
        else 
            obsi := List( pos, k -> pieces[k]!.objects ); 
            isos := ListWithIdenticalEntries( lenpi, 0 ); 
            isos[1] := IdentityMapping( auti ); 
            for j in [2..lenc] do 
                pj := pieces[ pos[j] ]; 
                isoj := IsomorphismGroupoids( pi, pj ); 
                invj := InverseGeneralMapping( isoj ); 
                genj := List( geni, g -> invj * g * isoj ); 
                autj := Group( genj ); 
                SetAutomorphismGroupOfGroupoid( pj, autj ); 
                if HasName( pj ) then 
                    SetName( autj, Concatenation( "Aut(", Name(pj), ")" ) ); 
                fi; 
                isosj := GroupHomomorphismByImagesNC(auti,autj,geni,genj); 
                SetIsInjective( isosj, true );
                SetIsSurjective( isosj, true ); 
                isos[j] := isosj; 
            od; 
            comp[i] := GroupoidByIsomorphisms( auti, obsi, isos );
        fi;
    od; 
    return UnionOfPieces( comp ); 
end );

############################# GROUPOID ACTIONS ##############################

#############################################################################
##
#M  GroupoidActionByConjugation                        sets up the action map
##
InstallMethod( GroupoidActionByConjugation, "method for a groupoid", true,
    [ IsGroupoid and IsSinglePieceDomain ], 0,
function( gpd )

    local aut, map, act;

    aut := AutomorphismGroupOfGroupoid( gpd );
    map := function(a) return GroupoidInnerAutomorphism( gpd, a ); end;
    act := rec(); 
    ObjectifyWithAttributes( act, GroupoidActionType, 
        Source, gpd,
        Range, aut,
        ActionMap, map,
        IsGroupoidAction, true );
    return act;
end );

InstallOtherMethod( GroupoidActionByConjugation, 
    "method for a groupoid and a normal subgroupoid", true,
    [ IsGroupoid and IsSinglePieceDomain, IsGroupoid ], 0,
function( gpd, sub )

    local issing, ishomd, aut, map, act;

    issing := false;
    ishomd := false;
    if not IsWideSubgroupoid( gpd, sub ) then 
        Error( "sub is not a subgroupoid of gpd" ); 
    fi;
    if IsSinglePiece( sub ) then
        issing := true;
    elif IsHomogeneousDomainWithObjects( sub ) then
        ishomd := true;
    else
        Error( "invalid subgroupoid sub" );
    fi;
    aut := AutomorphismGroupOfGroupoid( sub );
    map := function(a) 
               return GroupoidInnerAutomorphismNormalSubgroupoid(gpd,sub,a);
           end;
    act := rec(); 
    ObjectifyWithAttributes( act, GroupoidActionType, 
        Source, gpd,
        Range, aut,
        ActionMap, map,
        IsGroupoidAction, true );
    return act;
end );

[ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ]