Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7b798e1
Added Edges/Paths with Source/Range, Positive/Negative Path and relat…
joe-dw Sep 3, 2026
6d30d96
Lint
joe-dw Sep 3, 2026
00f0df2
Fixed docs and added methods for finding idempotents
joe-dw Sep 3, 2026
ca03b7f
Added comments
joe-dw Sep 3, 2026
0f43c0f
Remoted idempotent related functions, improved commenting and changed…
joe-dw Sep 4, 2026
62a0d70
Fixed issue with string running over two lines
joe-dw Sep 4, 2026
5e6b5e1
Reverted tests to those before Idempotent functions were implemented
joe-dw Sep 4, 2026
a0279c8
Update semigraph.xml
joe-dw Sep 4, 2026
7b5d526
Update semigraph.xml
joe-dw Sep 4, 2026
6585141
Fixed doc error
joe-dw Sep 4, 2026
0087793
Add PreImagesSet method for semigroup homs by images
fingolfin Sep 5, 2026
c46771e
Adding the zero element to the generating set for graph inverse semig…
joe-dw Sep 6, 2026
da07226
Merge branch 'semigroups:main' into pathsWithSourceRange
joe-dw Sep 15, 2026
d1357f2
Added handling and tests for infinite graph inverse semigroups
joe-dw Sep 15, 2026
5657b21
lint
joe-dw Sep 15, 2026
cb82fca
Updated docs
joe-dw Sep 16, 2026
55e17ea
Changed methods for edges with source/range to use digraphSource/Range
joe-dw Sep 16, 2026
be9c27d
Added documentation of depth trap errors and removed an unnecessary c…
joe-dw Sep 17, 2026
b9603db
Fixed error in last commit with concatenating the wrong paths
joe-dw Sep 17, 2026
af55234
Merge branch 'semigroups:main' into pathsWithSourceRange
joe-dw Sep 26, 2026
cd1a4da
Fixed docs to combine similar functions
joe-dw Sep 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 63 additions & 11 deletions doc/semigraph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -274,14 +274,19 @@ gap> IndexOfVertexOfGraphInverseSemigroup(v_3);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="LeftOne">
<#GAPDoc Label="LeftRightOne">
<ManSection>
<Oper Name = "LeftOne" Arg = "x" Label="for a graph inverse semigroup element"/>
<Oper Name = "RightOne" Arg = "x" Label="for a graph inverse semigroup element"/>
<Returns>A graph inverse semigroup element.</Returns>
<Description>
<C>LeftOne(<A>x</A>)</C> returns the unique idempotent
<C>e</C> such that <C>e * <A>x</A> = <A>x</A></C> and
<C>e</C> and <A>x</A> are related by Green's &R;-relation.

<C>RightOne(<A>x</A>)</C> returns the unique idempotent
<C>e</C> such that <C><A>x</A> * e = <A>x</A></C> and
<C>e</C> and <A>x</A> are related by Green's &L;-relation.
<Example><![CDATA[
gap> S := GraphInverseSemigroup(ChainDigraph(3));
<finite graph inverse semigroup with 3 vertices, 2 edges>
Expand All @@ -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
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="RightOne">
<#GAPDoc Label="EdgesPathsWithRangeSource">
<ManSection>
<Oper Name = "RightOne" Arg = "x" Label="for a graph inverse semigroup element"/>
<Attr Name="EdgesWithRange" Arg="x"/>
<Attr Name="EdgesWithSource" Arg="x"/>
<Attr Name="PathsWithRange" Arg="x"/>
<Attr Name="PathsWithSource" Arg="x"/>
<Returns>A list of graph inverse semigroup elements.</Returns>
<Description>
If <A>x</A> is an element of a finite graph inverse semigroup (i.e.
it satisfies <Ref Filt = "IsGraphInverseSemigroupElement"/>), then the
attributes <C>EdgesWithRange(<A>x</A>)</C> and
<C>EdgesWithSource(<A>x</A>)</C> return a list of all edges <C>e</C>
such that <C>Range(e)=<A>x</A></C> and <C>Source(e)=<A>x</A></C>
respectively.

If <A>x</A> is an element of a finite graph inverse semigroup (i.e.
it satisfies <Ref Filt = "IsGraphInverseSemigroupElement"/>), then the
operations <C>PathsWithRange(<A>x</A>)</C> and
<C>PathsWithSource(<A>x</A>)</C> return a list of all paths (products
of edges) <C>p</C> such that <C>Range(p)=<A>x</A></C> and
<C>Source(p)=<A>x</A></C> respectively.
<Example><![CDATA[
gap> D := Digraph([[2, 3], [3, 4], [4], []]);
<immutable digraph with 4 vertices, 5 edges>
gap> S := GraphInverseSemigroup(D);
<finite graph inverse semigroup with 4 vertices, 5 edges>
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 ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="PositiveNegativePath">
<ManSection>
<Attr Name="PositivePath" Arg="x"/>
<Attr Name="NegativePath" Arg="x"/>
<Returns>A graph inverse semigroup element.</Returns>
<Description>
<C>RightOne(<A>x</A>)</C> returns the unique idempotent
<C>e</C> such that <C><A>x</A> * e = <A>x</A></C> and
<C>e</C> and <A>x</A> are related by Green's &L;-relation.
All non-zero elements of a graph inverse semigroup can be written in the
form <C>pq^*</C>, where <C>p</C> and <C>q</C> are paths (products of
edges). If <A>x</A> is a non-zero element of a graph inverse semigroup,
then <C>PositivePath(<A>x</A>)</C> and <C>NegativePath(<A>x</A>)</C>
return the path <C>p</C> and ghost path <C>q*</C> respectively, while if
<C>x</C> is the zero element then both return <C>x</C>.
<Example><![CDATA[
gap> S := GraphInverseSemigroup(ChainDigraph(3));
<finite graph inverse semigroup with 3 vertices, 2 edges>
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
]]></Example>
</Description>
</ManSection>
Expand Down
5 changes: 3 additions & 2 deletions doc/z-chap07.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">

</Section>

Expand Down
8 changes: 8 additions & 0 deletions gap/semigroups/semigraph.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ DeclareAttribute("Source", IsGraphInverseSemigroupElement);

DeclareOperation("IsVertex", [IsGraphInverseSemigroupElement]);

DeclareAttribute("PositivePath", IsGraphInverseSemigroupElement);
DeclareAttribute("NegativePath", IsGraphInverseSemigroupElement);

InstallTrueMethod(IsGeneratorsOfInverseSemigroup,
IsGraphInverseSemigroupElementCollection);

Expand All @@ -41,3 +44,8 @@ DeclareAttribute("VerticesOfGraphInverseSemigroup",
IsGraphInverseSemigroup);
DeclareAttribute("EdgesOfGraphInverseSemigroup",
IsGraphInverseSemigroup);

DeclareAttribute("EdgesWithRange", IsGraphInverseSemigroupElement);
DeclareAttribute("EdgesWithSource", IsGraphInverseSemigroupElement);
DeclareOperation("PathsWithRange", [IsGraphInverseSemigroupElement]);
DeclareOperation("PathsWithSource", [IsGraphInverseSemigroupElement]);
118 changes: 115 additions & 3 deletions gap/semigroups/semigraph.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
Comment thread
joe-dw marked this conversation as resolved.
# 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)));
Comment thread
joe-dw marked this conversation as resolved.

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);
52 changes: 50 additions & 2 deletions tst/standard/semigroups/semigraph.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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);;

Expand Down Expand Up @@ -59,13 +58,62 @@ 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);
Comment thread
joe-dw marked this conversation as resolved.
[ 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);
<semigroup with 12 generators>
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?\")"
gap> String(S);
"GraphInverseSemigroup( DigraphFromDigraph6String(\"&DOS@O?\") )"
gap> EvalString(String(S)) = S;
false
gap> S := GraphInverseSemigroup(Digraph([[1]]));
<infinite graph inverse semigroup with 1 vertex, 1 edge>
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]]);
<immutable digraph with 1 vertex, 1 edge>
gap> S := GraphInverseSemigroup(gr);
Expand Down
Loading