From 1a9b94930178fb8d5cd3bad28742db04c40660bb Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Wed, 19 Jul 2017 15:31:19 +0100 Subject: [PATCH 1/3] Require Digraphs version 0.10.0 --- PackageInfo.g | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PackageInfo.g b/PackageInfo.g index f17c1777a..bdbc29628 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -11,7 +11,7 @@ ## <#GAPDoc Label="PKGVERSIONDATA"> ## ## -## +## ## ## ## @@ -236,7 +236,7 @@ Dependencies := rec( GAP := ">=4.9.0", NeededOtherPackages := [["orb", ">=4.7.5"], ["io", ">=4.4.4"], - ["digraphs", ">=0.7.1"], + ["digraphs", ">=0.10.0"], ["genss", ">=1.5"]], SuggestedOtherPackages := [["gapdoc", ">=1.5.1"]], diff --git a/README.md b/README.md index bc59bc905..7e5af98ac 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The following is a summary of the steps that should lead to a successful ins * get the [Orb](http://gap-system.github.io/orb/) package version 4.7.5 or higher. Both [Orb](http://gap-system.github.io/orb/) and [Semigroups](https://gap-packages.github.io/Semigroups) perform better if [Orb](http://gap-system.github.io/orb/) is compiled, so compile [Orb](http://gap-system.github.io/orb/)! -* ensure that the [Digraphs](http://gap-system.github.io/digraphs/) package version 0.7.1 or higher is available. [Digraphs](http://gap-system.github.io/digraphs/) must be compiled before [Semigroups](https://gap-packages.github.io/Semigroups) can be +* ensure that the [Digraphs](http://gap-system.github.io/digraphs/) package version 0.10.0 or higher is available. [Digraphs](http://gap-system.github.io/digraphs/) must be compiled before [Semigroups](https://gap-packages.github.io/Semigroups) can be loaded. * get the [genss](http://gap-system.github.io/genss/) package version 1.5 or higher From 5b31912c2c600515de9b791ddc3306e9fa3cd4ab Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Wed, 12 Jul 2017 18:32:48 +0100 Subject: [PATCH 2/3] fropin: add Left/RightCayleyDigraph These essentially just wrap the value previously returned by Left/RightCayleyGraphSemigroup in a Digraph object. Methods for Left/RightCayleyGraphSemigroup continue to exist (just calling OutNeighbours(Left/RightCayleyDigraph) since they are defined in the library. All other occurrences of Left/RightCayleyGraphSemigroup are replaced with Left/RightCayleyDigraph. --- doc/fropin.xml | 37 ++++++++++++++++++++++--------------- doc/z-chap13.xml | 2 +- gap/congruences/conginv.gi | 2 +- gap/greens/gree.gi | 2 -- gap/greens/gren.gi | 27 ++++++++++++++------------- gap/ideals/idealenum.gi | 4 ++-- gap/main/fropin.gd | 3 +++ gap/main/fropin.gi | 32 ++++++++++++++++++++++++++++---- gap/semigroups/grpperm.gi | 2 +- gap/semigroups/semifp.gi | 2 +- gap/semigroups/semitrans.gi | 6 +++--- src/fropin.cc | 12 ++++++------ tst/standard/attr.tst | 27 ++++++++++++++------------- tst/standard/fropin.tst | 31 ++++++++++++++++++++++++++----- tst/standard/gren.tst | 8 ++++---- 15 files changed, 126 insertions(+), 71 deletions(-) diff --git a/doc/fropin.xml b/doc/fropin.xml index 2a4f23295..1cecdbdc8 100644 --- a/doc/fropin.xml +++ b/doc/fropin.xml @@ -50,8 +50,8 @@ false returns a list of the elements of S in the order they are enumerated by the Froidure-Pin Algorithm. This is the same as the order used to index the elements of S in and .

+ Attr="RightCayleyDigraph"/> and .

EnumeratorCanonical and IteratorCanonical return an enumerator and an iterator where the elements are @@ -67,8 +67,8 @@ false AsList may not equal the value returned by AsListCanonical. AsListCanonical exists so that there is a method for obtaining the elements of S in the particular order used by - and - .

+ and + .

See also . @@ -183,27 +183,34 @@ true]]> <#/GAPDoc> -<#GAPDoc Label="RightCayleyGraphSemigroup"> +<#GAPDoc Label="RightCayleyDigraph"> - - + + A list of lists of positive integers. When the argument S is a semigroup in the representation , - RightCayleyGraphSemigroup returns the right - Cayley graphs of S, as a list graph where - graph[i][j] is equal to + RightCayleyDigraph returns the right + Cayley graphs of S, as a + digraph where vertex OutNeighbours(digraph)[i][j] is PositionCanonical(S, AsListCanonical(S)[i] * GeneratorsOfSemigroup(S)[j]). - The list returned by LeftCayleyGraphSemigroup is defined analogously. + The digraph returned by LeftCayleyDigraph is defined analogously.

+ + The digraph returned by this attribute belongs to the category + , the semigroup S + and the generators used to create the digraph can be recovered from the + digraph using + and . + S := FullTransformationMonoid(2); -gap> RightCayleyGraphSemigroup(S); -[ [ 1, 2, 3 ], [ 2, 1, 3 ], [ 3, 4, 3 ], [ 4, 3, 3 ] ] -gap> LeftCayleyGraphSemigroup(S); -[ [ 1, 2, 3 ], [ 2, 1, 4 ], [ 3, 3, 3 ], [ 4, 4, 4 ] ]]]> +gap> RightCayleyDigraph(S); + +gap> LeftCayleyDigraph(S); +]]> <#/GAPDoc> diff --git a/doc/z-chap13.xml b/doc/z-chap13.xml index 845f0ddfa..b26612332 100644 --- a/doc/z-chap13.xml +++ b/doc/z-chap13.xml @@ -27,7 +27,7 @@ Cayley graphs - <#Include Label = "RightCayleyGraphSemigroup"> + <#Include Label = "RightCayleyDigraph"> diff --git a/gap/congruences/conginv.gi b/gap/congruences/conginv.gi index ed6673f0e..97b62be44 100644 --- a/gap/congruences/conginv.gi +++ b/gap/congruences/conginv.gi @@ -507,7 +507,7 @@ SEMIGROUPS.KernelTraceClosure := function(S, kernel, traceBlocks, pairstoapply) hashlen := SEMIGROUPS.OptionsRec(S).hashlen.L; ht := HTCreate([1, 1], rec(forflatplainlists := true, treehashsize := hashlen)); - right := RightCayleyGraphSemigroup(idsmgp); + right := OutNeighbours(RightCayleyDigraph(idsmgp)); genstoapply := [1 .. Length(right[1])]; # diff --git a/gap/greens/gree.gi b/gap/greens/gree.gi index c9670f115..e2e758da9 100644 --- a/gap/greens/gree.gi +++ b/gap/greens/gree.gi @@ -391,8 +391,6 @@ function(S) l := LeftCayleyGraphSemigroup(S); r := RightCayleyGraphSemigroup(S); - # WW: in the future, when l and r are digraphs, gr can be created - # by using DigraphEdgeUnion(l, r) gr := Digraph(List([1 .. Length(l)], i -> Concatenation(l[i], r[i]))); gr := QuotientDigraph(gr, DigraphStronglyConnectedComponents(gr).comps); return List(OutNeighbours(gr), Set); diff --git a/gap/greens/gren.gi b/gap/greens/gren.gi index c9043cedc..e3f6f1c29 100644 --- a/gap/greens/gren.gi +++ b/gap/greens/gren.gi @@ -225,19 +225,19 @@ end); InstallMethod(GreensRRelation, "for an enumerable semigroup", [IsEnumerableSemigroupRep], function(S) - local fam, rel; + local fam, data, rel; if IsActingSemigroup(S) then TryNextMethod(); fi; fam := GeneralMappingsFamily(ElementsFamily(FamilyObj(S)), ElementsFamily(FamilyObj(S))); - + data := DigraphStronglyConnectedComponents(RightCayleyDigraph(S)); rel := Objectify(NewType(fam, IsEquivalenceRelation and IsEquivalenceRelationDefaultRep and IsGreensRRelation and IsEnumerableSemigroupGreensRelationRep), - rec(data := GABOW_SCC(RightCayleyGraphSemigroup(S)))); + rec(data := data)); SetSource(rel, S); SetRange(rel, S); SetIsLeftSemigroupCongruence(rel, true); @@ -250,19 +250,19 @@ end); InstallMethod(GreensLRelation, "for an enumerable semigroup", [IsEnumerableSemigroupRep], function(S) - local fam, rel; + local fam, data, rel; if IsActingSemigroup(S) then TryNextMethod(); fi; fam := GeneralMappingsFamily(ElementsFamily(FamilyObj(S)), ElementsFamily(FamilyObj(S))); - + data := DigraphStronglyConnectedComponents(LeftCayleyDigraph(S)); rel := Objectify(NewType(fam, IsEquivalenceRelation and IsEquivalenceRelationDefaultRep and IsGreensLRelation and IsEnumerableSemigroupGreensRelationRep), - rec(data := GABOW_SCC(LeftCayleyGraphSemigroup(S)))); + rec(data := data)); SetSource(rel, S); SetRange(rel, S); SetIsRightSemigroupCongruence(rel, true); @@ -514,19 +514,20 @@ InstallMethod(HClassReps, "for a Green's class of an enumerable semigroup", [IsGreensClass and IsEnumerableSemigroupGreensClassRep], C -> SEMIGROUPS.XClassRepsOfClass(C, GreensHRelation)); -## Partial order of D-classes -# There is duplicate code in here and in maximal D-classes +# There is duplicate code in here and in maximal D-classes. +# +# This cannot be replaced with the method for IsSemigroup and IsFinite since +# the value of GreensDRelation(S)!.data.comps is not the same as the output of +# DigraphStronglyConnectedComponents. InstallMethod(PartialOrderOfDClasses, "for a finite enumerable semigroup", [IsEnumerableSemigroupRep and IsFinite], function(S) local l, r, gr; - - l := LeftCayleyGraphSemigroup(S); - r := RightCayleyGraphSemigroup(S); - gr := Digraph(List([1 .. Length(l)], i -> Concatenation(l[i], r[i]))); + l := LeftCayleyDigraph(S); + r := RightCayleyDigraph(S); + gr := DigraphEdgeUnion(l, r); gr := QuotientDigraph(gr, GreensDRelation(S)!.data.comps); - return List(OutNeighbours(gr), Set); end); diff --git a/gap/ideals/idealenum.gi b/gap/ideals/idealenum.gi index 6c44c6f55..9d0423ca9 100644 --- a/gap/ideals/idealenum.gi +++ b/gap/ideals/idealenum.gi @@ -53,8 +53,8 @@ SEMIGROUPS.EnumerateIdeal := function(enum, limit, lookfunc) indices := enum!.indices; S := SupersemigroupOfIdeal(UnderlyingCollection(enum)); - left := LeftCayleyGraphSemigroup(S); - right := RightCayleyGraphSemigroup(S); + left := OutNeighbours(LeftCayleyDigraph(S)); + right := OutNeighbours(RightCayleyDigraph(S)); # FIXME Once the left and right Cayley graphs have been calculated, the # entire data structure of S is known and from this it is relatively easy to # find the entire data structure for I, so there is no point to what follows, diff --git a/gap/main/fropin.gd b/gap/main/fropin.gd index 652fbc604..50efb4a4e 100644 --- a/gap/main/fropin.gd +++ b/gap/main/fropin.gd @@ -48,3 +48,6 @@ DeclareOperation("Enumerate", [IsEnumerableSemigroupRep]); DeclareOperation("IsFullyEnumerated", [IsEnumerableSemigroupRep]); DeclareProperty("IsSemigroupEnumerator", IsEnumeratorByFunctions); + +DeclareAttribute("LeftCayleyDigraph", IsEnumerableSemigroupRep); +DeclareAttribute("RightCayleyDigraph", IsEnumerableSemigroupRep); diff --git a/gap/main/fropin.gi b/gap/main/fropin.gi index 1ea7a73ec..2f34fc836 100644 --- a/gap/main/fropin.gi +++ b/gap/main/fropin.gi @@ -565,11 +565,23 @@ end); InstallMethod(RightCayleyGraphSemigroup, "for an enumerable semigroup rep", [IsEnumerableSemigroupRep], 3, function(S) + return OutNeighbours(RightCayleyDigraph(S)); +end); + +InstallMethod(RightCayleyDigraph, +"for an enumerable semigroup rep", +[IsEnumerableSemigroupRep], +function(S) + local digraph; if not IsFinite(S) then - ErrorNoReturn("Semigroups: RightCayleyGraphSemigroup: usage,\n", + ErrorNoReturn("Semigroups: RightCayleyDigraph: usage,\n", "the first argument (a semigroup) must be finite,"); fi; - return EN_SEMI_RIGHT_CAYLEY_GRAPH(S); + digraph := Digraph(EN_SEMI_RIGHT_CAYLEY_GRAPH(S)); + SetFilterObj(digraph, IsCayleyDigraph); + SetSemigroupOfCayleyDigraph(digraph, S); + SetGeneratorsOfCayleyDigraph(digraph, GeneratorsOfSemigroup(S)); + return digraph; end); # same method for ideals @@ -578,11 +590,23 @@ InstallMethod(LeftCayleyGraphSemigroup, "for an enumerable semigroup rep", [IsEnumerableSemigroupRep], 3, function(S) + return OutNeighbours(LeftCayleyDigraph(S)); +end); + +InstallMethod(LeftCayleyDigraph, +"for an enumerable semigroup rep", +[IsEnumerableSemigroupRep], +function(S) + local digraph; if not IsFinite(S) then - ErrorNoReturn("Semigroups: LeftCayleyGraphSemigroup: usage,\n", + ErrorNoReturn("Semigroups: LeftCayleyDigraph: usage,\n", "the first argument (a semigroup) must be finite,"); fi; - return EN_SEMI_LEFT_CAYLEY_GRAPH(S); + digraph := Digraph(EN_SEMI_LEFT_CAYLEY_GRAPH(S)); + SetFilterObj(digraph, IsCayleyDigraph); + SetSemigroupOfCayleyDigraph(digraph, S); + SetGeneratorsOfCayleyDigraph(digraph, GeneratorsOfSemigroup(S)); + return digraph; end); InstallMethod(MultiplicationTable, "for an enumerable semigroup", diff --git a/gap/semigroups/grpperm.gi b/gap/semigroups/grpperm.gi index a1d4a4389..e18a101e9 100644 --- a/gap/semigroups/grpperm.gi +++ b/gap/semigroups/grpperm.gi @@ -156,7 +156,7 @@ function(S) "IsGroupAsSemigroup,"); fi; - cay := RightCayleyGraphSemigroup(S); + cay := OutNeighbours(RightCayleyDigraph(S)); deg := Size(S); gen := []; diff --git a/gap/semigroups/semifp.gi b/gap/semigroups/semifp.gi index 19c1ad0bb..73338d299 100644 --- a/gap/semigroups/semifp.gi +++ b/gap/semigroups/semifp.gi @@ -92,7 +92,7 @@ function(x1, x2) return x1 ^ map < x2 ^ map; end); -#TODO AsSSortedList, RightCayleyGraph, any more? +#TODO AsSSortedList, RightCayleyDigraph, any more? InstallMethod(ViewString, "for an f.p. semigroup element", [IsElementOfFpSemigroup], String); diff --git a/gap/semigroups/semitrans.gi b/gap/semigroups/semitrans.gi index 540bfebc0..3852acfbe 100644 --- a/gap/semigroups/semitrans.gi +++ b/gap/semigroups/semitrans.gi @@ -853,12 +853,12 @@ function(S) local cay, deg, gen, next, T, iso, inv, i; if not IsFinite(S) then - # This is unreachable in tests, since there is not other method that + # This is unreachable in tests, since there is no other method that # terminates TryNextMethod(); fi; - cay := RightCayleyGraphSemigroup(S); + cay := OutNeighbours(RightCayleyDigraph(S)); deg := Size(S); gen := []; @@ -897,7 +897,7 @@ function(S) TryNextMethod(); fi; - cay := RightCayleyGraphSemigroup(S); + cay := OutNeighbours(RightCayleyDigraph(S)); deg := Size(S); gen := EmptyPlist(Length(cay[1])); diff --git a/src/fropin.cc b/src/fropin.cc index a93902c23..730ffe440 100644 --- a/src/fropin.cc +++ b/src/fropin.cc @@ -338,9 +338,9 @@ Obj fropin(Obj obj, Obj limit, Obj lookfunc, Obj looking) { return data; } -// Using the output of GABOW_SCC on the right and left Cayley graphs of a -// semigroup, the following function calculates the strongly connected -// components of the union of these two graphs. +// Using the output of DigraphStronglyConnectedComponents on the right and left +// Cayley graphs of a semigroup, the following function calculates the strongly +// connected components of the union of these two graphs. Obj SCC_UNION_LEFT_RIGHT_CAYLEY_GRAPHS(Obj self, Obj scc1, Obj scc2) { UInt* ptr; @@ -416,9 +416,9 @@ Obj SCC_UNION_LEFT_RIGHT_CAYLEY_GRAPHS(Obj self, Obj scc1, Obj scc2) { } // and should be scc data structures for the right and left -// Cayley graphs of a semigroup, as produced by GABOW_SCC. This function find -// the H-classes of the semigroup from and . The method used is -// that described in: +// Cayley graphs of a semigroup, as produced by +// DigraphStronglyConnectedComponents. This function find the H-classes of the +// semigroup from and . The method used is that described in: // http://www.liafa.jussieu.fr/~jep/PDF/Exposes/StAndrews.pdf Obj FIND_HCLASSES(Obj self, Obj right, Obj left) { diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst index 56a452a3f..49c0378ee 100644 --- a/tst/standard/attr.tst +++ b/tst/standard/attr.tst @@ -342,22 +342,23 @@ gap> Size(MinimalDClass(s)); gap> MultiplicativeZero(s); Transformation( [ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ] ) -#T# attr: RightCayleyGraphSemigroup +#T# attr: RightCayleyDigraph gap> S := Semigroup(PartialPerm([1, 2, 3], [1, 3, 4]), > PartialPerm([1, 2, 3], [2, 5, 3]), > PartialPerm([1, 2, 3], [4, 1, 2]), > PartialPerm([1, 2, 3, 4], [2, 4, 1, 5]), > PartialPerm([1, 3, 5], [5, 1, 3]));; -gap> RightCayleyGraphSemigroup(S);; -gap> Length(STRONGLY_CONNECTED_COMPONENTS_DIGRAPH(last)) = NrRClasses(S); +gap> digraph := RightCayleyDigraph(S);; +gap> Length(DigraphStronglyConnectedComponents(digraph).comps) +> = NrRClasses(S); true -#T# attr: RightCayleyGraphSemigroup, infinite -gap> RightCayleyGraphSemigroup(FreeSemigroup(2)); +#T# attr: RightCayleyDigraph, infinite +gap> RightCayleyDigraph(FreeSemigroup(2)); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 2nd choice method found for `CayleyGraphSemigroup' on 1 arguments +Error, no 1st choice method found for `RightCayleyDigraph' on 1 arguments -#T# attr: LeftCayleyGraphSemigroup +#T# attr: LeftCayleyDigraph gap> S := Monoid(BooleanMat([[1, 1, 1, 1, 1], [1, 0, 1, 0, 0], > [1, 1, 0, 1, 0], [1, 1, 1, 1, 1], > [1, 1, 0, 0, 0]]), @@ -373,15 +374,15 @@ gap> S := Monoid(BooleanMat([[1, 1, 1, 1, 1], [1, 0, 1, 0, 0], > BooleanMat([[1, 0, 0, 0, 1], [1, 0, 0, 0, 1], > [0, 0, 0, 0, 1], [0, 1, 1, 0, 1], > [1, 1, 1, 0, 1]]));; -gap> LeftCayleyGraphSemigroup(S);; -gap> Length(STRONGLY_CONNECTED_COMPONENTS_DIGRAPH(last)) = NrLClasses(S); +gap> digraph := LeftCayleyDigraph(S);; +gap> Length(DigraphStronglyConnectedComponents(digraph).comps) +> = NrLClasses(S); true -#T# attr: RightCayleyGraphSemigroup, infinite -gap> LeftCayleyGraphSemigroup(FreeInverseSemigroup(2)); +#T# attr: RightCayleyDigraph, infinite +gap> LeftCayleyDigraph(FreeInverseSemigroup(2)); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 2nd choice method found for `CayleyGraphDualSemigroup' on 1 argument\ -s +Error, no 1st choice method found for `LeftCayleyDigraph' on 1 arguments #T# attr: IsomorphismReesMatrixSemigroup gap> D := GreensDClassOfElement(Semigroup( diff --git a/tst/standard/fropin.tst b/tst/standard/fropin.tst index 67c0e43d2..4faa8c9c4 100644 --- a/tst/standard/fropin.tst +++ b/tst/standard/fropin.tst @@ -416,15 +416,36 @@ gap> PositionSorted(S, S.1); Error, Semigroups: PositionSortedOp: usage, the first argument (a semigroup) must be finite, -# Left/RightCayleyGraphSemigroup, for an infinite enumerable semigroup +# Left/RightCayleyDigraph, for an infinite enumerable semigroup gap> S := Semigroup(Matrix(IsMaxPlusMatrix, [[-2, 2], [0, -1]]));; -gap> RightCayleyGraphSemigroup(S); -Error, Semigroups: RightCayleyGraphSemigroup: usage, +gap> RightCayleyDigraph(S); +Error, Semigroups: RightCayleyDigraph: usage, the first argument (a semigroup) must be finite, -gap> LeftCayleyGraphSemigroup(S); -Error, Semigroups: LeftCayleyGraphSemigroup: usage, +gap> LeftCayleyDigraph(S); +Error, Semigroups: LeftCayleyDigraph: usage, the first argument (a semigroup) must be finite, +# Left/RightCayleyGraphSemigroup +gap> S := Semigroup(FullTransformationMonoid(3));; +gap> LeftCayleyGraphSemigroup(S); +[ [ 1, 2, 3, 4 ], [ 2, 5, 8, 9 ], [ 3, 6, 1, 10 ], [ 4, 7, 7, 4 ], + [ 5, 1, 6, 14 ], [ 6, 8, 5, 15 ], [ 7, 11, 4, 10 ], [ 8, 3, 2, 16 ], + [ 9, 12, 12, 9 ], [ 10, 13, 13, 10 ], [ 11, 4, 11, 22 ], [ 12, 17, 9, 16 ], + [ 13, 18, 10, 4 ], [ 14, 19, 19, 14 ], [ 15, 20, 20, 15 ], + [ 16, 21, 21, 16 ], [ 17, 9, 17, 26 ], [ 18, 10, 18, 26 ], + [ 19, 23, 14, 15 ], [ 20, 24, 15, 14 ], [ 21, 25, 16, 9 ], + [ 22, 22, 22, 22 ], [ 23, 14, 23, 27 ], [ 24, 15, 24, 22 ], + [ 25, 16, 25, 27 ], [ 26, 26, 26, 26 ], [ 27, 27, 27, 27 ] ] +gap> RightCayleyGraphSemigroup(S); +[ [ 1, 2, 3, 4 ], [ 2, 5, 6, 7 ], [ 3, 8, 1, 7 ], [ 4, 9, 10, 4 ], + [ 5, 1, 8, 11 ], [ 6, 3, 2, 11 ], [ 7, 12, 13, 7 ], [ 8, 6, 5, 4 ], + [ 9, 14, 15, 10 ], [ 10, 16, 4, 10 ], [ 11, 17, 18, 11 ], + [ 12, 19, 20, 13 ], [ 13, 21, 7, 13 ], [ 14, 4, 16, 22 ], [ 15, 10, 9, 22 ], + [ 16, 15, 14, 4 ], [ 17, 23, 24, 18 ], [ 18, 25, 11, 18 ], + [ 19, 7, 21, 22 ], [ 20, 13, 12, 22 ], [ 21, 20, 19, 7 ], + [ 22, 26, 26, 22 ], [ 23, 11, 25, 22 ], [ 24, 18, 17, 22 ], + [ 25, 24, 23, 11 ], [ 26, 27, 22, 26 ], [ 27, 22, 27, 22 ] ] + # AsSet, for an infinite enumerable semigroup gap> S := Semigroup(Matrix(IsMaxPlusMatrix, [[-2, 2], [0, -1]]));; gap> AsSet(S); diff --git a/tst/standard/gren.tst b/tst/standard/gren.tst index 6b070547c..81525e3da 100644 --- a/tst/standard/gren.tst +++ b/tst/standard/gren.tst @@ -1670,16 +1670,16 @@ gap> GreensLClasses(D); # Test GreensXClasses for an infinite enumerable semigroup gap> S := Semigroup(Matrix(IsMaxPlusMatrix, [[0, 2], [-1, 0]]));; gap> GreensLClasses(S); -Error, Semigroups: LeftCayleyGraphSemigroup: usage, +Error, Semigroups: LeftCayleyDigraph: usage, the first argument (a semigroup) must be finite, gap> GreensRClasses(S); -Error, Semigroups: RightCayleyGraphSemigroup: usage, +Error, Semigroups: RightCayleyDigraph: usage, the first argument (a semigroup) must be finite, gap> GreensHClasses(S); -Error, Semigroups: LeftCayleyGraphSemigroup: usage, +Error, Semigroups: LeftCayleyDigraph: usage, the first argument (a semigroup) must be finite, gap> GreensDClasses(S); -Error, Semigroups: LeftCayleyGraphSemigroup: usage, +Error, Semigroups: LeftCayleyDigraph: usage, the first argument (a semigroup) must be finite, gap> GreensJClasses(S); Error, no method found! For debugging hints type ?Recovery from NoMethodFound From 0a0adc9d29b7518f39238f154b3b43fd4ed6d694 Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Wed, 12 Jul 2017 18:35:18 +0100 Subject: [PATCH 3/3] display: add methods for drawing Cayley graphs Using dot or tikz, for digraphs and semigroups. --- doc/display.xml | 108 ++++++++++++++++++++++++++++++++++++++- doc/z-chap18.xml | 3 ++ gap/tools/display.gd | 6 +++ gap/tools/display.gi | 98 +++++++++++++++++++++++++++++++++++ tst/standard/display.tst | 56 ++++++++++++++++++++ 5 files changed, 269 insertions(+), 2 deletions(-) diff --git a/doc/display.xml b/doc/display.xml index eb0e40e07..4138f54b9 100644 --- a/doc/display.xml +++ b/doc/display.xml @@ -127,8 +127,23 @@ pbrs - If obj is a PBR, then TikzString returns a graphical - representation obj; see Section . + If obj is a , then TikzString returns a + graphical representation obj; see Chapter . + + Cayley graphs + + If obj is a in the + category , then + TikzString returns a picture of obj. No attempt is made + whatsoever to produce a sensible picture of the digraph obj, + in fact, the vertices are all given the same coordinates. Human + intervention is required to produce a meaningful picture from the + value returned by this method. It is intended to make the task of + drawing such a Cayley graph more straightforward by providing + everything except the final layout of the graph. Please use if you want an automatically laid out diagram of + the digraph obj. @@ -288,6 +303,29 @@ gap> FileString("t3.dot", DotString(S)); <#/GAPDoc> +<#GAPDoc Label="DotStringDigraph"> + + + A string. + + If digraph is a in the + category , then + DotString returns a graphical representation of digraph. + The output is in dot format (also known + as GraphViz) format. For details about this file format, and + information about how to display or edit this format see + http://www.graphviz.org. +

+ + The string returned by DotString can be written to a file using + the command .

+ + See also and . + + +<#/GAPDoc> + <#GAPDoc Label="DotSemilatticeOfIdempotents"> @@ -341,3 +379,69 @@ d{pmatrix}"]]> <#/GAPDoc> + +<#GAPDoc Label="TikzLeftCayleyDigraph"> + + + + A string. + + If S is a semigroup in the representation + , then TikzLeftCayleyDigraph + is simply short for TikzString(LeftCayleyDigraph(S)).

+ + TikzRightCayleyDigraph can be used to produce a tikz string for + the right Cayley graph of S.

+ + See for more details, and see also + . + + TikzLeftCayleyDigraph(Semigroup(IdentityTransformation)); +"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={c\ +ircle, draw, thick, fill=white, minimum size=0.65cm},\n \ +edge/.style={arrows={-angle 90}, thick},\n loop/.style={\ +min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\ +\n % Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\ +\n \\node at (0, 0) {$a$};\n\n % Edges . . .\n \\path[\ +->] (a) edge [loop]\n node {$a$} (a);\n\\end{ti\ +kzpicture}" +gap> TikzRightCayleyDigraph(Semigroup(IdentityTransformation)); +"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={c\ +ircle, draw, thick, fill=white, minimum size=0.65cm},\n \ +edge/.style={arrows={-angle 90}, thick},\n loop/.style={\ +min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\ +\n % Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\ +\n \\node at (0, 0) {$a$};\n\n % Edges . . .\n \\path[\ +->] (a) edge [loop]\n node {$a$} (a);\n\\end{ti\ +kzpicture}"]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DotLeftCayleyDigraph"> + + + + A string. + + If S is a semigroup in the representation , then DotLeftCayleyDigraph is + simply short for DotString(LeftCayleyDigraph(S)).

+ + DotRightCayleyDigraph can be used to produce a dot string for + the right Cayley graph of S.

+ + See for more details, and see also + . + + DotLeftCayleyDigraph(Semigroup(IdentityTransformation)); +"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n1 -> 1\n}\ +\n" +gap> DotRightCayleyDigraph(Semigroup(IdentityTransformation)); +"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n1 -> 1\n}\ +\n"]]> + + +<#/GAPDoc> diff --git a/doc/z-chap18.xml b/doc/z-chap18.xml index 888d48680..d14e6eac0 100644 --- a/doc/z-chap18.xml +++ b/doc/z-chap18.xml @@ -46,7 +46,9 @@ BookName = "GAPDoc"/> or viewed using . <#Include Label = "DotString"/> + <#Include Label = "DotStringDigraph"/> <#Include Label = "DotSemilatticeOfIdempotents"/> + <#Include Label = "DotLeftCayleyDigraph"> @@ -81,6 +83,7 @@ BookName = "GAPDoc"/> or viewed using . <#Include Label = "TikzString"> + <#Include Label = "TikzLeftCayleyDigraph"> diff --git a/gap/tools/display.gd b/gap/tools/display.gd index 6052fc503..d66478b1c 100644 --- a/gap/tools/display.gd +++ b/gap/tools/display.gd @@ -15,4 +15,10 @@ DeclareOperation("DotString", [IsObject, IsRecord]); DeclareOperation("TexString", [IsObject]); DeclareOperation("TexString", [IsObject, IsObject]); +DeclareOperation("TikzLeftCayleyDigraph", [IsSemigroup]); +DeclareOperation("TikzRightCayleyDigraph", [IsSemigroup]); + +DeclareOperation("DotLeftCayleyDigraph", [IsSemigroup]); +DeclareOperation("DotRightCayleyDigraph", [IsSemigroup]); + DeclareAttribute("DotSemilatticeOfIdempotents", IsInverseSemigroup); diff --git a/gap/tools/display.gi b/gap/tools/display.gi index 4b61d2c1e..50eda6112 100644 --- a/gap/tools/display.gi +++ b/gap/tools/display.gi @@ -735,3 +735,101 @@ function(coll) deg := DegreeOfTransformationCollection(coll); return JoinStringsWithSeparator(List(coll, x -> TexString(x, deg)), "\n"); end); + +InstallMethod(TikzLeftCayleyDigraph, "for a semigroup", [IsSemigroup], +function(S) + return TikzString(LeftCayleyDigraph(S)); +end); + +InstallMethod(TikzRightCayleyDigraph, "for a semigroup", [IsSemigroup], +function(S) + return TikzString(RightCayleyDigraph(S)); +end); + +InstallMethod(TikzString, "for a Cayley digraph", [IsCayleyDigraph], +function(digraph) + local S, vertex, edge, str, nbs, x, from, gen; + + S := SemigroupOfCayleyDigraph(digraph); + if not IsEnumerableSemigroupRep(S) or Size(S) > 26 then + TryNextMethod(); + fi; + + vertex := function(x) + local word, name, label; + word := MinimalFactorization(S, x); + name := SEMIGROUPS.WordToString(word); + label := SEMIGROUPS.ExtRepObjToString(SEMIGROUPS.WordToExtRepObj(word)); + return Concatenation(" \\node [vertex] (", name, ") at (0, 0) {};\n", + " \\node at (0, 0) {$", label, "$};\n\n"); + end; + + edge := function(from, to, gen) + local word; + word := MinimalFactorization(S, AsListCanonical(S)[from]); + from := SEMIGROUPS.WordToString(word); + word := MinimalFactorization(S, AsListCanonical(S)[to]); + to := SEMIGROUPS.WordToString(word); + gen := SEMIGROUPS.WordToString([gen]); + if from <> to then + return Concatenation(" \\path[->] (", from, + ") edge [edge] node {$", gen, "$} (", + to, ");\n"); + else + return Concatenation(" \\path[->] (", from, + ") edge [loop]\n", + " node {$", gen, "$} (", to, ");\n"); + fi; + end; + + str := ""; + + Append(str, "\\begin{tikzpicture}[scale=1, auto, \n"); + Append(str, " vertex/.style={circle, draw, thick, fill=white, minimum"); + Append(str, " size=0.65cm},\n"); + Append(str, " edge/.style={arrows={-angle 90}, thick},\n"); + Append(str, " loop/.style={min distance=5mm,looseness=5,"); + Append(str, "arrows={-angle 90},thick}]\n\n"); + + Append(str, " % Vertices . . .\n"); + for x in AsListCanonical(S) do + Append(str, vertex(x)); + od; + + Append(str, " % Edges . . .\n"); + nbs := OutNeighbours(digraph); + for from in [1 .. Size(S)] do + for gen in [1 .. Size(nbs[from])] do + Append(str, edge(from, nbs[from][gen], gen)); + od; + od; + + Append(str, "\\end{tikzpicture}"); + return str; +end); + +InstallMethod(DotString, "for a Cayley digraph", [IsCayleyDigraph], +function(digraph) + local S, li, label, i; + S := SemigroupOfCayleyDigraph(digraph); + if not IsEnumerableSemigroupRep(S) or Size(S) > 26 then + TryNextMethod(); + fi; + li := AsListCanonical(S); + for i in [1 .. Size(S)] do + label := SEMIGROUPS.WordToExtRepObj(MinimalFactorization(S, li[i])); + label := SEMIGROUPS.ExtRepObjToString(label); + SetDigraphVertexLabel(digraph, i, label); + od; + return DotVertexLabelledDigraph(digraph); +end); + +InstallMethod(DotLeftCayleyDigraph, "for a semigroup", [IsSemigroup], +function(S) + return DotString(LeftCayleyDigraph(S)); +end); + +InstallMethod(DotRightCayleyDigraph, "for a semigroup", [IsSemigroup], +function(S) + return DotString(RightCayleyDigraph(S)); +end); diff --git a/tst/standard/display.tst b/tst/standard/display.tst index dd6bf3a2a..e291c1193 100644 --- a/tst/standard/display.tst +++ b/tst/standard/display.tst @@ -724,6 +724,62 @@ Error, Semigroups: TexString: usage, the second argument (the degree) should be at least the degree of the first ar\ gument (a transformation), +# Tikz/DotLeft/RightCayleyDigraph +gap> TikzLeftCayleyDigraph(FullTransformationMonoid(2)); +"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={circle, draw, thick, f\ +ill=white, minimum size=0.65cm},\n edge/.style={arrows={-angle 90}, thick},\n\ + loop/.style={min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\n % \ +Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\n \\node at (0, 0) {$a$};\ +\n\n \\node [vertex] (b) at (0, 0) {};\n \\node at (0, 0) {$b$};\n\n \\node\ + [vertex] (c) at (0, 0) {};\n \\node at (0, 0) {$c$};\n\n \\node [vertex] (c\ +b) at (0, 0) {};\n \\node at (0, 0) {$cb$};\n\n % Edges . . .\n \\path[->] \ +(a) edge [loop]\n node {$a$} (a);\n \\path[->] (a) edge [edge] node\ + {$b$} (b);\n \\path[->] (a) edge [edge] node {$c$} (c);\n \\path[->] (b) ed\ +ge [loop]\n node {$a$} (b);\n \\path[->] (b) edge [edge] node {$b$}\ + (a);\n \\path[->] (b) edge [edge] node {$c$} (cb);\n \\path[->] (c) edge [l\ +oop]\n node {$a$} (c);\n \\path[->] (c) edge [loop]\n nod\ +e {$b$} (c);\n \\path[->] (c) edge [loop]\n node {$c$} (c);\n \\pa\ +th[->] (cb) edge [loop]\n node {$a$} (cb);\n \\path[->] (cb) edge [\ +loop]\n node {$b$} (cb);\n \\path[->] (cb) edge [loop]\n \ +node {$c$} (cb);\n\\end{tikzpicture}" +gap> TikzRightCayleyDigraph(FullTransformationMonoid(2)); +"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={circle, draw, thick, f\ +ill=white, minimum size=0.65cm},\n edge/.style={arrows={-angle 90}, thick},\n\ + loop/.style={min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\n % \ +Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\n \\node at (0, 0) {$a$};\ +\n\n \\node [vertex] (b) at (0, 0) {};\n \\node at (0, 0) {$b$};\n\n \\node\ + [vertex] (c) at (0, 0) {};\n \\node at (0, 0) {$c$};\n\n \\node [vertex] (c\ +b) at (0, 0) {};\n \\node at (0, 0) {$cb$};\n\n % Edges . . .\n \\path[->] \ +(a) edge [loop]\n node {$a$} (a);\n \\path[->] (a) edge [edge] node\ + {$b$} (b);\n \\path[->] (a) edge [edge] node {$c$} (c);\n \\path[->] (b) ed\ +ge [loop]\n node {$a$} (b);\n \\path[->] (b) edge [edge] node {$b$}\ + (a);\n \\path[->] (b) edge [edge] node {$c$} (c);\n \\path[->] (c) edge [lo\ +op]\n node {$a$} (c);\n \\path[->] (c) edge [edge] node {$b$} (cb);\ +\n \\path[->] (c) edge [loop]\n node {$c$} (c);\n \\path[->] (cb) \ +edge [loop]\n node {$a$} (cb);\n \\path[->] (cb) edge [edge] node {\ +$b$} (c);\n \\path[->] (cb) edge [edge] node {$c$} (c);\n\\end{tikzpicture}" +gap> DotRightCayleyDigraph(FullTransformationMonoid(2)); +"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n2 [label=\"b\"]\n3\ + [label=\"c\"]\n4 [label=\"cb\"]\n1 -> 1\n1 -> 2\n1 -> 3\n2 -> 2\n2 -> 1\n2 ->\ + 3\n3 -> 3\n3 -> 4\n3 -> 3\n4 -> 4\n4 -> 3\n4 -> 3\n}\n" +gap> DotLeftCayleyDigraph(FullTransformationMonoid(2)); +"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n2 [label=\"b\"]\n3\ + [label=\"c\"]\n4 [label=\"cb\"]\n1 -> 1\n1 -> 2\n1 -> 3\n2 -> 2\n2 -> 1\n2 ->\ + 4\n3 -> 3\n3 -> 3\n3 -> 3\n4 -> 4\n4 -> 4\n4 -> 4\n}\n" +gap> S := LeftZeroSemigroup(27);; +gap> DotLeftCayleyDigraph(S); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 2nd choice method found for `DotString' on 1 arguments +gap> TikzLeftCayleyDigraph(S); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 2nd choice method found for `TikzString' on 1 arguments +gap> DotRightCayleyDigraph(S); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 2nd choice method found for `DotString' on 1 arguments +gap> TikzRightCayleyDigraph(S); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 2nd choice method found for `TikzString' on 1 arguments + # gap> SEMIGROUPS.StopTest(); gap> STOP_TEST("Semigroups package: standard/display.tst");