Website: cloud.gap-system.org
The semigroups package needs to be loaded for the current worksheet.
LoadPackage("semigroups");
Transformations are to semigroups as permutations are to groups.
Mathematically, permutations are transformations, but in GAP they are not.
f := Transformation([4, 1, 1, 5, 3, 3]);
g := Transformation([4, 5, 1, 2, 1, 4]);
f * g;
f * g = g * f;
x := RandomTransformation(10);
y := RandomTransformation(10);
z := RandomTransformation(10);
x * y = y * x; # commutativity
z * z = z; # idempotent?
Composition of functions is associative...
(x * y) * z = x * (y * z); # associativity
... and so you can make semigroups out of transformations
S := Semigroup(x, y, z);
Size(S);
t := Transformation([2, 3, 1]);
p := AsPermutation(t);
p = t;
AsPermutation(f);
t * p;
Permutations and transformations can be multiplied together, but you cannot create a semigroup with both elements.
Semigroup(t, p);
Something created as a semigroup may not satisfy IsGroup
even if it is mathematically a group. We use IsGroupAsSemigroup
to check for this.
There are similar problems with IsMonoid
. This the analogous property is IsMonoidAsSemigroup
.
M := [ [ Z(5), Z(5)^2 ], [ Z(5)^3, Z(5)^2 ] ];
M in GL(2, 5);
A group is also a monoid and a semigroup.
G := Group(M);
IsSemigroup(G);
IsMonoid(G);
IsGroup(G);
A semigroup is not (usually) a monoid or a group in GAP -- even if it is mathematically.
The category depends on how the object was created.
S := Semigroup(M);
IsSemigroup(S);
IsMonoid(S);
IsMonoidAsSemigroup(S);
IsGroup(S);
IsGroupAsSemigroup(S);
G = S;
For an object in IsGroup
, GAP needs to know that it can invert any element independently, and it needs how to do it.
For a permutation, there is only ever one inverse, and it is easy to calculate.
A transformation does not necessarily have an inverse, and so GAP needs to consider the whole semigroup to know how to invert an element in a group of transformations. So transformation groups are usually not in the category IsGroup
, except...
IsGroup(FullTransformationSemigroup(1));
A := [
[1, 2, 3, 4],
[2, 1, 3, 4],
[3, 4, 3, 4],
[4, 3, 3, 4]
];
S := SemigroupByMultiplicationTable(A);
T := FullTransformationSemigroup(2);
IsIsomorphicSemigroup(S, T);
S := FullTransformationSemigroup(10);
x := PseudoRandom(S);
I := SymmetricInverseSemigroup(8);
x := PseudoRandom(I);
Print(x);
P := PartitionMonoid(4);
x := PseudoRandom(P);
Print(x);
M := FullMatrixSemigroup(2, 5);
x := PseudoRandom(GroupOfUnits(M));
Print(x);
AsMatrix(x) in GL(2, 5);
IsSubsemigroup(M, GL(2, 5));
x := Random(GL(2, 5));
NewMatrixOverFiniteField(IsPlistMatrixOverFiniteFieldRep, GF(5), 2, x) in M;
F := FreeSemigroup("x", "y");
IsFinite(F);
x := F.1;
y := F.2;
Relation 1: x * y = y * x
rel1 := [ x * y, y * x ];
Relation 2: x ^ 3 = x ^ 2
rel2 := [ x ^ 3, x ^ 2 ];
Relation 3: y ^ 2 = y
rel3 := [y ^ 2, y ];
S := F / [rel1, rel2, rel3];
Size(S);
Elements(S);
T := F / [rel2, rel3];
# IsFinite(T);
enumerate_semigroup := function(gens)
local elts, x, g;
elts := ShallowCopy(gens);
for x in elts do
for g in gens do
if not x * g in elts then
Add(elts, x * g);
fi;
od;
od;
return elts;
end;
Length(enumerate_semigroup([f, g]));
Size(Semigroup(f, g));
LoadPackage("digraphs");
enumerate_with_graph := function(gens)
local elts, graph, adjacencies, pos, x, g, prod;
elts := ShallowCopy(gens);
graph := [];
for x in elts do
adjacencies := [];
for g in gens do
prod := x * g;
pos := Position(elts, prod);
if pos = fail then
Add(elts, prod);
Add(adjacencies, Length(elts));
else
Add(adjacencies, pos);
fi;
od;
Add(graph, adjacencies);
od;
return Digraph(graph);
end;
gr := enumerate_with_graph([Transformation([1, 1, 3]), Transformation([1, 2, 2])]);
JUPYTER_DotSplash(DotDigraph(gr));
Commutativity is a nice simple property to check for.
A semigroup is commutative if x y = y x for all x, y.
Check all elements for commutativity, as per the definition.
is_commutative_1 := function(S)
local x, y;
for x in S do
for y in S do
if not x * y = y * x then
return false;
fi;
od;
od;
return true;
end;
S := FullTransformationSemigroup(4);;
is_commutative_1(S);
IsCommutative(S);
S := Semigroup([
PartialPerm([1, 2, 3, 4, 5, 6, 8, 9], [1, 2, 3, 4, 5, 6, 8, 9]),
PartialPerm([1, 3, 4, 5, 6, 7, 8, 9], [1, 3, 4, 5, 6, 7, 8, 9]),
PartialPerm([1, 2, 4, 5, 6, 7, 8, 9], [1, 2, 4, 5, 6, 7, 8, 9]),
PartialPerm([1, 2, 3, 4, 6, 7, 8, 9], [1, 2, 3, 4, 6, 7, 8, 9]),
PartialPerm([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8]),
PartialPerm([1, 2, 3, 4, 5, 7, 8, 9], [1, 2, 3, 4, 5, 7, 8, 9]),
PartialPerm([1, 2, 3, 4, 5, 6, 7, 9], [1, 2, 3, 4, 5, 6, 7, 9]),
PartialPerm([2, 3, 4, 5, 6, 7, 8, 9], [2, 3, 4, 5, 6, 7, 8, 9]),
PartialPerm([1, 2, 3, 5, 6, 7, 8, 9], [1, 2, 3, 5, 6, 7, 8, 9])]);
is_commutative_1(S)
time;
IsCommutative(S);
time;
Check all generators
is_commutative_2 := function(S)
local gens, x, y;
gens := GeneratorsOfSemigroup(S);
for x in gens do
for y in gens do
if not x * y = y * x then
return false;
fi;
od;
od;
return true;
end;
is_commutative_2(S);
time;
Don't repeat work!
is_commutative_3 := function(S)
local pair;
for pair in Combinations(GeneratorsOfSemigroup(S), 2) do
if not pair[1] * pair[2] = pair[2] * pair[1] then
return false;
fi;
od;
return true;
end;
is_commutative_3(S);
IteratorOfCombinations
.¶An idempotent is an element where x ^ 2 = x
Check every element for idempotency.
nr_idempotents_1 := S -> Number(S, IsIdempotent);
S := SymmetricInverseSemigroup(7);
nr_idempotents_1(S);
time;
NrIdempotents(S);
time;
In any semigroup, the number of idempotents is the number of maximal subgroups.
nr_idempotents_2 := S -> Number(GreensHClasses(S), IsGroupHClass);
S := SymmetricInverseSemigroup(7);
nr_idempotents_2(S);
time;
In an inverse semigroup, NrIdempotents
= NrRClasses
.
nr_idempotents_inverse := NrRClasses;
S := SymmetricInverseSemigroup(7);
nr_idempotents_inverse(S);
time;
In a band, every element is idempotent. So NrIdempotents
= Size
.
nr_idempotents_band := Size;
S := FreeBand(4);
nr_idempotents_band(S);
time;
S := FreeBand(4);
NrIdempotents(S);
time;
InstallMethod(NrIdempotents, "for a band", [IsBand], Size);
S := FreeBand(4);
SetIsBand(S, true);
NrIdempotents(S);
time;