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);