|
#############################################################################
##
#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
--> --------------------
[ 0.52Quellennavigators
Projekt
]
|