Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  gpd.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

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

#############################################################################
##  Standard error messages

GPD_CONSTRUCTORS := Concatenation( 
    "The standard operations which construct a groupoid are:\n",
    "1.  SinglePieceGroupoid( object group, list of objects );\n",
    "2.  MagmaWithSingleObject( group, single object );\n",
    "3.  UnionOfPieces( list of groupoids );\n",
    "4.  SinglePieceSubgroupoidByGenerators( list of elements );\n", 
    "5.  SubgroupoidWithRays( parent gpd, root gp, ray mults. );\n", 
    "6.  Groupoid( one of the previous parameter options );" );
##  these are called by the GlobalFunction Groupoid 

SUB_CONSTRUCTORS := Concatenation( 
    "The standard operations which construct a subgroupoid are:\n", 
    "1.  SubgroupoidByObjects( groupoid, list of objects );\n", 
    "2.  SubgroupoidBySubgroup( groupoid, group );\n", 
    "3.  SubgroupoidWithRays( groupoid, root group, rays );\n", 
    "4.  SubgroupoidByPieces( groupoid, list of [imobs,hom] pairs );\n",
    "5.  FullTrivialSubgroupoid( groupoid );\n", 
    "6.  DiscreteTrivialSubgroupoid( groupoid );\n", 
    "7.  DiscreteSubgroupoid( groupoid, list of subgps, list of obs );\n",
    "8.  HomogerneousDiscreteSubgroupoid( groupoid, group, list of obs );\n",
    "9.  MaximalDiscreteSubgroupoid( groupoid );\n", 
    "10. Subgroupoid( one of the previous parameter options );" );
##  and these are all called by the GlobalFunction Subgroupoid 

#############################################################################
##
#M  SinglePieceGroupoidNC                                            
#M  SinglePieceGroupoid                                            
##
InstallMethod( SinglePieceGroupoidNC, "method for a connected groupoid",
    true, [ IsGroup, IsHomogeneousList ], 0,
function( gp, obs ) 

    local gpd, gens;

    gpd := rec( objects := obs, magma := gp, 
                rays := List( obs, o -> One( gp ) ) ); 
    ObjectifyWithAttributes( gpd, IsGroupoidType, 
        IsSinglePieceDomain, true,
        IsAssociative, true, 
        IsCommutative, IsCommutative( gp ), 
        IsDirectProductWithCompleteDigraphDomain, true ); 
    gens := GeneratorsOfMagmaWithObjects( gpd ); 
    SetIsDiscreteDomainWithObjects( gpd, Length(obs) = 1 );
    return gpd; 
end );

InstallMethod( SinglePieceGroupoid, "method for a connected groupoid",
    true, [ IsGroup, IsHomogeneousList ], 0,
function( gp, obs ) 
    if not IsSet( obs ) then 
        Sort( obs ); 
    fi; 
    if not IsDuplicateFree( obs ) then
        Error( "objects must be distinct," );
    fi; 
    return SinglePieceGroupoidNC( gp, obs );
end ); 

#############################################################################
##
#M  GroupoidByIsomorphisms
##
InstallMethod( GroupoidByIsomorphisms, 
    "generic method for a group, a set of objects, and a set of isos", true, 
    [ IsGroup, IsHomogeneousList, IsList ], 0,
function( rgp, obs, isos )

    local fam, gpd, gps, i, iso, inv;

    if not ( Length( obs ) = Length( isos ) ) then 
        Error( "obs and isos should have the same length" ); 
    fi; 
    fam := IsGroupoidFamily;
    gpd := rec( objects := obs, magma := rgp, isomorphisms := isos ); 
    ObjectifyWithAttributes( gpd, IsSinglePieceRaysType, 
        IsDirectProductWithCompleteDigraph, false, 
        IsSinglePieceDomain, true, 
        IsGroupoidByIsomorphisms, true ); 
    gps := ShallowCopy( obs ); 
    gps[1] := rgp; 
    for i in [1..Length(obs)] do 
        iso := isos[i]; 
        if not ( IsGroupHomomorphism( iso ) and IsBijective( iso ) ) 
           and not ( IsGroupoidHomomorphism(iso) and IsBijective(iso) ) then 
            Error( "expecting the isos to be group or groupoid isomorphisms" ); 
        fi; 
        gps[i] := Image( iso );
        inv := InverseGeneralMapping( iso ); 
    od; 
    SetObjectGroups( gpd, gps ); 
    gpd!.rays := List( gps, g -> [ One(rgp), One(g) ] );
    return gpd; 
end );



#############################################################################
##
#M  SubgroupoidWithRays
#M  SubgroupoidWithRaysNC 
##
InstallMethod( SubgroupoidWithRaysNC, 
    "generic method for a connected gpd with variable object gps", true, 
    [ IsGroupoid, IsGroup, IsHomogeneousList ], 0,
function( pgpd, rgp, rays )

    local obs, rob, fam, filter, gpd, id;

    Info( InfoGroupoids, 2, "calling SubgroupoidWithRaysNC" );
    fam := IsGroupoidFamily;
    ## filter := IsSinglePieceRaysRep; 
    gpd := rec( objects := pgpd!.objects, magma := rgp, rays := rays ); 
    ObjectifyWithAttributes( gpd, IsSinglePieceRaysType, 
        IsSinglePieceDomain, true, 
        LargerDirectProductGroupoid, pgpd ); 
    SetRaysOfGroupoid( gpd, rays );
    SetParent( gpd, pgpd );
    id := One( pgpd!.magma ); 
    SetIsDirectProductWithCompleteDigraphDomain( gpd, 
        ForAll( rays, r -> r = id ) );
    return gpd; 
end );

InstallMethod( SubgroupoidWithRays, 
    "generic method for a connected gpd with variable object gps", true, 
    [ IsGroupoid and IsSinglePiece, IsGroup, IsHomogeneousList ], 0,
function( gpd, rgp, rays )

    local obs, gp, par, grays;

    Info( InfoGroupoids, 2, "calling SubgroupoidWithRays" );
    obs := gpd!.objects; 
    if not ( Length( obs ) = Length( rays ) ) then 
        Error( "should be 1 ray element for each object in the groupoid," ); 
    fi; 
    if not IsSubgroup( gpd!.magma, rgp ) then
        Error( "subgroupoid root group not a subgroup of the root group," );
    fi;
    grays := RaysOfGroupoid( gpd ); 
    gp := gpd!.magma; 
    if not ( rays[1] = One( rgp ) ) then
        Error( "first ray element is not the identity element," );
    fi;
    if not ForAll( [2..Length(obs)], 
                   i -> rays[i] * grays[i]^-1 in gp ) then 
        Error( "not all the rays are in the corresponding homsets," );
    fi; 
    if HasLargerDirectProductGroupoid( gpd ) then   ## for RaysRep 
        par := LargerDirectProductGroupoid( gpd ); 
    else 
        par := gpd; 
    fi;
    return SubgroupoidWithRaysNC( par, rgp, rays );
end );

#############################################################################
##
#M  SinglePieceSubgroupoidByGenerators
##
InstallMethod( SinglePieceSubgroupoidByGenerators, "for a list of elements",
    true, [ IsGroupoid, IsList ], 0,
function( anc, gens ) 

    local ok, ngens, lpos, loops, ro, go, found, obs, nobs, i, gp, rpos, 
          g, c, p, q, r, rays, par; 

    Info( InfoGroupoids, 2, "calling SinglePieceSubgroupoidByGenerators" );
    ok := ForAll( gens, g -> ( FamilyObj(g) = IsGroupoidElementFamily ) ); 
    if not ok then 
        Error( "list supplied is not a list of groupoid elements," ); 
    fi;  
    ngens := Length( gens );
    loops := ListWithIdenticalEntries( ngens, false ); 
    obs := ListWithIdenticalEntries( ngens + ngens, 0 );
    lpos := [ ]; 
    for i in [1..ngens] do 
        obs[i] := gens[i]![3]; 
        obs[ngens+i] := gens[i]![4]; 
        if ( gens[i]![3] = gens[i]![4] ) then 
            loops[i] := true; 
            Add( lpos, i ); 
        fi; 
    od; 
    obs := Set( obs ); 
    ro := obs[1]; 
    nobs := Length( obs ); 
    if ( lpos = [ ] ) then 
        Error( "case with no loops not yet implemented," ); 
    fi; 
    go := gens[ lpos[1] ]![3]; 
    for i in lpos do 
        if ( go <> gens[i]![3] ) then 
            Error( "loop at more than one object not yet implemented," ); 
        fi; 
    od; 
    gp := Group( List( lpos, j -> gens[j]![2] ) ); 
    if not ( ngens - Length( lpos ) - nobs + 1 = 0 ) then 
        Error( "only case (group generators) + (rays) implemented," ); 
    fi; 
    ## find positions of the rays 
    rpos := ListWithIdenticalEntries( nobs, 0 );
    for i in [1..ngens] do 
        if not loops[i] then 
            g := gens[i]; 
            c := g![2]; 
            p := g![3]; 
            q := g![4]; 
            if ( p = go ) then 
                rpos[ Position( obs, q ) ] := i; 
            else 
                Error( "this case not yet implemented," ); 
            fi;
        fi; 
     od; 
    if ( rpos[1] = 0 ) then 
        rpos[1] := lpos[1]; 
        rays := List( rpos, i -> gens[i]![2] ); 
        rays[1] := One( gp ); 
    else 
        ## move the group object to the root object 
        gp := gp^(gens[rpos[1]]![2]); 
        rays := ListWithIdenticalEntries( nobs, 0 ); 
        rays[1] := One( gp ); 
        r := (gens[ rpos[1] ]![2])^-1; 
        for i in [2..nobs] do 
            if ( rpos[i] = 0 ) then 
                rays[i] := r; 
            else 
                rays[i] := r * gens[ rpos[i] ]![2]; 
            fi;  
        od; 
    fi; 
    par := SubgroupoidByObjects( anc, obs ); 
    return SubgroupoidWithRays( par, gp, rays ); 
end );

#############################################################################
##
#M  SinglePieceGroupoidWithRaysNC                                            
#M  SinglePieceGroupoidWithRays                                            
##
InstallMethod( SinglePieceGroupoidWithRaysNC, 
    "method for a connected groupoid", true,
    [ IsGroup, IsHomogeneousList, IsHomogeneousList ], 0,
function( gp, obs, rays ) 

    local gpd, gens1, gens;

    Info( InfoGroupoids, 2, "calling SinglePieceGroupoidWithRaysNC" );
    gpd := rec( objects := obs, magma := gp, rays := rays ); 
    ObjectifyWithAttributes( gpd, IsSinglePieceRaysType, 
        IsSinglePieceDomain, true,
        IsAssociative, true, 
        IsCommutative, IsCommutative( gp ), 
        IsSinglePieceGroupoidWithRays, true, 
        IsDirectProductWithCompleteDigraphDomain, false ); 
    gens := GeneratorsOfMagmaWithObjects( gpd ); 
    return gpd; 
end );

InstallMethod( SinglePieceGroupoidWithRays, 
    "method for a connected groupoid", true,
    [ IsGroup, IsHomogeneousList, IsHomogeneousList ], 0,
function( gp, obs, rays ) 
    Info( InfoGroupoids, 2, "calling SinglePieceGroupoidWithRays" );
    if not IsSet( obs ) then 
        Sort( obs ); 
    fi; 
    if not IsDuplicateFree( obs ) then
        Error( "objects must be distinct," );
    fi; 
    if not ( Length( obs ) = Length( rays ) ) then 
        Error( "obs and rays should have the same length" ); 
    fi;
    #?  how detailed should tests on the rays be? 
    if ( One( gp ) * rays[1] = fail ) then 
        Error( "cannot compose One(gp) with the first ray" ); 
    fi;
    return SinglePieceGroupoidWithRaysNC( gp, obs, rays );
end ); 

#############################################################################
##
#M  RootGroup
##
InstallMethod( RootGroup, "for a connected groupoid",
    true, [ IsGroupoid and IsSinglePiece ], 0,
function( G )
    return G!.magma; 
end );

#############################################################################
##
#M  RaysOfGroupoid
#M  RayArrowsOfGroupoid
##
InstallMethod( RaysOfGroupoid, "for a connected groupoid",
    true, [ IsGroupoid and IsSinglePiece ], 0,
function( G ) 
    return G!.rays; 
end );

InstallMethod( RaysOfGroupoid, "for a groupoid", true, [ IsGroupoid ], 0,
function( G ) 
    return List( Pieces( G ), RaysOfGroupoid ); 
end ); 

InstallMethod( RayArrowsOfGroupoid, "for a connected groupoid",
    true, [ IsGroupoid and IsSinglePiece ], 0,
function( gpd ) 
    local obs, root, elts; 
    obs := ObjectList( gpd ); 
    root := obs[1]; 
    elts := RaysOfGroupoid( gpd ); 
    return List( [1..Length(obs)], 
                 i -> ArrowNC( gpd, true, elts[i], root, obs[i] ) );
end );

InstallMethod( RayArrowsOfGroupoid, "for a groupoid", true, 
    [ IsGroupoid ], 0,
function( G ) 
    return List( Pieces( G ), RayArrowsOfGroupoid ); 
end ); 

#############################################################################
##
#M  Pieces 
##
InstallMethod( Pieces, "for a homogeneous, discrete groupoid",
    true, [ IsHomogeneousDiscreteGroupoid ], 0,
function( gpd ) 
    return List( gpd!.objects, 
                 o -> MagmaWithSingleObject( gpd!.magma, o ) );
end );

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

    local obs, nobs, o1, m, mgens, id, gens1, gens2, gens, rays; 

    obs := gpd!.objects;
    nobs := Length( obs );
    o1 := obs[1];
    m := gpd!.magma; 
    mgens := GeneratorsOfGroup( m ); 
    id := One( m ); 
    if ( HasIsGroupoidByIsomorphisms( gpd ) 
         and IsGroupoidByIsomorphisms( gpd ) ) then 
        gens1 := List( mgens, g -> ArrowNC( gpd, true, [ g, g ], o1, o1 ) ); 
    else 
        gens1 := List( mgens, g -> ArrowNC( gpd, true, g, o1, o1 ) ); 
    fi;
    if ( HasIsDirectProductWithCompleteDigraph( gpd ) 
        and IsDirectProductWithCompleteDigraph( gpd ) ) then 
        gens2 := List( obs{[2..nobs]}, o -> GroupoidElement(gpd,id,o1,o) ); 
    elif IsSinglePieceRaysRep( gpd ) then 
        rays := gpd!.rays; 
        gens2 := List( [2..nobs], 
                       i -> ArrowNC( gpd, true, rays[i], o1, obs[i] ) ); 
    fi; 
    gens := Immutable( Concatenation( gens1, gens2 ) ); 
    SetGeneratorsOfGroupoid( gpd, gens );
    return gens; 
end );

InstallMethod( GeneratorsOfGroupoid, "for a groupoid", true, [ IsGroupoid ], 0,
function( gpd ) 
    return Flat( List( Pieces( gpd ), GeneratorsOfGroupoid ) ); 
end );

#############################################################################
##
#M  IsPermGroupoid
#M  IsFpGroupoid
#M  IsPcGroupoid
#M  IsMatrixGroupoid
##
InstallMethod( IsPermGroupoid, "for a groupoid", true,
    [ IsGroupoid ], 0,
function( gpd ) 
    if IsSinglePiece( gpd ) then 
        return ( IsPermCollection(gpd!.magma) and IsPermGroup(gpd!.magma) ); 
    else 
        return ForAll( Pieces(gpd), IsPermGroupoid ); 
    fi; 
end );

InstallMethod( IsFpGroupoid, "for a groupoid", true,
    [ IsGroupoid ], 0,
function( gpd )
    if IsSinglePiece( gpd ) then 
        return ( IsGroupOfFamily(gpd!.magma) and IsFpGroup(gpd!.magma) ); 
    else 
        return ForAll( Pieces(gpd), IsFpGroupoid );   
    fi; 
end );

InstallMethod( IsPcGroupoid, "for a groupoid", true,
    [ IsGroupoid ], 0,
function( gpd )
    if IsSinglePiece( gpd ) then 
        return ( HasIsPolycyclicGroup( gpd!.magma )
                 and IsPolycyclicGroup( gpd!.magma ) ); 
    else 
        return ForAll( Pieces(gpd), IsPcGroupoid );   
    fi; 
end ); 

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

    local gens; 

    if IsSinglePiece( gpd ) then 
        gens := GeneratorsOfGroup( gpd!.magma ); 
        return ForAll( gens, g ->  HasIsRectangularTable( g )
                                  and IsRectangularTable( g ) ); 
    else 
        return ForAll( Pieces(gpd), IsMatrixGroupoid );   
    fi; 
end ); 

InstallMethod( IsFreeGroupoid, "for a groupoid", true,
    [ IsGroupoid ], 0,
function( gpd )
    if IsSinglePiece( gpd ) then 
        return IsFreeGroup( gpd!.magma ); 
    else 
        return ForAll( Pieces(gpd), IsFreeGroupoid );   
    fi; 
end ); 

#############################################################################
##
#F  Groupoid( <pieces> )                groupoid as list of pieces 
#F  Groupoid( <gp>, <obj> )             group as groupoid 
#F  Groupoid( <gp>, <obs> )             single piece groupoid 
#F  Groupoid( <gpd>, <rgp>, <rays> )    subgroupoid by root group and rays 
##
InstallGlobalFunction( Groupoid, function( arg )

    local nargs, id, rays;

    nargs := Length( arg ); 
    # list of pieces
    if ( ( nargs = 1 ) and IsList( arg[1] ) 
         and  ForAll( arg[1], IsGroupoid ) ) then
        Info( InfoGroupoids, 2, "ByUnion" );
        return UnionOfPieces( arg[1] );
    # group * tree groupoid
    elif ( ( nargs = 2 ) and IsList( arg[2] ) and IsGroup( arg[1] ) ) then
        Info( InfoGroupoids, 2, "group plus objects" ); 
        return SinglePieceGroupoid( arg[1], arg[2] );
    # one-object groupoid
    elif ( ( nargs = 2 ) and IsObject( arg[2] ) and IsGroup( arg[1] ) ) then
        Info( InfoGroupoids, 2, "SingleObject" );
        return MagmaWithSingleObject( arg[1], arg[2] );
    elif ( ( nargs = 3 ) and IsGroupoid( arg[1] ) and IsGroup( arg[2] ) 
           and IsHomogeneousList( arg[3] ) ) then 
        return SubgroupoidWithRays( arg[1], arg[2], arg[3] );
    else
        Info( InfoGroupoids, 1, GPD_CONSTRUCTORS );
        return fail;
    fi;
end );

#############################################################################
##
#M  String, ViewString, PrintString, ViewObj, PrintObj
##
InstallMethod( String, "for a groupoid", true, [ IsGroupoid ], 0, 
function( gpd ) 
    if IsSinglePiece( gpd ) then 
        return( STRINGIFY( "single piece groupoid with ", 
                           String(Length(ObjectList(gpd))), " objects") ); 
    else 
        return( STRINGIFY( "groupoid with ", 
                           String(Length(Pieces(gpd))), " pieces" ) );
    fi;
end );

InstallMethod( ViewString, "for a groupoid", true, [ IsGroupoid ], 0, String ); 

InstallMethod( PrintString, "for a groupoid", true, [ IsGroupoid ], 0, String ); 

InstallMethod( ViewObj, "for a groupoid", true, [ IsGroupoid ], 0, PrintObj ); 

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

    local comp, len, c, i;

    if ( HasIsPermGroupoid( gpd ) and IsPermGroupoid( gpd ) ) then
        Print( "perm " );
    elif ( HasIsFpGroupoid( gpd ) and IsFpGroupoid( gpd ) ) then 
        Print( "fp " );
    elif ( HasIsPcGroupoid( gpd ) and IsPcGroupoid( gpd ) ) then
        Print( "pc " );
    fi; 
    if IsSinglePiece( gpd ) then  
        if IsDirectProductWithCompleteDigraph( gpd ) then 
            Print( "single piece groupoid: < " ); 
            Print( gpd!.magma, ", ", gpd!.objects, " >" );
        else 
            Print( "single piece groupoid with rays: < " ); 
            Print( gpd!.magma, ", ", gpd!.objects, ", ", 
                                     gpd!.rays, " >" );
        fi; 
    elif ( HasIsHomogeneousDiscreteGroupoid( gpd ) 
           and IsHomogeneousDiscreteGroupoid( gpd ) ) then 
            Print( "homogeneous, discrete groupoid: < ",
                   gpd!.magma, ", ", gpd!.objects, " >" ); 
    else 
        comp := Pieces( gpd ); 
        len := Length( comp ); 
        if ( HasIsHomogeneousDomainWithObjects( gpd ) 
             and IsHomogeneousDomainWithObjects( gpd ) ) then 
            Print( "homogeneous " ); 
        fi; 
        Print( "groupoid with ", len, " pieces:\n" ); 
        if ForAll( comp, HasName ) then 
            Print( comp ); 
        else 
            for i in [1..len-1] do
                c := comp[i]; 
                Print( i, ":  ", c, "\n" );
            od; 
            Print( len, ":  ", comp[len] ); 
        fi;  
    fi;
end );

##############################################################################
##
#M  Display( <gpd> ) . . . . . . . . . . . . . . . . . . .  display a groupoid
##
InstallMethod( Display, "for a groupoid", [ IsGroupoid ],
function( gpd )
    
    local comp, c, i, pgpd, gp, len, rgp, rays;

    if ( HasIsPermGroupoid( gpd ) and IsPermGroupoid( gpd ) ) then
        Print( "perm " );
    elif ( HasIsFpGroupoid( gpd ) and IsFpGroupoid( gpd ) ) then
        Print( "fp " );
    elif ( HasIsPcGroupoid( gpd ) and IsPcGroupoid( gpd ) ) then
        Print( "pc " );
    fi;
    if IsSinglePiece( gpd ) then 
        if IsDirectProductWithCompleteDigraph( gpd ) then 
            Print( "single piece groupoid: " );
            if HasName( gpd ) then
                Print( gpd );
            fi;
            Print( "\n" ); 
            Print( "  objects: ", gpd!.objects, "\n" );
            gp := gpd!.magma;
            Print( "    group: " );
            if HasName( gp ) then
                Print( gp, " = <", GeneratorsOfGroup( gp ), ">\n" );
            else
                Print( gp, "\n" );
            fi; 
        elif ( HasIsGroupoidByIsomorphisms( gpd ) 
               and IsGroupoidByIsomorphisms( gpd ) ) then 
            Print( "single piece groupoid by isomorphisms: " ); 
            if HasName( gpd ) then
                Print( gpd );
            fi;
            Print( "\n" ); 
            Print( "      objects: ", gpd!.objects, "\n" );
            rgp := gpd!.magma;
            Print( "   root group: " );
            if HasName( rgp ) then
                Print( rgp, " = <", GeneratorsOfGroup( rgp ), ">\n" );
            else
                Print( rgp, "\n" );
            fi; 
            Print( " isomorphisms: " ); 
            Perform( gpd!.isomorphisms, Display );
        else
            Print( "single piece groupoid with rays having: " );
            if HasName( gpd ) then
                Print( gpd );
            fi;
            Print( "\n" ); 
            pgpd := LargerDirectProductGroupoid( gpd );
            Print( "supergroupoid: ", pgpd, "\n" ); 
            Print( "      objects: ", gpd!.objects, "\n" );
            rgp := gpd!.magma;
            Print( "   root group: " );
            if HasName( rgp ) then
                Print( rgp, " = <", GeneratorsOfGroup( rgp ), ">\n" );
            else
                Print( rgp, "\n" );
            fi; 
            Print( "         rays: ", gpd!.rays, "\n" );
        fi; 
    elif ( HasIsHomogeneousDiscreteGroupoid( gpd ) 
           and IsHomogeneousDiscreteGroupoid( gpd ) ) then 
        Print( "homogeneous, discrete groupoid with:\n" ); 
        gp := gpd!.magma; 
        Print( "  group: " ); 
        if HasName( gp ) then
            Print( gp, " = <", GeneratorsOfGroup( gp ), "> >\n" );
        else
            Print( gp, " >\n" );
        fi; 
        Print( "objects: ", gpd!.objects, "\n" ); 
    else
        comp := Pieces( gpd );
        len := Length( comp ); 
        if ( HasIsHomogeneousDomainWithObjects( gpd ) 
             and IsHomogeneousDomainWithObjects( gpd ) ) then 
            Print( "homogeneous " ); 
        fi; 
        Print( "groupoid with ", len, " pieces:\n" );
        for i in [1..len] do
            c := comp[i];
            if IsDirectProductWithCompleteDigraph( c ) then 
                Print( "< objects: ", c!.objects, "\n" );
                gp := c!.magma;
                Print( "    group: " );
                if HasName( gp ) then
                    Print( gp, " = <", GeneratorsOfGroup( gp ), "> >\n" );
                else
                    Print( gp, " >\n" );
                fi;
            else
                Print( "<     objects: ", c!.objects, "\n" ); 
                Print( "   parent gpd: ", Parent( c ), "\n" ); 
                rgp := c!.magma; 
                Print( "   root group: " );
                if HasName( rgp ) then
                    Print( rgp, " = <", GeneratorsOfGroup( rgp ), ">\n" );
                else
                    Print( rgp, "\n" );
                fi; 
                Print( "         rays: ", c!.rays, "\n" );
            fi; 
        od;
    fi;
end );

#############################################################################
##
#M  \=( <G1>, <G2> )  . . . . . . . . . . . . test if two groupoids are equal
##
InstallMethod( \=, "for a connected groupoid", true,
    [ IsGroupoid and IsSinglePiece, IsGroupoid ], 
function ( G1, G2 )

    Info( InfoGroupoids, 2, "### method 1 for G1 = G2" ); 
    if not IsSinglePiece( G2 ) then
        return false;
    fi;
    if not ( IsDirectProductWithCompleteDigraph( G1 ) = 
             IsDirectProductWithCompleteDigraph( G2 ) ) then
        return false;
    fi;
    if IsDirectProductWithCompleteDigraph( G1 ) then
        return ( ( G1!.objects = G2!.objects ) and ( G1!.magma = G2!.magma ) ); 
    elif ( HasIsGroupoidByIsomorphisms( G1 ) 
           and IsGroupoidByIsomorphisms( G1 ) ) then 
        return ( HasIsGroupoidByIsomorphisms( G2 ) 
                 and IsGroupoidByIsomorphisms( G2 ) 
                 and ( G1!.objects = G2!.objects ) 
                 and ( ObjectGroups( G1 ) = ObjectGroups( G2 ) ) 
                 and ( G1!.isomorphisms = G2!.isomorphisms ) ); 
    elif ( IsSinglePieceRaysRep( G1 ) and IsSinglePieceRaysRep( G2 ) ) then 
        return ( ( Parent( G1 ) = Parent( G2 ) ) and 
                  ( G1!.magma = G2!.magma ) and 
                  ForAll( [1..Length(G1!.rays)], 
                      j -> G1!.rays[j] * G2!.rays[j]^-1 in G1!.magma ) ); 
    else 
        Error( "method not found for G1=G2," ); 
    fi;
end );

InstallMethod( \=, "for a groupoid", true, [ IsGroupoid, IsGroupoid ], 
function ( G1, G2 )
    local c1, c2, len, obj, i, j;

    Info( InfoGroupoids, 2, "### method 2 for G1 = G2" ); 
    c1 := Pieces( G1 );
    c2 := Pieces( G2 );
    len := Length( c1 );
    if ( ( len <> Length(c2) ) or ( ObjectList(G1) <> ObjectList(G2) ) ) then
        return false;
    fi;
    for i in [1..len] do
        obj := c1[i]!.objects[1];
        j := PieceNrOfObject( G2, obj );
        if ( c1[i] <> c2[j] ) then
            return false;
        fi;
    od;
    return true;
end );

############################################################################# 
## 
#M  ObjectGroup
## 
InstallMethod( ObjectGroup, "generic method for single piece gpd and object",
    true, [ IsGroupoid and IsSinglePiece, IsObject ], 0,
function( G, obj )

    local obs, nobs, pos, gps, i, c, rgp; 

    obs := G!.objects; 
    if not ( obj in obs ) then
        Error( "obj not an object of G," );
    fi;
    if IsDirectProductWithCompleteDigraph( G ) then 
        return G!.magma;
    fi; 
    pos := Position( obs, obj ); 
    if HasObjectGroups(G) then 
        return ObjectGroups(G)[pos];
    else 
        ## construct all the object groups 
        nobs := Length( obs ); 
        gps := ListWithIdenticalEntries( nobs, 0 ); 
        rgp := G!.magma; 
        gps[1] := rgp; 
        for i in [2..nobs] do
            c := G!.rays[i]; 
            gps[i] := rgp^c; 
        od;
        return gps[pos];
    fi;
end );

InstallMethod( ObjectGroup, "generic method for groupoid and object",
    true, [ IsGroupoid, IsObject ], 0,
function( G, obj )

    local nC, C;

    if not ( obj in ObjectList( G ) ) then
        Error( "obj not an object of G," );
    fi;
    nC := PieceNrOfObject( G, obj ); 
    C := Pieces( G )[ nC ];
    return ObjectGroup( C, obj );
end );

InstallMethod( ObjectGroup, "generic method for single piece gpd with rays",
    true, [ IsSinglePieceGroupoidWithRays, IsObject ], 0,
function( G, obj )

    local H, pieceH, obs, np, p, genp;

    ##  added 11/09/18 to deal with automorphism gpds of homogeneous gpds 
    if HasAutomorphismDomain( G ) then 
        H := AutomorphismDomain( G ); 
        pieceH := Pieces( H ); 
        obs := List( pieceH, ObjectList ); 
        if not ( obj in obs ) then
            Error( "obj not an object of G," );
        fi;
        np := Position( obs, obj ); 
        p := pieceH[ np ]; 
        if not IsGroupoid( p ) then 
            Error( "P is not a groupoid" ); 
        fi; 
        return AutomorphismGroupOfGroupoid( p ); 
    else 
        TryNextMethod(); 
    fi;
end );

############################################################################# 
## 
#M  ObjectGroups
## 
InstallMethod( ObjectGroups, "generic method for groupoid", true,
    [ IsGroupoid and IsSinglePiece ], 0,
function( gpd )
    return List( gpd!.objects, o -> ObjectGroup( gpd, o ) );
end );

InstallMethod( ObjectGroups, "generic method for groupoid", true,
    [ IsGroupoid ], 0,
function( gpd )
    return List( Pieces( gpd ), ObjectGroups );
end );


## ======================================================================== ##
##                           Homogeneous groupoids                          ##
## ======================================================================== ##

#############################################################################
##
#M  HomogeneousGroupoid
#M  HomogeneousGroupoidNC  
#M  HomogeneousDiscreteGroupoid 
##
InstallMethod( HomogeneousGroupoidNC, 
    "generic method for a connected gpd and lists of objects", true, 
    [ IsGroupoid, IsHomogeneousList ], 0,
function( gpd, oblist )

    local len, isos, inv1, pieces, hgpd, pisos; 

    
    len := Length( oblist );
    isos := List( oblist, L -> IsomorphismNewObjects( gpd, L ) ); 
    inv1 := InverseGeneralMapping( isos[1] ); 
    pieces := List( isos, ImagesSource ); 
    hgpd := UnionOfPiecesOp( pieces, pieces[1] ); 
    pisos := List( [2..len], i -> inv1 * isos[i] );
    SetIsHomogeneousDomainWithObjects( hgpd, true );
    SetIsSinglePieceDomain( hgpd, false ); 
    SetPieceIsomorphisms( hgpd, pisos );
    SetObjectList( hgpd, Set( Flat( oblist ) ) ); 
    return hgpd; 
end );

InstallMethod( HomogeneousGroupoid, 
    "generic method for a connected gpd and lists of objects", true, 
    [ IsGroupoid, IsHomogeneousList ], 0,
function( gpd, oblist )

    local len, obs, ob1, j, L; 

    if not ForAll( oblist, IsHomogeneousList ) then 
        Error( "oblist must be a list of lists," ); 
    fi; 
    obs := gpd!.objects; 
    len := Length( obs ); 
    if not ForAll( oblist, L -> ( Length(L) = len ) ) then 
        Error( "lists in list must have the same length as Objects(gpd)," ); 
    fi; 
    ob1 := oblist[1]; 
    for j in [2..Length(oblist)] do 
        if ( Intersection( ob1, oblist[j] ) <> [ ] ) then
            Info( InfoGroupoids, 1, 
                  "pieces must have disjoint object sets," );
            return fail;
        fi; 
    od; 
    for L in oblist do 
        Sort( L );
    od;
    Sort( oblist );
    return HomogeneousGroupoidNC( gpd, oblist );
end );

InstallMethod( HomogeneousDiscreteGroupoid, 
    "generic method for a group and a list of objects", true, 
    [ IsGroup, IsHomogeneousList ], 0,
function( gp, obs ) 

    local fam, filter, gpd; 

    if ( Length( obs ) = 1 ) then 
        Error( "hom discrete groupoids should have more than one object" ); 
    fi;
    fam := IsGroupoidFamily; 
    filter := IsHomogeneousDiscreteGroupoidRep; 
    gpd := rec( objects := obs, magma := gp );
    ObjectifyWithAttributes( gpd, IsHomogeneousDiscreteGroupoidType,
        IsAssociative, true, 
        IsDiscreteDomainWithObjects, true, 
        IsHomogeneousDomainWithObjects, true, 
        IsAssociative, true, 
        IsCommutative, IsCommutative( gp ), 
        IsDirectProductWithCompleteDigraphDomain, false, 
        IsSinglePieceDomain, false );
    return gpd; 
end );


## ======================================================================= ##
##                           Groupoid Elements                             ##
## ======================================================================= ##

#############################################################################
##
#M  Arrow 
##  ArrowNC
##
InstallMethod( Arrow, "generic method for a groupoid element",
    true, [ IsGroupoid, IsMultiplicativeElement, IsObject, IsObject ], 0,
function( gpd, g, i, j ) 

    local comp, obs, ok1, ok2, rays, ri, rj;

    if ( HasIsSinglePiece( gpd ) 
         and IsSinglePiece( gpd ) ) then 
        comp := gpd; 
    else 
        comp := PieceOfObject( gpd, i );
    fi; 
    obs := comp!.objects; 
    ok1 := ( ( i in obs ) and ( j in obs ) ); 
    if ( HasIsDirectProductWithCompleteDigraph( comp ) 
         and IsDirectProductWithCompleteDigraph( comp ) ) then 
        ok2 := ( g in comp!.magma ); 
    else 
        rays := comp!.rays; 
        ri := rays[ Position( obs, i ) ]; 
        rj := rays[ Position( obs, j ) ];
        ok2 := ri * g * rj^(-1) in comp!.magma; 
    fi; 
    if not ( ok1 and ok2 ) then 
        return fail;
    else
        return ArrowNC( gpd, true, g, i, j ); 
    fi;
end );

InstallOtherMethod( Arrow, "generic method for a groupoid by isomorphisms",
    true, [ IsGroupoidByIsomorphisms, IsList, IsObject, IsObject ], 0,
function( gpd, pair, o1, o2 ) 

    local obs, ok1, p1, p2, gps, g1, g2, isos, iso, rays;

    Info( InfoGroupoids, 3, "Arrow: method for groupoid by isomorphisms" ); 
    obs := gpd!.objects; 
    ok1 := ( ( o1 in obs ) and ( o2 in obs ) ); 
    if not ok1 then 
        Info( InfoGroupoids, 2, "o1, o2 not both in gpd" ); 
        return fail; 
    fi;
    p1 := Position( obs, o1 ); 
    p2 := Position( obs, o2 );
    gps := ObjectGroups( gpd ); 
    g1 := pair[1]; 
    g2 := pair[2]; 
    isos := gpd!.isomorphisms; 
    iso := InverseGeneralMapping( isos[p1] ) * isos[p2]; 
    if not ( ImageElm( iso, g1 ) = g2 ) then 
        Info( InfoGroupoids, 2, "iso(g1) <> g2" );
        return fail; 
    else 
        return ArrowNC( gpd, true, pair, o1, o2 ); 
    fi;
end );

InstallOtherMethod( ArrowNC, 
    "for mwo, boolean, pair of elements, tail and head", true,  
    [ IsGroupoidByIsomorphisms, IsBool, IsList, IsObject, IsObject ], 0,
function( gpd, isge, pair, t, h ) 

    local obs, elt, fam;

Info( InfoGroupoids, 1, "special method for ArrowNC" );
    fam := IsGroupoidElementFamily; 
    elt := Objectify( IsGroupoidByIsomorphismsElementType, 
                      [ gpd, pair, t, h ] );
    return elt; 
end ); 

#############################################################################
## 
#M  ConjugateGroupoid( <gpd>, <elt> )
## 
InstallMethod( ConjugateGroupoid, "<gpd>, <elt>", true,
    [ IsGroupoid and IsSinglePiece, IsGroupoidElement ], 0, 
function( gpd, elt )

    local gens, ims, conj;

    gens := GeneratorsOfGroupoid( gpd ); 
    ims := List( gens, g -> g^elt ); 
    conj := SinglePieceSubgroupoidByGenerators( Ancestor( gpd ), ims );
    return conj;
end );

InstallMethod( ConjugateGroupoid, "<gpd>, <elt>", true,
    [ IsGroupoid and IsPiecesRep, IsGroupoidElement ], 0, 
function( U, elt )

    local p, q, np, nq, n, pieces, gpd; 

    p := elt![3]; 
    np := PieceNrOfObject( U, p ); 
    q := elt![4]; 
    nq := PieceNrOfObject( U, q ); 
    if ( np = fail ) then 
        if ( nq = fail ) then 
            return fail; 
        else 
            n := nq; 
        fi; 
    else 
        n := np; 
        if ( ( nq <> fail ) and ( np <> nq ) ) then 
            Info( InfoGroupoids, 1, "expecting np = nq here" ); 
        fi; 
    fi; 
    pieces := ShallowCopy( Pieces( U ) );
    gpd := pieces[n]; 
    pieces[n] := ConjugateGroupoid( gpd, elt ); 
    return UnionOfPieces( pieces ); 
end ); 

#############################################################################
##
#M  <e> in <G> 
##
InstallMethod( \in, "for groupoid element and a standard groupoid", true, 
    [ IsGroupoidElement, IsGroupoid and IsSinglePiece ], 0,
function( e, gpd )

    local obs, r1, r2, rays, r;

    obs := gpd!.objects; 
    if not ( (e![3] in obs) and (e![4] in obs) ) then
        return false;
    fi; 
    if ( HasIsDirectProductWithCompleteDigraph( gpd ) 
         and IsDirectProductWithCompleteDigraph( gpd ) ) then
        return (e![2] in gpd!.magma);
    else 
        rays := RayArrowsOfGroupoid( gpd );
        r1 := rays[ Position( obs, e![3] ) ]; 
        r2 := rays[ Position( obs, e![4] ) ];
        r := r1 * e * r2^-1;
        if HasIsGroupoidByIsomorphisms( gpd )
          and IsGroupoidByIsomorphisms( gpd ) then
            return ( r![2][1] in gpd!.magma ) and (r![2][2] in gpd!.magma );
        else
            return r![2] in gpd!.magma;
        fi;
    fi; 
end );

InstallMethod( \in, "for groupoid element and a union of pieces", true, 
    [ IsGroupoidElement, IsGroupoid and HasPieces ], 0,
function( e, gpd )

    local p; 

    p := PieceOfObject( gpd, e![3] ); 
    if p = fail then 
        return false; 
    else 
        return e in p; 
    fi;
end );

#############################################################################
##
#M  PrintObj 
#M  Display
##
InstallMethod( PrintObj, "for a subset of elements of a groupoid", true, 
    [ IsHomsetCosets ], 0,
function ( hc )
        if ( hc!.type = "h" ) then 
        Print( "<homset ", hc!.tobs[1], " -> ", hc!.hobs[1],
               " with head group ", hc!.elements, ">" );
    elif ( hc!.type = "s" ) then 
        Print( "<star at ", hc!.tobs[1], 
               " with vertex group ", hc!.elements, ">" );
    elif ( hc!.type = "c" ) then 
        Print( "<costar at ", hc!.hobs[1], 
               " with vertex group ", hc!.elements, ">" );
    elif ( hc!.type = "r" ) then 
        Print( "<right coset of ", hc!.ActingDomain, 
               " with representative ", Representative( hc ),">" );
    elif ( hc!.type = "l" ) then 
        Print( "<left coset of ", hc!.ActingDomain, 
               " with representative ", Representative( hc ),">" );
    elif ( hc!.type = "d" ) then 
        Print( "<double coset of ", hc!.ActingDomain, 
               " with representative ", Representative( hc ),">" );
    else
        Print( "<object>");
    fi; 
end );

InstallMethod( Display, "for a subset of elements of a groupoid", true, 
    [ IsHomsetCosets ], 0,
function ( hc )
    
    local g; 

    if ( hc!.type = "h" ) then 
        Print( "<homset ", hc!.tobs[1], " -> ", hc!.hobs[1], 
               " with elements:\n" );
    elif ( hc!.type = "s" ) then 
        Print( "star at ", hc!.tobs[1], " with elements:\n" ); 
    elif ( hc!.type = "c" ) then 
        Print( "costar at ", hc!.hobs[1], " with elements:\n" );
    elif ( hc!.type = "r" ) then 
        Print( "<right coset of ", hc!.ActingDomain, " with elements:\n" );
    elif ( hc!.type = "l" ) then 
        Print( "<left coset of ", hc!.ActingDomain, " with elements:\n" );
    elif ( hc!.type = "d" ) then 
        Print( "<double coset of ", hc!.ActingDomain, " with elements:\n" );
    fi; 
    for g in hc do  
        Print( g, "\n" ); 
    od; 
end );

#############################################################################
##
#M  \=( <cset> ) . . . . . . . . . . . . . . . . . . . . for groupoid cosets 
##
InstallMethod( \=, "for groupoid cosets", [IsGroupoidCoset, IsGroupoidCoset], 
function( c1, c2 ) 

    local  act1, act2, sd1, sd2, rep1, rep2, type1, type2, elts1, elts2; 

    act1 := ActingDomain( c1 ); 
    act2 := ActingDomain( c2 ); 
    sd1 := SuperDomain( c1 ); 
    sd2 := SuperDomain( c2 ); 
    if not ( ( act1 = act2 ) and ( SuperDomain(c1) = SuperDomain(c2) ) ) then 
        Info( InfoGroupoids, 2, "different acting domain or super domain" ); 
        return false; 
    fi; 
    type1 := c1!.type; 
    type2 := c2!.type; 
    if not ( type1 = type2 ) then 
        Info( InfoGroupoids, 2, "different type" ); 
        return false; 
    fi; 
    rep1 := Representative( c1 ); 
    rep2 := Representative( c2 ); 
    if not ( rep1![3] = rep2![3] ) then 
        Info( InfoGroupoids, 2, "different tail" ); 
        return false; 
    fi; 
    if not ( rep1![4] = rep2![4] ) then 
        Info( InfoGroupoids, 2, "different head" ); 
        return false; 
    fi; 
    if not ( c1!.elements = c2!.elements ) then 
        Info( InfoGroupoids, 2, "different sets of elements" ); 
        return false; 
    fi;
    return true; 
end );

#############################################################################
##
#M  Size( <homsets> ) . . . . . . . . size for star, costar, homset or coset
##
InstallMethod( Size, "for a subset of a connected groupoid", 
    [ IsHomsetCosets ], 
function( hc ) 
    return Length(hc!.tobs) * Size( hc!.elements) * Length(hc!.hobs); 
end ); 

#############################################################################
##
#M  Iterator( <homsets> ) . . . . iterator for star, costar, homset or coset
##
InstallMethod( Iterator, "for a subset of a connected groupoid", 
    [ IsHomsetCosets ], 
function( hc )

    local gpd, elements, pro1, pro2;

    gpd := hc!.groupoid;
    elements := hc!.elements; 
    return IteratorByFunctions( rec( 
        groupoid := gpd,
        IsDoneIterator := function( iter )
            return ( IsDoneIterator( iter!.elementsIterator ) 
                     and ( iter!.tpos = iter!.tlen )
                     and ( iter!.hpos = iter!.hlen ) );
            end, 
        NextIterator := function( iter )
            if ( iter!.tpos = 0 ) then
                iter!.gpelt := NextIterator( iter!.elementsIterator );
                iter!.tpos := 1;
                iter!.hpos := 1;
           elif ((iter!.tpos = iter!.tlen) and (iter!.hpos = iter!.hlen)) then 
                iter!.gpelt := NextIterator( iter!.elementsIterator );
                iter!.tpos := 1;
                iter!.hpos := 1;
           elif ( iter!.hpos = iter!.hlen ) then
                iter!.hpos := 1;
                iter!.tpos := iter!.tpos + 1;
           else 
                iter!.hpos := iter!.hpos + 1;
            fi; 
            if ( hc!.type = "h" ) then 
                return ArrowNC( gpd, true, 
                           hc!.hrays[iter!.hpos]*(iter!.gpelt), 
                           iter!.tobs[iter!.tpos], iter!.hobs[iter!.hpos] );
            elif ( hc!.type = "c" ) then 
                return ArrowNC( gpd, true,
                           (hc!.hrays[iter!.tpos])*(iter!.gpelt), 
                           iter!.tobs[iter!.tpos], iter!.hobs[iter!.hpos] );
            elif ( hc!.type = "s" ) then 
                return ArrowNC( gpd, true,
                           (iter!.gpelt)*hc!.trays[iter!.hpos], 
                           iter!.tobs[iter!.tpos], iter!.hobs[iter!.hpos] );
            elif ( hc!.type = "r" ) then 
                return ArrowNC( gpd, true,
                           (hc!.trays[iter!.tpos]^-1)*(iter!.gpelt),  
                           iter!.tobs[iter!.tpos], iter!.hobs[iter!.hpos] );
            elif ( hc!.type = "l" ) then 
                return ArrowNC( gpd, true, 
                           (iter!.gpelt)*(hc!.hrays[iter!.hpos]), 
                           iter!.tobs[iter!.tpos], iter!.hobs[iter!.hpos] );
            elif ( hc!.type = "d" ) then 
                return ArrowNC( gpd, true, 
                           hc!.trays[iter!.tpos]^-1
                             * (iter!.gpelt) 
                               * hc!.hrays[iter!.hpos],  
                           iter!.tobs[iter!.tpos], iter!.hobs[iter!.hpos] );
            fi; 
        end,
        ShallowCopy := iter -> 
            rec( elementsIterator := ShallowCopy( iter!.elementsIterator ), 
                 groupoid := iter!.groupoid,
                 gpelt := iter!.gpelt,
                 tobs := iter!.tobs,
                 tlen := iter!.tlen,
                 hobs := iter!.hobs,
                 hlen := iter!.hlen,
                 tpos := iter!.tpos,
                 hpos := iter!.hpos,
                  rep := iter!.rep ),
        elementsIterator := Iterator( elements ), 
        ## fgpd := hc![2], 
        gpelt := 0,
        tobs := hc!.tobs,
        tlen := Length( hc!.tobs ),
        hobs := hc!.hobs,
        hlen := Length( hc!.hobs ),
        tpos := 0,
        hpos := 0, 
         rep := hc!.rep ) );
end );

#############################################################################
##
#M  ObjectStarNC 
#M  ObjectStar 
##
InstallMethod( ObjectStarNC, "for a connected groupoid and an object",
    true, [ IsGroupoid and IsSinglePiece, IsObject ], 0,
function( gpd, obj )

    local gp, obs, nobs, st, rays, pos, rpos;

    obs := gpd!.objects; 
    gp := ObjectGroup( gpd, obj ); 
    rays := gpd!.rays; 
    pos := Position( obs, obj ); 
    if ( pos <> 1 ) then  ## not the root object 
        rpos := rays[pos]^(-1); 
        rays := List( [1..Length(obs)], j -> rpos*rays[j] ); 
    fi; 
    st := rec( groupoid := gpd, elements := gp, tobs := [ obj ], 
               hobs := obs, trays := rays, rep := (), type := "s" );
    ObjectifyWithAttributes( st, IsHomsetCosetsType, 
        IsHomsetCosets, true ); 
    return st;
end );

InstallMethod( ObjectStar, "generic method for a groupoid and an object",
    true, [ IsGroupoid, IsObject ], 0,
function( gpd, obj )

    local comp;

    if ( IsSinglePiece(gpd) and ( obj in ObjectList(gpd) ) ) then
        return ObjectStarNC( gpd, obj );
    else
        comp := PieceOfObject( gpd, obj );
        if ( comp = fail ) then
            Info( InfoGroupoids, 1, "obj not an object in gpd" );
            return fail;
        else
            return ObjectStarNC( comp, obj );
        fi;
    fi;
end );

#############################################################################
##
#M  ObjectCostarNC 
#M  ObjectCostar 
##
InstallMethod( ObjectCostarNC, "for a connected groupoid and an object",
    true, [ IsGroupoid and IsSinglePiece, IsObject ], 0,
function( gpd, obj )

    local gp, obs, nobs, cst, rays, pos, rpos;

    obs := gpd!.objects; 
    gp := ObjectGroup( gpd, obj ); 
    rays := gpd!.rays; 
    pos := Position( obs, obj ); 
    if ( pos <> 1 ) then  ## not the root object 
        rpos := rays[pos]; 
        rays := List( [1..Length(obs)], j -> rays[j]^(-1)*rpos ); 
    fi; 
    cst := rec( groupoid := gpd, elements := gp, tobs := obs,
                hobs := [ obj ], hrays := rays, rep := (), type := "c" ); 
    ObjectifyWithAttributes( cst, IsHomsetCosetsType, 
        IsHomsetCosets, true ); 
    return cst;
end );

InstallMethod( ObjectCostar, "generic method for a groupoid and an object",
    true, [ IsGroupoid, IsObject ], 0,
function( gpd, obj )

    local comp;

    if ( IsSinglePiece(gpd) and ( obj in ObjectList(gpd) ) ) then
        return ObjectCostarNC( gpd, obj );
    else
        comp := PieceOfObject( gpd, obj );
        if ( comp = fail ) then
            Info( InfoGroupoids, 1, "obj not an object in gpd" );
            return fail;
        else
            return ObjectCostarNC( comp, obj );
        fi;
    fi;
end );

#############################################################################
##
#M  HomsetNC 
#M  Homset
##
InstallMethod( HomsetNC, "for a connected groupoid and two objects",
    true, [ IsGroupoid and IsSinglePiece, IsObject, IsObject ], 0,
function( gpd, o1, o2 )

    local obs, rob, rays, gp, p1, p2, ray, hs;
    
    obs := gpd!.objects; 
    rob := obs[1]; 
    rays := RaysOfGroupoid( gpd );
    gp := ObjectGroup( gpd, o2 ); 
    if ( o1 = o2 ) then 
        return gp; 
    fi;
    p1 := Position( obs, o1 ); 
    p2 := Position( obs, o2 );
    if ( o1 = rob ) then 
        ray := rays[p2]; 
    elif ( o2 = rob ) then 
        ray := rays[p1]^(-1); 
    else 
        ray := rays[p1]^(-1) * rays[p2]; 
    fi;
    hs := rec( groupoid := gpd, elements := gp, tobs := [ o1 ],
               hobs := [ o2 ], hrays := [ ray ], rep := (), type := "h" ); 
    ObjectifyWithAttributes( hs, IsHomsetCosetsType, 
        IsHomsetCosets, true,
        Representative, ray ); 
    return hs;
end );

InstallMethod( Homset, "generic method for a groupoid and two objects",
    true, [ IsGroupoid, IsObject, IsObject ], 0,
function( gpd, o1, o2 )

    local obs, comp;

    obs := ObjectList( gpd );
    if not ( ( o1 in obs ) and ( o2 in obs ) ) then
        Info( InfoGroupoids, 1, "o1,o2 not objects in gpd" );
        return fail;
    fi;
    if IsSinglePiece( gpd ) then
        return HomsetNC( gpd, o1, o2 );
    else
        comp := PieceOfObject( gpd, o1 );
        if not ( o2 in comp!.objects ) then
            Info( InfoGroupoids, 1, "o1,o2 not objects in same constituent" );
            return fail;
        else
            return HomsetNC( comp, o1, o2 );
        fi;
    fi;
end );

#############################################################################
##
#M  ElementsOfGroupoid
##
InstallMethod( ElementsOfGroupoid, "for a connected groupoid", true,
    [ IsGroupoid and IsSinglePiece ], 0,
function( gpd )

    local iter, elts;

    elts := [ ];
    iter := Iterator( gpd );
    while not IsDoneIterator( iter ) do
        Add( elts, NextIterator( iter ) );
    od;
    return elts;
end );

InstallMethod( ElementsOfGroupoid, "generic method for a groupoid", true,
    [ IsGroupoid ], 0,
function( gpd )

    local comps, c, elts;
    comps := Pieces( gpd );
    elts := [ ];
    for c in comps do
        Append( elts, ElementsOfGroupoid( c ) );
    od;
    return elts;
end );

#############################################################################
##
#M  Iterator( <gpd> ) . . . . . . . . . . . . . . . . iterator for a groupoid
##
InstallMethod( Iterator, "for a connected groupoid", 
    [ IsGroupoid and IsSinglePiece ], 
function( gpd )
    return IteratorByFunctions( rec( 
        IsDoneIterator := function( iter )
            return ( IsDoneIterator( iter!.groupIterator ) 
                     and ( iter!.tpos = iter!.len )
                     and ( iter!.hpos = iter!.len ) );
            end, 
        NextIterator := function( iter )
            if ( iter!.tpos = 0 ) then
                iter!.gpelt := NextIterator( iter!.groupIterator );
                iter!.tpos := 1;
                iter!.hpos := 1;
            elif ((iter!.tpos = iter!.len) and (iter!.hpos = iter!.len)) then 
                iter!.gpelt := NextIterator( iter!.groupIterator );
                iter!.tpos := 1;
                iter!.hpos := 1;
            elif ( iter!.hpos = iter!.len ) then
                iter!.hpos := 1;
                iter!.tpos := iter!.tpos + 1;
            else 
                iter!.hpos := iter!.hpos + 1;
            fi;
            if ( HasIsDirectProductWithCompleteDigraph( gpd ) 
                 and IsDirectProductWithCompleteDigraph( gpd ) ) then 
                return ArrowNC( gpd, true, iter!.gpelt, 
                                iter!.obs[iter!.tpos], iter!.obs[iter!.hpos] );
            else 
                return ArrowNC( gpd, true, 
                                gpd!.rays[iter!.tpos]^(-1)
                                  * iter!.gpelt
                                    * gpd!.rays[iter!.hpos], 
                                iter!.obs[iter!.tpos], iter!.obs[iter!.hpos] );
            fi;
            end, 
        ShallowCopy := iter -> 
            rec( groupIterator := ShallowCopy( iter!.groupIterator ), 
                 gpelt := iter!.gpelt,
                 obs := iter!.obs,
                 len := iter!.len,
                 tpos := iter!.tpos,
                 hpos := iter!.hpos ),
        groupIterator := Iterator( gpd!.magma ), 
        gpelt := 0, 
        obs := gpd!.objects,
        len := Length( gpd!.objects ),
        tpos := 0,
        hpos := 0 ) );
end );

InstallMethod( Iterator, "generic method for a groupoid", [ IsGroupoid ], 
function( gpd )
    return IteratorByFunctions( rec( 
        IsDoneIterator := function( iter )
            return ( IsDoneIterator( iter!.groupoidIterator ) 
                     and ( iter!.cpos = iter!.len ) );
            end, 
        NextIterator := function( iter )
            if IsDoneIterator( iter!.groupoidIterator ) then 
                iter!.cpos := iter!.cpos + 1;
                iter!.groupoidIterator := 
                    Iterator( iter!.pieces[iter!.cpos] );
            fi;
            return NextIterator( iter!.groupoidIterator );
            end,
        ShallowCopy := iter -> 
            rec( pieces := iter!.pieces,
                 len := iter!.len,
                 groupoidIterator := ShallowCopy( iter!.groupoidIterator ),
                 cpos := iter!.cpos ),
        pieces := Pieces( gpd ),
        len := Length( Pieces( gpd ) ),
        groupoidIterator := Iterator( Pieces( gpd )[1] ),
        cpos := 1 ) );
end );

## ======================================================================= ##
##                                Subgroupoids                             ##
## ======================================================================= ##

#############################################################################
##
#F  Subgroupoid( <gpd>, <subgp> )        subgroupoid by subgroup
#F  Subgroupoid( <gpd>, <comp> )         subgroupoid as list of [sgp,obs]
#F  Subgroupoid( <gpd>, <obs> )          subgroupoid by objects
#F  Subgroupoid( <gpd>, <gps>, <obs> )   discrete subgroupoid 
##
InstallGlobalFunction( Subgroupoid, function( arg )

    local nargs, gpd, id, rays, gp, sub; 

    nargs := Length( arg );
    gpd := arg[1];
    if not IsGroupoid( gpd ) then 
        Info( InfoGroupoids, 1, "arg[1] is not a groupoid" );
        return fail;
    fi;
    # by subgroup
    if ( nargs = 2 ) then
        if ( IsSinglePiece( arg[1] ) and IsGroup( arg[2] ) ) then
            gp := gpd!.magma;
            Info( InfoGroupoids, 2, "connected subgroupoid" );
            sub := SinglePieceGroupoid( arg[2], gpd!.objects );
            SetParentAttr( sub, gpd );
        elif IsHomogeneousList( arg[2] ) then
            if IsList( arg[2][1] ) then 
                Info( InfoGroupoids, 2, "subgroupoid by pieces" );
                sub := SubgroupoidByPieces( arg[1], arg[2] );
            else
                Info( InfoGroupoids, 2, "subgroupoid by objects" );
                sub := SubgroupoidByObjects( arg[1], arg[2] );
            fi;
        fi;
        return sub;
    fi;
    # discrete subgroupoid
    if ( nargs = 3 ) then
        if ( IsHomogeneousList( arg[2] ) and IsHomogeneousList( arg[3] ) ) then
            Info( InfoGroupoids, 2, "discrete subgroupoid" );
            return DiscreteSubgroupoid( arg[1], arg[2], arg[3] );
        elif ( IsGroup( arg[2] ) and IsHomogeneousList( arg[3] ) ) then
            Info( InfoGroupoids, 2, "subgroupoid with rays" );
            return SubgroupoidWithRays( arg[1], arg[2], arg[3] );
        fi;
    fi;
    Info( InfoGroupoids, 1, SUB_CONSTRUCTORS );
    return fail;
end );

#############################################################################
##
#F  IsSubgroupoid( <G>, <U> )
##
InstallMethod( IsSubgroupoid, "generic method for two groupoids", true,
    [ IsGroupoid, IsGroupoid], 0,
function( G, U ) 
    if ( HasParentAttr( U ) and ( ParentAttr( U ) = G ) ) then 
        return true;
    fi;
    if not IsSubset( ObjectList(G), ObjectList(U) ) then
        return false;
    fi; 
    return ForAll( Pieces( U ), C -> IsSubgroupoid( G, C ) );
end );

InstallMethod( IsSubgroupoid, "generic method for two groupoids", true,
    [ IsGroupoid, IsGroupoid and IsSinglePiece], 0,
function( G, U )
    if ( HasParentAttr( U ) and ( ParentAttr( U ) = G ) ) then 
        return true;
    fi;
    if not IsSubset( ObjectList(G), ObjectList(U) ) then
        return false;
    fi; 
    return IsSubgroupoid( PieceOfObject(G,U!.objects[1]), U ); 
end ); 

InstallMethod( IsSubgroupoid, "generic method for two groupoids", true,
  [IsGroupoid and IsSinglePiece, IsGroupoid and IsSinglePiece], 0,
function( G, U )

    local objG, objU; 

    ## Print( "IsSubgroupoid 3 : ", G, " >= ", U, "\n" ); 
    if ( HasParentAttr( U ) and ( ParentAttr( U ) = G ) ) then 
        return true;
    fi;
    if not IsSubset( ObjectList(G), ObjectList(U) ) then
        return false;
    fi;  
    if ( G = U ) then 
        return true; 
    fi; 
    objG := G!.objects; 
    objU := U!.objects; 
    if not IsSubset( objG, objU ) then
        return false;
    fi; 
    if not IsSubgroup( ObjectGroup( G, objU[1] ), U!.magma ) then
        return false; 
    fi; 
    if not HasParentAttr( U ) then 
        SetParent( U, G ); 
    fi; 
    return true; 
end ); 

InstallMethod( IsWideSubgroupoid, "for two groupoids", true, 
    [ IsGroupoid, IsGroupoid ], 0, 
function( D, S )
    return ( IsSubgroupoid( D, S ) and 
             ObjectList( D ) = ObjectList( S ) ); 
end ); 

InstallMethod( IsFullSubgroupoid, "for two groupoids", true, 
    [ IsGroupoid, IsGroupoid ], 0, 
function( D, S )
    local  r, rgpS, pD, rgpD, pS;
    if IsSinglePiece( S ) then 
        r := RootObject( S );
        rgpS := ObjectGroup( S, r );
        pD := PieceOfObject( D, r );
        rgpD := ObjectGroup( pD, r );
        return ( rgpS = rgpD );
    else
        for pS in Pieces( S ) do
            r := RootObject( pS );
            rgpS := ObjectGroup( pS, r );
            pD := PieceOfObject( D, r );
            rgpD := ObjectGroup( pD, r );
            if not ( rgpS = rgpD ) then
                return false;
            fi;
        od;
        return true;
    fi;
end ); 

############################################################################
##
#M  SubgroupoidBySubgroup
##
InstallMethod( SubgroupoidBySubgroup, "for single piece groupoid and subgroup", 
    true, [ IsGroupoid and IsSinglePiece, IsGroup ], 0,
function( G, sgp ) 

    local gpG, U;     

    Info( InfoGroupoids, 2, "calling SubgroupoidBySubgroup" );
    gpG := G!.magma; 
    if not IsSubgroup( gpG, sgp ) then 
        Error( "sgp is not a subgroup of RootGroup(G)" ); 
    fi; 
    if ( HasIsDirectProductWithCompleteDigraph( G ) 
         and IsDirectProductWithCompleteDigraph( G ) ) then 
        U := SinglePieceGroupoid( sgp, G!.objects );
    else
        U := SubgroupoidWithRays( G, sgp, RaysOfGroupoid( G ) ); 
    fi;
    SetParentAttr( U, G );
    return U; 
end ); 

#############################################################################
##
#M  SubgroupoidByPieces
##
InstallMethod( SubgroupoidByPieces,
    "generic method for a groupoid and a list of pieces", true,
    [ IsGroupoid, IsList ], 0, 
function( gpd, piecedata )

    local p1, withrays, pieceU, len, i, pi, par, sub, U, c, piece, 
          gobs, grays, nobspi, j, ob, rays, rootpi, rootpos, obpos;

    Info( InfoGroupoids, 2, "calling SubgroupoidByPieces" );
    p1 := piecedata[1];
    if IsList( p1 ) then 
        withrays := (("IsSinglePieceRaysRep" in RepresentationsOfObject(gpd)) 
                     or ( Length( p1 ) = 3))
                    and not ( ForAll( piecedata, p -> Length(p[2])=1 ) );
        len := Length( piecedata );
        pieceU := ListWithIdenticalEntries( len, 0 ); 
        for i in [1..len] do 
            pi := piecedata[i];
            if withrays then 
                if not ( Length( pi ) = 3 ) then 
                    ## keep the rays of the larger gpd 
                    gobs := ObjectList( gpd ); 
                    grays := RaysOfGroupoid( gpd ); 
                    rays := ShallowCopy( pi[2] ); 
                    nobspi := Length( pi[2] );
                    rootpi := pi[2][1]; 
                    rootpos := Position( gobs, rootpi );
                    for j in [1..nobspi] do 
                        ob := pi[2][j]; 
                        obpos := Position( gobs, ob ); 
                        rays[j] := grays[rootpos]^(-1) * grays[obpos]; 
                    od;
                    par := SubgroupoidByObjects( gpd, pi[2] ); 
                    sub := SubgroupoidWithRays( par, pi[1], rays ); 
                else 
                    par := SubgroupoidByObjects( gpd, pi[2] ); 
                    sub := SubgroupoidWithRays( par, pi[1], pi[3] ); 
                fi; 
            else 
                sub := SubgroupoidByObjects( gpd, pi[2] );
                if ( Length( pi ) = 2 ) then 
                    sub := SubgroupoidBySubgroup( sub, pi[1] );
                else
                    sub := SubgroupoidWithRays( sub, pi[1], pi[3] );
                fi;
            fi; 
            pieceU[i] := sub;
        od;
    else 
        pieceU := piecedata; 
    fi;
    if ( Length( pieceU ) > 1 ) then
        U := UnionOfPieces( pieceU );
    else
        U := pieceU[1];
    fi;
    if not IsSubgroupoid( gpd, U ) then 
        Info( InfoGroupoids, 1, 
                  "union of pieces is not a subgroupoid of gpd" );
        return fail;
    fi;
    if ForAll( pieceU, p -> ( Length(p!.objects) = 1 ) ) then
        SetIsDiscreteDomainWithObjects( U, true );
    else
        SetIsDiscreteDomainWithObjects( U, false );
    fi;
    SetParentAttr( U, gpd );
    for c in pieceU do 
        piece := PieceOfObject( gpd, c!.objects[1] ); 
        SetParentAttr( c, SubgroupoidByObjects( piece, ObjectList(c) ) );
    od;
    return U;
end );

#############################################################################
##
#M  DiscreteSubgroupoid
##
InstallMethod( DiscreteSubgroupoid, "generic method for a groupoid", true,
    [ IsGroupoid, IsList, IsHomogeneousList ], 0,
function( G, gps, obs )

    local pieceU, U, len, o, pieceG, obsg, C, i, gpo, ishomo;

    Info( InfoGroupoids, 2, "calling DiscreteSubgroupoid" );
    obsg := ObjectList( G );
    len := Length( obs ); 
    if ( len = 1 ) then 
        return MagmaWithSingleObject( gps[1], obs[1] ); 
    fi; 
    pieceU := ListWithIdenticalEntries( len, 0 );
    if not ( len = Length( gps ) ) then
        Error( "object and subgroup lists not of same length," );
    fi;
    for i in [1..len] do
        o := obs[i];
        if not ( o in obsg ) then
            Error( "i-th subgroupoid object not in groupoid," );
        fi;
        C := PieceOfObject( G, o ); 
        gpo := ObjectGroup( C, o ); 
        if not IsSubgroup( gpo, gps[i] ) then
            Error( "i-th group not a subgroup of the object group," );
        fi;
        pieceU[i] := MagmaWithSingleObject( gps[i], o );
    od; 
    ishomo := ForAll( gps, g -> ( g = gps[1] ) ); 
    if ishomo then 
        Info( InfoGroupoids, 2, 
              "all groups equal, so using HomogeneousDiscreteGroupoid" ); 
        U := HomogeneousDiscreteGroupoid( gps[1], obs ); 
    else 
        U := UnionOfPieces( pieceU ); 
    fi;
    SetIsDiscreteDomainWithObjects( U, true );
    SetParentAttr( U, G );
    return U;
end );

#############################################################################
##
#M  HomogeneousDiscreteSubgroupoid
##
InstallMethod( HomogeneousDiscreteSubgroupoid, "generic method for a groupoid",
    true, [ IsGroupoid and IsSinglePiece, IsGroup, IsHomogeneousList ], 0,
function( G, gp, obs )

    local obsg, len, rgp, gps;

    Info( InfoGroupoids, 2, "calling HomogeneousDiscreteSubgroupoid" );
    obsg := ObjectList( G );
    len := Length( obs ); 
    if ( len = 1 ) then 
        return MagmaWithSingleObject( gp, obs[1] ); 
    fi; 
    rgp := RootGroup( G );
    if not IsSubgroup( rgp, gp ) then
        Error( "gp is not a subgroup of the root group of G" );
    fi;
    gps := List( obs, o -> ObjectGroup( G, o ) );
    return DiscreteSubgroupoid( G, gps, obs );
end );

#############################################################################
##
#M  SubgroupoidByObjects
##
InstallMethod( SubgroupoidByObjects, "for direct product groupoid + objects", 
    true, [ IsGroupoid and IsDirectProductWithCompleteDigraph, 
    IsHomogeneousList ], 10,
function( G, obsU )

    local obsG, nobs, U; 

    Info( InfoGroupoids, 2, "calling SubgroupoidByObjects, method 1" );
    obsG := ObjectList( G ); 
    if not ForAll( obsU, o -> o in obsG ) then 
        Error( "<obsU> not a subset of the objects in G" ); 
    fi; 
    nobs := Length( obsU ); 
    if not ForAll( [1..nobs-1], j -> obsU[j] < obsU[j+1] ) then 
        Sort( obsU ); 
    fi; 
    U := SinglePieceGroupoidNC( G!.magma, obsU ); 
    SetParentAttr( U, G ); 
    return U;
end ); 

InstallMethod( SubgroupoidByObjects, "for a connected groupoid + object set", 
    true, [ IsGroupoid and IsSinglePieceRaysRep, IsHomogeneousList ], 0,
function( G, obsU )

    local obsG, nobs, ro, gpU, pos, rayG, rayU, ray1, j, anc; 

    Info( InfoGroupoids, 2, "calling SubgroupoidByObjects, method 2" );
    obsG := ObjectList( G ); 
    if not ForAll( obsU, o -> o in obsG ) then 
        Error( "<obsU> not a subset of the objects in G" ); 
    fi; 
    nobs := Length( obsU ); 
    if not ForAll( [1..nobs-1], j -> obsU[j] < obsU[j+1] ) then 
        Sort( obsU ); 
    fi; 
    ro := obsU[1]; 
    gpU := ObjectGroup( G, ro ); 
    pos := List( [1..nobs], j -> Position ( obsG, obsU[j] ) ); 
    rayG := RaysOfGroupoid( G ); 
    rayU := ShallowCopy( obsU ); 
    ray1 := rayG[ pos[1] ]^(-1);  
    for j in [1..nobs] do 
        rayU[j] := ray1 * rayG[ pos[j] ]; 
    od; 
    anc := SubgroupoidByObjects( Ancestor( G ), obsU ); 
    return SubgroupoidWithRays( anc, gpU, rayU ); 
end );

InstallMethod( SubgroupoidByObjects, "for a groupoid and set of objects", 
    true, [ IsGroupoid, IsHomogeneousList ], 0,
function( G, sobs ) 

    local pieceG, pieceU, j, P, obsP, sobsP;

    Info( InfoGroupoids, 2, "calling SubgroupoidByObjects, method 3" );
    pieceG := Pieces( G );
    pieceU := [ ];
    for j in [1..Length(pieceG)] do
        P := pieceG[j];
        obsP := P!.objects;
        sobsP := Intersection( sobs, obsP );
        if ( sobsP <> [ ] ) then 
            Add( pieceU, SubgroupoidByObjects( P, sobsP ) );
        fi;
    od;
    return UnionOfPieces( pieceU );
end );

InstallMethod( SubgroupoidByObjects, "for a homogeneous discrete groupoid", 
    true, [ IsHomogeneousDiscreteGroupoid, IsHomogeneousList ], 0,
function( gpd, sobs )

    local obs;

    Info( InfoGroupoids, 2, "calling SubgroupoidByObjects, method 4" );
    obs := gpd!.objects; 
    if not ForAll( sobs, o -> o in obs ) then 
        Error( "<sobs> not a subset of <gpd>!.objects," ); 
    fi; 
    if ( Length( sobs ) = 1 ) then 
        return MagmaWithSingleObject( gpd!.magma, sobs[1] ); 
    else 
        return HomogeneousDiscreteGroupoid( gpd!.magma, sobs ); 
    fi; 
end );

#############################################################################
##
#M  MaximalDiscreteSubgroupoid
#M  FullTrivialSubgroupoid
#M  DiscreteTrivialSubgroupoid
##
InstallMethod( MaximalDiscreteSubgroupoid,
    "generic method for a groupoid", true, [ IsGroupoid ], 0,
function( gpd )

    local obs, len, gps, i, piece, U, ok;

--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.60 Sekunden  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge