From 20798072e4d0dfbb2018dc1bd1e9cff73b3c40e9 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 10 Feb 2021 16:05:45 +0000 Subject: [PATCH] examples: add pancakes --- doc/examples.xml | 79 +++++++++++++++++++++++++++++++++++++++ doc/z-chap2.xml | 1 + gap/examples.gd | 8 ++++ gap/examples.gi | 64 +++++++++++++++++++++++++++++++ gap/grape.gd | 5 +++ gap/grape.gi | 65 ++++++++++++++++++++++++-------- tst/standard/examples.tst | 27 +++++++++++++ tst/standard/grape.tst | 29 +++++++++++++- 8 files changed, 261 insertions(+), 17 deletions(-) diff --git a/doc/examples.xml b/doc/examples.xml index 60a28de39..bad6a4062 100644 --- a/doc/examples.xml +++ b/doc/examples.xml @@ -419,6 +419,85 @@ gap> TriangularGridGraph(IsMutable, 3, 3); <#/GAPDoc> +<#GAPDoc Label="PancakeGraph"> + + + A digraph. + + If n is a positive integer, then this operation returns + the pancake graph with n! vertices and n!(n - 1) + directed edges. The nth pancake graph is the Cayley graph of the + symmetric group acting on [1 .. n] with respect to the + generating set consisting of the prefix reversals. This generating + set consists of the permutations p2, p3, ..., + pn where ListPerm(pi, n) is the concatenation + of [i, i - 1 .. 1] and [i + 1 .. n]. +

+ + If the optional first argument filt is not present, then is used by default.

+ + See https://en.wikipedia.org/wiki/Pancake_graph for further + details. + + D := PancakeGraph(5); + +gap> DigraphUndirectedGirth(D); +6 +gap> ChromaticNumber(D); +3 +gap> IsHamiltonianDigraph(D); +true +gap> IsCayleyDigraph(D); +true +gap> IsVertexTransitive(D); +true]]> + + +<#/GAPDoc> + +<#GAPDoc Label="BurntPancakeGraph"> + + + A digraph. + + If n is a positive integer, then this operation returns + the burnt pancake graph with n! vertices and n2^(n)n! + directed edges. The nth burnt pancake graph is the Cayley graph of the + hyperoctahedral group acting on [-n .. -1, 1 .. n] with respect to the + generating set consisting of the prefix reversals, which are defined in exactly + the same way as in . The hyperoctahedral group consists of + permutations p acting on [-n .. -1, 1 .. n], where the image + of every point i in [-n .. -1, 1 .. n] is equal to the + negative of the image of -i under p. + GAP only works with permutations of positive integers and so BurntPancakeGraph returns + the Cayley graph of the hyperoctahedral group acting on [1 .. 2n] instead of + [-n .. -1, 1 .. n]. + If the optional first argument filt is not present, then is used by default.

+ + See https://en.wikipedia.org/wiki/Pancake_graph for further + details. + + BurntPancakeGraph(3); + +gap> BurntPancakeGraph(4); + +gap> BurntPancakeGraph(5); + +gap> BurntPancakeGraph(IsMutableDigraph, 1); + +]]> + + +<#/GAPDoc> + <#GAPDoc Label="StarGraph"> diff --git a/doc/z-chap2.xml b/doc/z-chap2.xml index 210b4da68..aafca146c 100644 --- a/doc/z-chap2.xml +++ b/doc/z-chap2.xml @@ -100,6 +100,7 @@ <#Include Label="BookGraph"> <#Include Label="StackedBookGraph"> <#Include Label="BinaryTree"> + <#Include Label="PancakeGraph"> diff --git a/gap/examples.gd b/gap/examples.gd index 16ba7f4c5..e52fa7a41 100644 --- a/gap/examples.gd +++ b/gap/examples.gd @@ -98,3 +98,11 @@ DeclareOperation("StackedBookGraph", [IsFunction, IsPosInt, IsPosInt]); DeclareConstructor("BinaryTreeCons", [IsDigraph, IsPosInt]); DeclareOperation("BinaryTree", [IsPosInt]); DeclareOperation("BinaryTree", [IsFunction, IsPosInt]); + +DeclareConstructor("PancakeGraphCons", [IsDigraph, IsPosInt]); +DeclareOperation("PancakeGraph", [IsPosInt]); +DeclareOperation("PancakeGraph", [IsFunction, IsPosInt]); + +DeclareConstructor("BurntPancakeGraphCons", [IsDigraph, IsPosInt]); +DeclareOperation("BurntPancakeGraph", [IsPosInt]); +DeclareOperation("BurntPancakeGraph", [IsFunction, IsPosInt]); diff --git a/gap/examples.gi b/gap/examples.gi index 59943d5a7..913e22c9d 100644 --- a/gap/examples.gi +++ b/gap/examples.gi @@ -793,3 +793,67 @@ depth -> BinaryTreeCons(IsImmutableDigraph, depth)); InstallMethod(BinaryTree, "for a function and a positive integer", [IsFunction, IsPosInt], BinaryTreeCons); + +BindGlobal("DIGRAPHS_PrefixReversalGroup", +function(n) + return Group(List([2 .. n], i -> PermList([i, i - 1 .. 1])), ()); +end); + +InstallMethod(PancakeGraphCons, "for IsMutableDigraph and pos int", +[IsMutableDigraph, IsPosInt], +{filt, n} -> CayleyDigraph(IsMutableDigraph, DIGRAPHS_PrefixReversalGroup(n))); + +InstallMethod(PancakeGraphCons, "for IsImmutableDigraph and pos int", +[IsImmutableDigraph, IsPosInt], +function(filt, n) + local D; + D := CayleyDigraph(IsImmutableDigraph, DIGRAPHS_PrefixReversalGroup(n)); + SetIsMultiDigraph(D, false); + SetIsSymmetricDigraph(D, true); + SetIsHamiltonianDigraph(D, true); + return D; +end); + +InstallMethod(PancakeGraph, "for a function and pos int", +[IsFunction, IsPosInt], PancakeGraphCons); + +InstallMethod(PancakeGraph, "for a pos int", +[IsPosInt], n -> PancakeGraphCons(IsImmutableDigraph, n)); + +BindGlobal("DIGRAPHS_HyperoctahedralGroup", +function(n) + local id, A, i; + if n = 1 then + return Group(()); + fi; + id := [1 .. 2 * n]; + A := []; + for i in [1 .. n] do + id{[1 .. i]} := [i + n, i - 1 + n .. 1 + n]; + id{[n + 1 .. n + i]} := [i, i - 1 .. 1]; + Add(A, PermList(id)); + od; + return Group(A); +end); + +InstallMethod(BurntPancakeGraphCons, "for IsMutableDigraph and pos int", +[IsMutableDigraph, IsPosInt], +{filt, n} -> CayleyDigraph(IsMutableDigraph, DIGRAPHS_HyperoctahedralGroup(n))); + +InstallMethod(BurntPancakeGraphCons, "for IsImmutableDigraph and pos int", +[IsImmutableDigraph, IsPosInt], +function(filt, n) + local D; + D := CayleyDigraph(IsImmutableDigraph, DIGRAPHS_HyperoctahedralGroup(n)); + SetIsMultiDigraph(D, false); + SetIsSymmetricDigraph(D, true); + SetIsHamiltonianDigraph(D, true); + return D; +end); + +InstallMethod(BurntPancakeGraph, "for a function and pos int", +[IsFunction, IsPosInt], BurntPancakeGraphCons); + +InstallMethod(BurntPancakeGraph, "for a pos int", +[IsPosInt], n -> BurntPancakeGraphCons(IsImmutableDigraph, n)); + diff --git a/gap/grape.gd b/gap/grape.gd index 9eab49d94..205a931c0 100644 --- a/gap/grape.gd +++ b/gap/grape.gd @@ -11,8 +11,13 @@ DeclareOperation("Graph", [IsDigraph]); # Cayley digraphs +DeclareConstructor("CayleyDigraphCons", [IsDigraph, IsGroup, IsList]); + DeclareOperation("CayleyDigraph", [IsGroup]); DeclareOperation("CayleyDigraph", [IsGroup, IsList]); +DeclareOperation("CayleyDigraph", [IsFunction, IsGroup]); +DeclareOperation("CayleyDigraph", [IsFunction, IsGroup, IsList]); + DeclareAttribute("GroupOfCayleyDigraph", IsCayleyDigraph); DeclareAttribute("SemigroupOfCayleyDigraph", IsCayleyDigraph); DeclareAttribute("GeneratorsOfCayleyDigraph", IsCayleyDigraph); diff --git a/gap/grape.gi b/gap/grape.gi index 2a10a286e..5b5106bd7 100644 --- a/gap/grape.gi +++ b/gap/grape.gi @@ -91,37 +91,72 @@ function(imm, G, obj, act, adj) return D; end); -InstallMethod(CayleyDigraph, "for a group with generators", -[IsGroup, IsHomogeneousList], -function(G, gens) - local elts, adj, D, edge_labels; - +InstallMethod(CayleyDigraphCons, +"for IsMutableDigraph, group, and list of elements", +[IsMutableDigraph, IsGroup, IsHomogeneousList], +function(filt, G, gens) if not IsFinite(G) then - ErrorNoReturn("the 1st argument must be a finite group,"); + ErrorNoReturn("the 2nd argument (a group) must be finite"); elif not ForAll(gens, x -> x in G) then - ErrorNoReturn("the 2nd argument must consist of elements of the ", - "1st argument,"); + 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(filt, G, gens) + local 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; # vertex i in the Cayley digraph corresponds to elts[i]. - elts := AsList(G); - adj := {x, y} -> LeftQuotient(x, y) in gens; + D := Digraph(IsImmutableDigraph, + G, + AsList(G), + OnLeftInverse, + {x, y} -> LeftQuotient(x, y) in gens); - D := Digraph(IsImmutableDigraph, G, elts, OnLeftInverse, adj); SetFilterObj(D, IsCayleyDigraph); SetGroupOfCayleyDigraph(D, G); SetGeneratorsOfCayleyDigraph(D, gens); - SetDigraphVertexLabels(D, elts); + SetDigraphVertexLabels(D, AsList(G)); # Out-neighbours of identity give the correspondence between edges & gens - edge_labels := elts{OutNeighboursOfVertex(D, Position(elts, One(G)))}; + edge_labels := AsList(G){OutNeighboursOfVertex(D, + Position(AsList(G), 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 -> CayleyDigraph(G, GeneratorsOfGroup(G))); +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) diff --git a/tst/standard/examples.tst b/tst/standard/examples.tst index 9b1f019ed..ef43338df 100644 --- a/tst/standard/examples.tst +++ b/tst/standard/examples.tst @@ -401,6 +401,33 @@ true gap> BinaryTree(4); +# PancakeGraph +gap> D := PancakeGraph(3); + +gap> ChromaticNumber(D); +2 +gap> IsVertexTransitive(D); +true +gap> DigraphUndirectedGirth(D); +6 +gap> IsHamiltonianDigraph(D); +true +gap> D := PancakeGraph(IsMutableDigraph, 1); + + +# BurntPancakeGraph +gap> BurntPancakeGraph(3); + +gap> BurntPancakeGraph(4); + +gap> BurntPancakeGraph(5); + +gap> BurntPancakeGraph(IsMutableDigraph, 1); + + # gap> DIGRAPHS_StopTest(); gap> STOP_TEST("Digraphs package: standard/examples.tst", 0); diff --git a/tst/standard/grape.tst b/tst/standard/grape.tst index a121d7f68..65101cd74 100644 --- a/tst/standard/grape.tst +++ b/tst/standard/grape.tst @@ -26,6 +26,13 @@ true gap> ForAll(DigraphEdges(digraph), e -> AsList(group)[e[1]] > * DigraphEdgeLabel(digraph, e[1], e[2]) = AsList(group)[e[2]]); true +gap> digraph := CayleyDigraph(IsMutableDigraph, group); + +gap> digraph := CayleyDigraph(IsMutableDigraph, FreeGroup(1)); +Error, the 2nd argument (a group) must be finite +gap> digraph := CayleyDigraph(IsMutableDigraph, group, [(2, 3)]); +Error, the 3rd argument (a homog. list) must consist of elements of the 2nd ar\ +gument (a group) gap> group := DihedralGroup(IsPermGroup, 8); Group([ (1,2,3,4), (2,4) ]) gap> digraph := CayleyDigraph(group); @@ -41,10 +48,11 @@ true gap> GeneratorsOfCayleyDigraph(digraph); [ () ] gap> digraph := CayleyDigraph(group, [(1, 2, 3, 4), (2, 5)]); -Error, the 2nd argument must consist of elements of the 1st argument, +Error, the 3rd argument (a homog. list) must consist of elements of the 2nd ar\ +gument (a list) gap> group := FreeGroup(2);; gap> digraph := CayleyDigraph(group); -Error, the 1st argument must be a finite group, +Error, the 2nd argument (a group) must be finite # CayleyDigraph: check edge labels # @@ -260,6 +268,23 @@ gap> if DIGRAPHS_IsGrapeLoaded then gap> Digraph(SymmetricGroup(3), [1, 2, 3], OnPoints, {x, y} -> x <> y); +# +gap> Digraph(IsSemigroup, SymmetricGroup(3), [1, 2, 3], OnPoints, +> {x, y} -> x <> y); +Error, must be IsMutableDigraph or IsImmutableDigraph + +# Code coverage +gap> D := Digraph([[1, 1]]); + +gap> Graph(D); +rec( adjacencies := [ [ 1 ] ], group := Group(()), isGraph := true, + names := [ 1 ], order := 1, representatives := [ 1 ], + schreierVector := [ -1 ] ) +gap> D := CompleteDigraph(IsMutableDigraph, 5);; +gap> HasDigraphGroup(D); +false +gap> Graph(D);; + # gap> DIGRAPHS_StopTest(); gap> STOP_TEST("Digraphs package: standard/grape.tst", 0);