|
#############################################################################
##
## grape.gi
## Copyright (C) 2019-21 James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##
# TODO (later) revise this for mutable digraphs, if it makes sense to do so.
# <G> is a group, <obj> a set of points on which <act> acts, and <adj> is a
# function which for 2 elements u, v of <obj> returns <true> if and only if
# u and v should be adjacent in the digraph we are constructing.
InstallImmediateMethod(SemigroupOfCayleyDigraph,
IsCayleyDigraph and HasGroupOfCayleyDigraph, 0, GroupOfCayleyDigraph);
InstallMethod(Digraph,
"for a group, list or collection, function, and function",
[IsGroup, IsListOrCollection, IsFunction, IsFunction],
{G, obj, act, adj} -> Digraph(IsImmutableDigraph, G, obj, act, adj));
InstallMethod(Digraph,
"for a group, list or collection, function, and function",
[IsFunction, IsGroup, IsListOrCollection, IsFunction, IsFunction],
function(imm, G, obj, act, adj)
local hom, dom, sch, orbits, reps, stabs, rep_out, out, gens, trace, word,
D, adj_func, i, o, w;
if not imm in [IsMutableDigraph, IsImmutableDigraph] then
ErrorNoReturn("<imm> must be IsMutableDigraph or IsImmutableDigraph");
fi;
hom := ActionHomomorphism(G, obj, act, "surjective");
dom := [1 .. Size(obj)];
sch := DIGRAPHS_Orbits(Range(hom), dom);
orbits := sch.orbits;
sch := sch.schreier;
reps := List(orbits, Representative);
stabs := List(reps, i -> Stabilizer(Range(hom), i));
rep_out := EmptyPlist(Length(reps));
for i in [1 .. Length(reps)] do
if IsTrivial(stabs[i]) then
rep_out[i] := Filtered(dom, j -> adj(obj[reps[i]], obj[j]));
else
rep_out[i] := [];
for o in DIGRAPHS_Orbits(stabs[i], dom).orbits do
if adj(obj[reps[i]], obj[o[1]]) then
Append(rep_out[i], o);
fi;
od;
fi;
od;
# TODO comment this out, use method for OutNeighbours for digraph with group
# instead.
out := EmptyPlist(Size(obj));
gens := GeneratorsOfGroup(Range(hom));
for i in [1 .. Length(sch)] do
if sch[i] < 0 then
out[i] := rep_out[-sch[i]];
fi;
trace := DIGRAPHS_TraceSchreierVector(gens, sch, i);
out[i] := rep_out[trace.representative];
word := trace.word;
for w in word do
out[i] := OnTuples(out[i], gens[w]);
od;
od;
D := DigraphNC(imm, out);
if IsImmutableDigraph(D) then
adj_func := {u, v} -> adj(obj[u], obj[v]);
SetFilterObj(D, IsDigraphWithAdjacencyFunction);
SetDigraphAdjacencyFunction(D, adj_func);
SetDigraphGroup(D, Range(hom));
SetDigraphOrbits(D, orbits);
SetDIGRAPHS_Stabilizers(D, stabs);
SetDigraphSchreierVector(D, sch);
SetRepresentativeOutNeighbours(D, rep_out);
fi;
return D;
end);
InstallMethod(CayleyDigraphCons,
"for IsMutableDigraph, group, and list of elements",
[IsMutableDigraph, IsGroup, IsHomogeneousList],
function(_, G, gens)
if not IsFinite(G) then
ErrorNoReturn("the 2nd argument (a group) must be finite");
elif not ForAll(gens, x -> x in G) then
ErrorNoReturn("the 3rd argument (a homog. list) must consist of ",
"elements of the 2nd argument (a group)");
fi;
return Digraph(IsMutableDigraph,
G,
AsList(G),
OnLeftInverse,
{x, y} -> x ^ -1 * y in gens);
end);
InstallMethod(CayleyDigraphCons,
"for IsImmutableDigraph, group, and list of elements",
[IsImmutableDigraph, IsGroup, IsHomogeneousList],
function(_, G, gens)
local set, D, edge_labels;
# This method is a duplicate of the one above because the method for Digraph
# sets some additional attributes if IsImmutableDigraph is passed as 1st
# argument, and so we don't want to make a mutable version of the returned
# graph, and then make it immutable, because then those attributes won't be
# set.
if not IsFinite(G) then
ErrorNoReturn("the 2nd argument (a group) must be finite");
elif not ForAll(gens, x -> x in G) then
ErrorNoReturn("the 3rd argument (a homog. list) must consist ",
"of elements of the 2nd argument (a list)");
fi;
set := AsSet(G);
# vertex i in the Cayley digraph corresponds to elts[i].
D := Digraph(IsImmutableDigraph,
G,
set,
OnLeftInverse,
{x, y} -> LeftQuotient(x, y) in gens);
SetFilterObj(D, IsCayleyDigraph);
SetGroupOfCayleyDigraph(D, G);
SetGeneratorsOfCayleyDigraph(D, gens);
SetDigraphVertexLabels(D, AsList(G));
# Out-neighbours of identity give the correspondence between edges & gens
edge_labels := AsList(G){OutNeighboursOfVertex(D,
Position(set, One(G)))};
SetDigraphEdgeLabels(D, ListWithIdenticalEntries(Size(G), edge_labels));
return D;
end);
InstallMethod(CayleyDigraph, "for a group and list of elements",
[IsGroup, IsHomogeneousList],
{G, gens} -> CayleyDigraphCons(IsImmutableDigraph, G, gens));
InstallMethod(CayleyDigraph, "for a filter and group with generators",
[IsFunction, IsGroup, IsHomogeneousList], CayleyDigraphCons);
InstallMethod(CayleyDigraph, "for a group with generators",
[IsGroup and HasGeneratorsOfGroup],
G -> CayleyDigraphCons(IsImmutableDigraph, G, GeneratorsOfGroup(G)));
InstallMethod(CayleyDigraph, "for a filter and group with generators",
[IsFunction, IsGroup and HasGeneratorsOfGroup],
{filt, G} -> CayleyDigraphCons(filt, G, GeneratorsOfGroup(G)));
InstallMethod(Graph, "for a digraph", [IsDigraph],
function(D)
local gamma, i, n;
if IsMultiDigraph(D) then
Info(InfoWarning, 1, "Grape does not support multiple edges, so ",
"the Grape graph will have fewer\n#I edges than the original,");
fi;
if not DIGRAPHS_IsGrapeLoaded() then
Info(InfoWarning, 1, "Grape is not loaded,");
fi;
n := DigraphNrVertices(D);
if HasDigraphGroup(D) then
gamma := rec(order := n,
group := DigraphGroup(D),
isGraph := true,
representatives := DigraphOrbitReps(D),
schreierVector := DigraphSchreierVector(D));
gamma.adjacencies := ShallowCopy(RepresentativeOutNeighbours(D));
Apply(gamma.adjacencies, AsSet);
else
gamma := rec(order := n,
group := Group(()),
isGraph := true,
representatives := [1 .. n] * 1,
schreierVector := [1 .. n] * -1);
gamma.adjacencies := EmptyPlist(n);
for i in [1 .. gamma.order] do
gamma.adjacencies[i] := Set(OutNeighbours(D)[i]);
od;
fi;
gamma.names := Immutable(DigraphVertexLabels(D));
return gamma;
end);
# InstallMethod(PrintString,
# "for a digraph with group and representative out neighbours",
# [IsDigraph and HasDigraphGroup and HasRepresentativeOutNeighbours],
# function(D)
# return Concatenation("D< ",
# PrintString(DigraphGroup(D)), ", ",
# PrintString(DigraphVertices(D)), ", ",
# PrintString(RepresentativeOutNeighbours(D)), ">");
# end);
# Returns the digraph with vertex - set {1, .. ., n} and edge-set
# the union over e in E of e ^ G.
# (E can consist of just a singleton edge.)
# Note: if at some point we don't store all of the out neighbours, then this
# can be improved. JDM
InstallMethod(EdgeOrbitsDigraph, "for a perm group, list, and int",
[IsPermGroup, IsList, IsInt],
function(G, edges, n)
local out, o, D, e, f;
if n < 0 then
ErrorNoReturn("the 3rd argument <n> must be a non-negative integer,");
elif n = 0 then
return EmptyDigraph(0);
elif IsPosInt(edges[1]) then # E consists of a single edge
edges := [edges];
fi;
if not ForAll(edges, e -> Length(e) = 2 and ForAll(e, IsPosInt)) then
ErrorNoReturn("the 2nd argument <edges> must be a list of pairs of ",
"positive integers,");
fi;
out := List([1 .. n], x -> []);
for e in edges do
o := Orbit(G, e, OnTuples);
for f in o do
AddSet(out[f[1]], f[2]);
od;
od;
D := DigraphNC(out);
SetDigraphGroup(D, G);
return D;
end);
InstallMethod(EdgeOrbitsDigraph, "for a group and list",
[IsPermGroup, IsList],
{G, E} -> EdgeOrbitsDigraph(G, E, LargestMovedPoint(G)));
# Note: if at some point we don't store all of the out neighbours, then this
# can be improved. JDM
InstallMethod(DigraphAddEdgeOrbit, "for a digraph and list",
[IsDigraph, IsList],
function(D, edge)
local G, o, imm, e;
if not (Length(edge) = 2 and ForAll(edge, IsPosInt)) then
ErrorNoReturn("the 2nd argument <edge> must be a list of 2 ",
"positive integers,");
elif not (edge[1] in DigraphVertices(D)
and edge[2] in DigraphVertices(D)) then
ErrorNoReturn("the 2nd argument <edge> must be a list of 2 vertices of ",
"the 1st argument <D>,");
elif IsDigraphEdge(D, edge) then
return D;
fi;
G := DigraphGroup(D);
o := Orbit(G, edge, OnTuples);
if IsImmutableDigraph(D) then
imm := true;
D := DigraphMutableCopy(D);
fi;
for e in o do
DigraphAddEdge(D, e);
od;
if imm then
MakeImmutable(D);
SetDigraphGroup(D, G);
fi;
return D;
end);
# Note: if at some point we don't store all of the out neighbours, then this
# can be improved. JDM
InstallMethod(DigraphRemoveEdgeOrbit, "for a digraph and list",
[IsDigraph, IsList],
function(D, edge)
local G, o, imm, e;
if not (Length(edge) = 2 and ForAll(edge, IsPosInt)) then
ErrorNoReturn("the 2nd argument <edge> must be a pair of ",
"positive integers,");
elif not (edge[1] in DigraphVertices(D)
and edge[2] in DigraphVertices(D)) then
ErrorNoReturn("the 2nd argument <edge> must be a ",
"pair of vertices of the 1st argument <D>,");
elif not IsDigraphEdge(D, edge) then
return D;
fi;
G := DigraphGroup(D);
o := Orbit(G, edge, OnTuples);
if IsImmutableDigraph(D) then
imm := true;
D := DigraphMutableCopy(D);
fi;
for e in o do
DigraphRemoveEdge(D, e);
od;
if imm then
MakeImmutable(D);
SetDigraphGroup(D, G);
fi;
return D;
end);
[ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet)
]
|