diff --git a/doc/semigraph.xml b/doc/semigraph.xml index 802ab7ef6..3a5801118 100644 --- a/doc/semigraph.xml +++ b/doc/semigraph.xml @@ -274,14 +274,19 @@ gap> IndexOfVertexOfGraphInverseSemigroup(v_3); <#/GAPDoc> -<#GAPDoc Label="LeftOne"> +<#GAPDoc Label="LeftRightOne"> + A graph inverse semigroup element. LeftOne(x) returns the unique idempotent e such that e * x = x and e and x are related by Green's &R;-relation. + + RightOne(x) returns the unique idempotent + e such that x * e = x and + e and x are related by Green's &L;-relation. S := GraphInverseSemigroup(ChainDigraph(3)); @@ -291,28 +296,75 @@ gap> LeftOne(x); e_1e_2e_2^-1e_1^-1 gap> LeftOne(x) * x = x; true +gap> RightOne(x); +v_3 +gap> x * RightOne(x) = x; +true ]]> <#/GAPDoc> -<#GAPDoc Label="RightOne"> +<#GAPDoc Label="EdgesPathsWithRangeSource"> - + + + + + A list of graph inverse semigroup elements. + + If x is an element of a finite graph inverse semigroup (i.e. + it satisfies ), then the + attributes EdgesWithRange(x) and + EdgesWithSource(x) return a list of all edges e + such that Range(e)=x and Source(e)=x + respectively. + + If x is an element of a finite graph inverse semigroup (i.e. + it satisfies ), then the + operations PathsWithRange(x) and + PathsWithSource(x) return a list of all paths (products + of edges) p such that Range(p)=x and + Source(p)=x respectively. + D := Digraph([[2, 3], [3, 4], [4], []]); + +gap> S := GraphInverseSemigroup(D); + +gap> EdgesWithRange(VerticesOfGraphInverseSemigroup(S)[4]); +[ e_4, e_5 ] +gap> EdgesWithSource(VerticesOfGraphInverseSemigroup(S)[2]); +[ e_3, e_4 ] +gap> PathsWithRange(VerticesOfGraphInverseSemigroup(S)[4]); +[ v_4, e_4, e_1e_4, e_5, e_2e_5, e_3e_5, e_1e_3e_5 ] +gap> PathsWithSource(VerticesOfGraphInverseSemigroup(S)[2]); +[ v_2, e_3, e_3e_5, e_4 ] +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="PositiveNegativePath"> + + + A graph inverse semigroup element. - RightOne(x) returns the unique idempotent - e such that x * e = x and - e and x are related by Green's &L;-relation. + All non-zero elements of a graph inverse semigroup can be written in the + form pq^*, where p and q are paths (products of + edges). If x is a non-zero element of a graph inverse semigroup, + then PositivePath(x) and NegativePath(x) + return the path p and ghost path q* respectively, while if + x is the zero element then both return x. S := GraphInverseSemigroup(ChainDigraph(3)); -gap> x := S.1 * S.2; +gap> x := S.1 * S.2 * S.2 ^ -1; +e_1e_2e_2^-1 +gap> PositivePath(x); e_1e_2 -gap> RightOne(x); -v_3 -gap> x * RightOne(x) = x; -true +gap> NegativePath(x); +e_2^-1 ]]> diff --git a/doc/z-chap07.xml b/doc/z-chap07.xml index 426f890cf..2d363a7bc 100644 --- a/doc/z-chap07.xml +++ b/doc/z-chap07.xml @@ -248,8 +248,9 @@ <#Include Label = "IsGraphInverseSubsemigroup"> <#Include Label = "VerticesOfGraphInverseSemigroup"> <#Include Label = "IndexOfVertexOfGraphInverseSemigroup"> - <#Include Label = "LeftOne"> - <#Include Label = "RightOne"> + <#Include Label = "LeftRightOne"> + <#Include Label = "EdgesPathsWithRangeSource"> + <#Include Label = "PositiveNegativePath"> diff --git a/gap/semigroups/semigraph.gd b/gap/semigroups/semigraph.gd index 69de98a70..7d3c471fc 100644 --- a/gap/semigroups/semigraph.gd +++ b/gap/semigroups/semigraph.gd @@ -27,6 +27,9 @@ DeclareAttribute("Source", IsGraphInverseSemigroupElement); DeclareOperation("IsVertex", [IsGraphInverseSemigroupElement]); +DeclareAttribute("PositivePath", IsGraphInverseSemigroupElement); +DeclareAttribute("NegativePath", IsGraphInverseSemigroupElement); + InstallTrueMethod(IsGeneratorsOfInverseSemigroup, IsGraphInverseSemigroupElementCollection); @@ -41,3 +44,8 @@ DeclareAttribute("VerticesOfGraphInverseSemigroup", IsGraphInverseSemigroup); DeclareAttribute("EdgesOfGraphInverseSemigroup", IsGraphInverseSemigroup); + +DeclareAttribute("EdgesWithRange", IsGraphInverseSemigroupElement); +DeclareAttribute("EdgesWithSource", IsGraphInverseSemigroupElement); +DeclareOperation("PathsWithRange", [IsGraphInverseSemigroupElement]); +DeclareOperation("PathsWithSource", [IsGraphInverseSemigroupElement]); diff --git a/gap/semigroups/semigraph.gi b/gap/semigroups/semigraph.gi index 8009e7e26..c71231b76 100644 --- a/gap/semigroups/semigraph.gi +++ b/gap/semigroups/semigraph.gi @@ -299,9 +299,11 @@ end); InstallMethod(EdgesOfGraphInverseSemigroup, "for a graph inverse semigroup", [IsGraphInverseSemigroup], -S -> Difference(GeneratorsOfInverseSemigroup(S), -Concatenation([MultiplicativeZero(S)], -VerticesOfGraphInverseSemigroup(S)))); +function(S) + local D; + D := GraphOfGraphInverseSemigroup(S); + return List([1 .. DigraphNrEdges(D)], i -> GeneratorsOfSemigroup(S)[i]); +end); InstallMethod(IndexOfVertexOfGraphInverseSemigroup, "for a graph inverse semigroup element", @@ -327,3 +329,113 @@ InstallMethod(RightOne, "for a graph inverse semigroup element", [IsGraphInverseSemigroupElement], x -> x ^ -1 * x); + +InstallMethod(PositivePath, +"for a graph inverse semigroup element", +[IsGraphInverseSemigroupElement], +function(elt) + local pos, S; + + pos := PositionProperty(elt![1], IsNegInt); + # elt![1] is the list of all edges and ghost edges that form elt. pos is the + # position of the first negative edge, i.e. the edges up to pos form the + # positive path. + if pos = fail then + # no negative edges so the positive path is all of x or x is the zero + return elt; + elif pos = 1 then + # no positive edges so the positive path is just a vertex + return Source(elt); + fi; + # Get the semigroup containing "elt" + S := FamilyObj(elt)!.semigroup; + # product of all positive edges in elt is the positive path + return EvaluateWord(GeneratorsOfSemigroup(S), elt![1]{[1 .. pos - 1]}); +end); + +InstallMethod(NegativePath, +"for a graph inverse semigroup element", +[IsGraphInverseSemigroupElement], +elt -> PositivePath(elt ^ -1) ^ -1); + +InstallMethod(IsIsomorphicSemigroup, +"for two graph inverse semigroups", +[IsGraphInverseSemigroup, IsGraphInverseSemigroup], + # two graph inverse semigroups are isomorphic if and only if their underlying + # graphs are isomorphic +{G1, G2} -> IsIsomorphicDigraph(GraphOfGraphInverseSemigroup(G1), + GraphOfGraphInverseSemigroup(G2))); + +InstallMethod(EdgesWithRange, +"for a graph inverse semigroup element", +[IsGraphInverseSemigroupElement], +function(x) + local G; + G := FamilyObj(x)!.semigroup; + if not IsVertex(x) then + return []; + elif not IsFinite(EdgesOfGraphInverseSemigroup(G)) then + ErrorNoReturn("the graph inverse semigroup containing the argument", + "(element) must have a finite number of edges!"); + fi; + return List(Positions(DigraphRange(GraphOfGraphInverseSemigroup(G)), + IndexOfVertexOfGraphInverseSemigroup(x)), + i -> GeneratorsOfSemigroup(G)[i]); +end); + +InstallMethod(PathsWithRange, +"for a graph inverse semigroup element", +[IsGraphInverseSemigroupElement], +function(x) + local inPaths, e, G; + G := FamilyObj(x)!.semigroup; + if not IsFinite(G) then + ErrorNoReturn("the graph inverse semigroup containing the argument", + "(element) must be finite"); + elif not IsVertex(x) then + return []; + fi; + inPaths := [x]; + # recursively find all paths leading into all inneighbours to find all + # inpaths + for e in EdgesWithRange(x) do + Append(inPaths, List(PathsWithRange(Source(e)), p -> p * e)); + od; + return inPaths; +end); + +InstallMethod(EdgesWithSource, +"for a graph inverse semigroup element", +[IsGraphInverseSemigroupElement], +function(x) + local G; + G := FamilyObj(x)!.semigroup; + if not IsVertex(x) then + return []; + elif not IsFinite(EdgesOfGraphInverseSemigroup(G)) then + ErrorNoReturn("the graph inverse semigroup containing the argument", + "(element) must have a finite number of edges!"); + fi; + return List(Positions(DigraphSource(GraphOfGraphInverseSemigroup(G)), + IndexOfVertexOfGraphInverseSemigroup(x)), + i -> GeneratorsOfSemigroup(G)[i]); +end); + +InstallMethod(PathsWithSource, +"for a graph inverse semigroup element", +[IsGraphInverseSemigroupElement], +function(x) + local outPaths, e, G; + G := FamilyObj(x)!.semigroup; + if not IsFinite(G) then + ErrorNoReturn("the graph inverse semigroup containing the argument", + "(element) must be finite"); + elif not IsVertex(x) then + return []; + fi; + outPaths := [x]; + for e in EdgesWithSource(x) do + Append(outPaths, List(PathsWithSource(Range(e)), p -> e * p)); + od; + return outPaths; +end); diff --git a/tst/standard/semigroups/semigraph.tst b/tst/standard/semigroups/semigraph.tst index 31cd51a7e..394cc4719 100644 --- a/tst/standard/semigroups/semigraph.tst +++ b/tst/standard/semigroups/semigraph.tst @@ -8,8 +8,7 @@ ############################################################################# ## -#@local D, DigraphNrVertices, DigraphRange, DigraphSource, S, gr, s, x, y -#@local G, H +#@local D, DigraphNrVertices, DigraphRange, DigraphSource, S, gr, s, x, y, G, H gap> START_TEST("Semigroups package: standard/semigroups/semigraph.tst"); gap> LoadPackage("semigroups", false);; @@ -59,6 +58,43 @@ gap> List(x, Range); [ v_4, v_4, v_2, v_1, v_2, v_1, v_1, v_2, v_1, v_3, v_4, v_2, v_1, v_5, v_4, v_2, v_1, v_3, v_4, v_2, v_1, v_5, v_4, v_2, v_1, v_3, v_4, v_2, v_1, v_5, v_4, v_2, v_1, v_1, v_2, v_3, v_4, v_5 ] +gap> List(x, PositivePath); +[ v_5, v_3, v_5, v_5, v_3, v_3, v_2, e_1, e_1, e_1e_2, e_1e_2, e_1e_2, + e_1e_2, e_1e_3, e_1e_3, e_1e_3, e_1e_3, e_2, e_2, e_2, e_2, e_3, e_3, e_3, + e_3, e_4, e_4, e_4, e_4, e_5, e_5, e_5, e_5, v_1, v_2, v_3, v_4, v_5 ] +gap> List(x, NegativePath); +[ e_5^-1, e_4^-1, e_3^-1, e_3^-1e_1^-1, e_2^-1, e_2^-1e_1^-1, e_1^-1, v_2, + e_1^-1, v_3, e_4^-1, e_2^-1, e_2^-1e_1^-1, v_5, e_5^-1, e_3^-1, + e_3^-1e_1^-1, v_3, e_4^-1, e_2^-1, e_2^-1e_1^-1, v_5, e_5^-1, e_3^-1, + e_3^-1e_1^-1, v_3, e_4^-1, e_2^-1, e_2^-1e_1^-1, v_5, e_5^-1, e_3^-1, + e_3^-1e_1^-1, v_1, v_2, v_3, v_4, v_5 ] +gap> List(x, EdgesWithSource); +[ [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ e_1 ], + [ e_2, e_3 ], [ ], [ e_4, e_5 ], [ ] ] +gap> List(x, EdgesWithRange); +[ [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ e_1 ], + [ e_2, e_4 ], [ ], [ e_3, e_5 ] ] +gap> List(x, PathsWithSource); +[ [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ v_1, e_1, e_1e_2, e_1e_3 ], [ v_2, e_2, e_3 ], [ v_3 ], [ v_4, e_4, e_5 ], + [ v_5 ] ] +gap> List(x, PathsWithRange); +[ [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], + [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ ], [ v_1 ], + [ v_2, e_1 ], [ v_3, e_2, e_1e_2, e_4 ], [ v_4 ], [ v_5, e_3, e_1e_3, e_5 ] + ] +gap> IdempotentGeneratedSubsemigroup(S); + +gap> Idempotents(S); +[ v_1, v_2, v_3, v_4, v_5, 0, e_1e_1^-1, e_2e_2^-1, e_3e_3^-1, e_4e_4^-1, + e_5e_5^-1, e_1e_2e_2^-1e_1^-1, e_1e_3e_3^-1e_1^-1 ] gap> AssignGeneratorVariables(S); gap> String(gr); "DigraphFromDigraph6String(\"&DOS@O?\")" @@ -66,6 +102,18 @@ gap> String(S); "GraphInverseSemigroup( DigraphFromDigraph6String(\"&DOS@O?\") )" gap> EvalString(String(S)) = S; false +gap> S := GraphInverseSemigroup(Digraph([[1]])); + +gap> PathsWithRange(S.1); +Error, the graph inverse semigroup containing the argument(element) must be fi\ +nite +gap> PathsWithSource(S.2); +Error, the graph inverse semigroup containing the argument(element) must be fi\ +nite +gap> EdgesWithRange(S.1); +[ ] +gap> EdgesWithSource(S.2); +[ e_1 ] gap> gr := Digraph([[1]]); gap> S := GraphInverseSemigroup(gr);