|
#############################################################################
##
## greens/acting.gi
## Copyright (C) 2015-2022 James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##
#############################################################################
## This file contains methods for Green's classes etc for acting semigroups.
## It is organized as follows:
##
## 1. Helper functions for the creation of Green's classes, and lambda-rho
## stuff.
##
## 2. Technical Green's stuff (types, representative, etc)
##
## 3. Individual Green's classes (constructors, size, membership)
##
## 4. Collections of Green's classes (GreensXClasses, XClassReps, NrXClasses)
##
## 5. Idempotents and NrIdempotents
##
## 6. Regularity of Green's classes
##
## 7. Iterators and enumerators
##
#############################################################################
#############################################################################
## Green's classes are created as follows:
##
## 1. Create the class C using SEMIGROUPS.CreateXClass, this sets the type,
## equivalence relations, whether or not the class is NC, the parent, and
## the element used to create the class (stored in C!.rep)
##
## 2. Copy or set the lambda/rho orbits using SEMIGROUPS.CopyLambda/Rho and
## SEMIGROUPS.SetLambda/Rho. After calling any combination of these two
## functions Lambda/RhoOrb and Lambda/RhoOrbSCCIndex for the class are
## set.
##
## The former simply copies the orbit and the index of the strongly
## connected component containing the lambda/rho value of the element used
## to create the class. This is useful, for example, when trying to create
## an R-class of a D-class, when the lambda orbit and scc index are just
## the same as those for the D-class.
##
## The latter uses the lambda/rho orbit of the whole semigroup if it is
## known and the class is not nc. Otherwise it creates/finds the graded
## lambda/rho orbit. If the graded lambda/rho orbit is created/found, then
## the position of the lambda/rho value of C!.rep (the element used to
## create the class) in the orbit is stored in C!.Lambda/RhoPos.
##
## 3. Rectify the lambda/rho value of the representative. The representative
## of an R-class, for example, must have its lambda-value in the first
## position of the scc containing it. Representatives of L-classes must
## have the rho-value in the first position of the scc containing
## it, D-class reps must have both lambda- and rho-values in the
## respective first positions, the lambda- and rho-values of H-class reps
## must not be modified. The functions SEMIGROUPS.RectifyLambda/Rho can
## used to modify C!.rep (in place) so that its lambda/rho-value is in the
## first place of its scc. These functions depend on the previous 2 steps
## being called.
##
## Note that a Green's class does not satisfies IsGreensClassNC if it is known
## that its representative is an element of the underlying semigroup, not if it
## is known to be an element of another Green's class. Also a class in
## IsGreensClassNC makes the assumption that the representative belongs to the
## containing object, and reuses the lambda/rho orbit from the container. So,
## it might be that the representative of a class created using an NC method,
## has lambda/rho value not belonging to the lambda/rho orbit of the class.
#############################################################################
#############################################################################
## 1. Helper functions for the creation of Green's classes . . .
#############################################################################
# same method for regular/different for inverse
SEMIGROUPS.CreateXClass := function(args, type, rel)
local S, nc, rep, irep, erep, C;
if Length(args) = 1 then # arg is a Green's class
# for creating bigger classes containing smaller ones
Assert(1, IsActingSemigroupGreensClass(args[1]));
S := Parent(args[1]);
nc := IsGreensClassNC(args[1]);
rep := args[1]!.rep;
else # arg is semigroup/Green's class, rep, and boolean
# for creating smaller classes inside bigger ones
if IsGreensClass(args[1]) then
S := Parent(args[1]);
else
S := args[1];
fi;
rep := args[2];
nc := args[3];
fi;
irep := ConvertToInternalElement(S, rep);
erep := ConvertToExternalElement(S, rep);
C := rec(rep := irep);
ObjectifyWithAttributes(C, type(S),
ParentAttr, S,
IsGreensClassNC, nc,
EquivalenceClassRelation, rel(S),
Representative, erep);
if IsInverseActingSemigroupRep(S) then
SetFilterObj(C, IsInverseActingRepGreensClass);
elif IsRegularActingSemigroupRep(S) then
SetFilterObj(C, IsRegularActingRepGreensClass);
elif HasIsRegularSemigroup(S) and IsRegularSemigroup(S) then
if type <> HClassType then
SetIsRegularGreensClass(C, true);
fi;
fi;
return C;
end;
# same method for regular/inverse
SEMIGROUPS.CreateDClass := function(arg...)
return SEMIGROUPS.CreateXClass(arg, DClassType, GreensDRelation);
end;
# same method for regular/inverse
SEMIGROUPS.CreateRClass := function(arg...)
return SEMIGROUPS.CreateXClass(arg, RClassType, GreensRRelation);
end;
# same method for regular/inverse
SEMIGROUPS.CreateLClass := function(arg...)
return SEMIGROUPS.CreateXClass(arg, LClassType, GreensLRelation);
end;
# same method for regular/inverse
SEMIGROUPS.CreateHClass := function(arg...)
return SEMIGROUPS.CreateXClass(arg, HClassType, GreensHRelation);
end;
SEMIGROUPS.SetLambda := function(C)
local S, o;
S := Parent(C);
if HasLambdaOrb(S) and IsClosedOrbit(LambdaOrb(S))
and not IsGreensClassNC(C) then
SetLambdaOrb(C, LambdaOrb(S));
SetLambdaOrbSCCIndex(C, OrbSCCIndex(LambdaOrb(S), LambdaFunc(S)(C!.rep)));
else
o := GradedLambdaOrb(S, C!.rep, IsGreensClassNC(C) <> true, C);
SetLambdaOrb(C, o);
SetLambdaOrbSCCIndex(C, OrbSCCLookup(o)[C!.LambdaPos]);
fi;
end;
SEMIGROUPS.SetRho := function(C)
local S, o;
S := Parent(C);
if HasRhoOrb(S) and IsClosedOrbit(RhoOrb(S)) and not IsGreensClassNC(C) then
SetRhoOrb(C, RhoOrb(S));
SetRhoOrbSCCIndex(C, OrbSCCIndex(RhoOrb(S), RhoFunc(S)(C!.rep)));
else
o := GradedRhoOrb(S, C!.rep, IsGreensClassNC(C) <> true, C);
SetRhoOrb(C, o);
SetRhoOrbSCCIndex(C, OrbSCCLookup(o)[C!.RhoPos]);
fi;
end;
SEMIGROUPS.CopyLambda := function(old, new)
SetLambdaOrb(new, LambdaOrb(old));
SetLambdaOrbSCCIndex(new, LambdaOrbSCCIndex(old));
return;
end;
SEMIGROUPS.CopyRho := function(old, new)
SetRhoOrb(new, RhoOrb(old));
SetRhoOrbSCCIndex(new, RhoOrbSCCIndex(old));
return;
end;
SEMIGROUPS.RectifyLambda := function(C)
local o, i, m;
Assert(1, not IsGreensHClass(C));
o := LambdaOrb(C);
if not IsBound(C!.LambdaPos) then
i := Position(o, LambdaFunc(Parent(C))(C!.rep));
else
i := C!.LambdaPos;
fi;
m := LambdaOrbSCCIndex(C);
if i <> OrbSCC(o)[m][1] then
C!.rep := C!.rep * LambdaOrbMult(o, m, i)[2];
# don't set Representative in case we must also rectify Rho
fi;
return;
end;
SEMIGROUPS.RectifyRho := function(C)
local o, i, m;
Assert(1, not IsGreensHClass(C));
o := RhoOrb(C);
if not IsBound(C!.RhoPos) then
i := Position(o, RhoFunc(Parent(C))(C!.rep));
else
i := C!.RhoPos;
fi;
m := RhoOrbSCCIndex(C);
if i <> OrbSCC(o)[m][1] then
C!.rep := RhoOrbMult(o, m, i)[2] * C!.rep;
# don't set Representative in case we must also rectify Lambda
fi;
return;
end;
# helper function, for: Green's class, lambda/rho value, rho/lambda scc,
# rho/lambda orbit, and boolean
SEMIGROUPS.Idempotents := function(x, value, scc, o, onright)
local S, out, j, tester, creator, i;
Assert(1, IsActingSemigroupGreensClass(x));
if HasIsRegularGreensClass(x) and not IsRegularGreensClass(x) then
return [];
fi;
S := Parent(x);
if IsActingSemigroupWithFixedDegreeMultiplication(S)
and IsMultiplicativeElementWithOneCollection(S)
and ActionRank(S)(x!.rep) = ActionDegree(x!.rep) then
return [One(S)];
fi;
out := EmptyPlist(Length(scc));
j := 0;
tester := IdempotentTester(S);
creator := IdempotentCreator(S);
if onright then
for i in scc do
if tester(o[i], value) then
j := j + 1;
out[j] := ConvertToExternalElement(S, creator(o[i], value));
fi;
od;
else
for i in scc do
if tester(value, o[i]) then
j := j + 1;
out[j] := ConvertToExternalElement(S, creator(value, o[i]));
fi;
od;
fi;
if not HasIsRegularGreensClass(x) then
SetIsRegularGreensClass(x, j <> 0);
fi;
# can't set NrIdempotents here since we sometimes input a D-class here.
ShrinkAllocationPlist(out);
return out;
end;
# helper function, for: Green's class, lambda/rho value, rho/lambda scc,
# rho/lambda orbit, and boolean
SEMIGROUPS.NrIdempotents := function(x, value, scc, o, onright)
local S, data, m, nr, tester, i;
if HasIsRegularGreensClass(x) and not IsRegularGreensClass(x) then
return 0;
fi;
S := Parent(x);
# check if we already know this...
if HasSemigroupDataIndex(x)
and not (HasIsRegularGreensClass(x) and IsRegularGreensClass(x)) then
data := SemigroupData(S);
m := LambdaOrbSCCIndex(x);
if data!.repslens[m][data!.orblookup1[SemigroupDataIndex(x)]] > 1 then
return 0;
fi;
fi;
# is r the group of units...
if IsActingSemigroupWithFixedDegreeMultiplication(S) and
ActionRank(S)(x!.rep) = ActionDegree(x!.rep) then
return 1;
fi;
nr := 0;
tester := IdempotentTester(S);
if onright then
for i in scc do
if tester(o[i], value) then
nr := nr + 1;
fi;
od;
else
for i in scc do
if tester(value, o[i]) then
nr := nr + 1;
fi;
od;
fi;
if not HasIsRegularGreensClass(x) then
SetIsRegularGreensClass(x, nr <> 0);
fi;
return nr;
end;
# helper function, for: Green's class, lambda/rho value, rho/lambda scc,
# rho/lambda orbit, and boolean
SEMIGROUPS.IsRegularGreensClass := function(x, value, scc, o, onright)
local S, data, m, tester, i;
if HasNrIdempotents(x) then
return NrIdempotents(x) <> 0;
fi;
S := Parent(x);
if HasSemigroupDataIndex(x) then
data := SemigroupData(S);
m := LambdaOrbSCCIndex(x);
if data!.repslens[m][data!.orblookup1[SemigroupDataIndex(x)]] > 1 then
return false;
fi;
fi;
# is x the group of units...
if IsActingSemigroupWithFixedDegreeMultiplication(S) and
ActionRank(S)(x!.rep) = ActionDegree(x!.rep) then
return true;
fi;
tester := IdempotentTester(S);
if onright then
for i in scc do
if tester(o[i], value) then
return true;
fi;
od;
else
for i in scc do
if tester(value, o[i]) then
return true;
fi;
od;
fi;
return false;
end;
# Lambda-Rho stuff
# same method for regular/inverse/ideals
InstallMethod(LambdaOrbSCC, "for a Green's class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensClass],
C -> OrbSCC(LambdaOrb(C))[LambdaOrbSCCIndex(C)]);
# same method for regular/inverse/ideals
InstallMethod(RhoOrbSCC, "for a Green's class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensClass],
C -> OrbSCC(RhoOrb(C))[RhoOrbSCCIndex(C)]);
# not required for regular/inverse, same method for ideals
InstallMethod(LambdaCosets, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
return RightTransversal(LambdaOrbSchutzGp(LambdaOrb(D),
LambdaOrbSCCIndex(D)),
SchutzenbergerGroup(D));
end);
# not required for regular/inverse, same method for ideals
InstallMethod(RhoCosets, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
local o, m, S;
o := RhoOrb(D);
m := RhoOrbSCCIndex(D);
S := Parent(D);
return RightTransversal(RhoOrbSchutzGp(o, m) ^
LambdaConjugator(S)(RhoOrbRep(o, m),
D!.rep),
SchutzenbergerGroup(D));
end);
# note that the RhoCosets of the D-class containing an L-class are not the same
# as the RhoCosets of the L-class. The RhoCosets of a D-class correspond to the
# lambda value of the rep of the D-class (which is in the first place of its
# scc) and the rep of the D-class but the RhoCosets of the L-class should
# correspond to the lambda value of the rep of the L-class which is not nec in
# the first place of its scc.
# different method for regular, same method for ideals
InstallMethod(RhoCosets, "for a L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
function(L)
local D, S, rep, m, o, pos, x, conj;
D := DClassOfLClass(L);
S := Parent(L);
o := LambdaOrb(D);
m := LambdaOrbSCCIndex(D);
if IsRegularGreensClass(L) or Length(RhoCosets(D)) = 1 then
# Maybe <L> is regular and doesn't know it!
return [LambdaIdentity(S)(LambdaRank(S)(o[OrbSCC(o)[m][1]]))];
fi;
rep := L!.rep;
pos := Position(o, LambdaFunc(S)(rep));
if pos = OrbSCC(o)[m][1] then
return RhoCosets(D);
else
x := rep * LambdaOrbMult(o, m, pos)[2];
conj := LambdaConjugator(S)(x, rep) * LambdaPerm(S)(x, D!.rep);
return List(RhoCosets(D), x -> x ^ conj);
fi;
end);
# different method for regular/inverse, same for ideals
InstallMethod(RhoOrbStabChain, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
D -> RhoOrbStabChain(GreensLClassOfElementNC(D, D!.rep)));
# same method for regular, not required for inverse, same for ideals
InstallMethod(RhoOrbStabChain, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
function(L)
local G;
G := SchutzenbergerGroup(L);
if IsTrivial(G) then
return false;
elif IsNaturalSymmetricGroup(G) and
NrMovedPoints(G) = ActionRank(Parent(L))(L!.rep) then
return true;
elif IsPermGroup(G) then
return StabChainImmutable(G);
else # if IsMatrixGroup(g)
return G;
fi;
end);
InstallMethod(SemigroupDataIndex,
"for an acting semigroup Green's class",
[IsActingSemigroupGreensClass],
C -> Position(SemigroupData(Parent(C)), Representative(C)));
# different method for regular/inverse/ideals
InstallMethod(SchutzenbergerGroup, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
local o, m, lambda_schutz, lambda_stab, rho_schutz, rho_stab, schutz, p;
o := LambdaOrb(D);
m := LambdaOrbSCCIndex(D);
lambda_schutz := LambdaOrbSchutzGp(o, m);
lambda_stab := LambdaOrbStabChain(o, m);
o := RhoOrb(D);
m := RhoOrbSCCIndex(D);
rho_schutz := RhoOrbSchutzGp(o, m);
rho_stab := RhoOrbStabChain(o, m);
if rho_stab = true then
schutz := lambda_schutz;
if lambda_stab = true then
SetRhoOrbStabChain(D, true);
# Right transversal required so can use PositionCanonical
SetRhoCosets(D, RightTransversal(schutz, schutz));
return lambda_schutz;
fi;
elif rho_stab = false then
SetRhoOrbStabChain(D, false);
SetRhoCosets(D, RightTransversal(rho_schutz, rho_schutz));
return rho_schutz;
fi;
# Use D!.rep because it might be different that Representative(D)
p := LambdaConjugator(Parent(D))(RhoOrbRep(o, m), D!.rep);
rho_schutz := rho_schutz ^ p;
if IsPermGroup(rho_schutz) then
SetRhoOrbStabChain(D, StabChainImmutable(rho_schutz));
else # if IsMatrixGroup(g)
SetRhoOrbStabChain(D, rho_schutz);
fi;
if lambda_stab = false then
SetRhoCosets(D, Enumerator(rho_schutz));
return lambda_schutz;
elif lambda_stab = true then
schutz := rho_schutz;
else
schutz := Intersection(lambda_schutz, rho_schutz);
fi;
SetRhoCosets(D, RightTransversal(rho_schutz, schutz));
return schutz;
end);
# same method for regular/inverse/ideals
InstallMethod(SchutzenbergerGroup, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
R -> LambdaOrbSchutzGp(LambdaOrb(R), LambdaOrbSCCIndex(R)));
# same method for regular/ideals, different method for inverse
InstallMethod(SchutzenbergerGroup, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
function(L)
local o, m, p;
o := RhoOrb(L);
m := RhoOrbSCCIndex(L);
p := LambdaConjugator(Parent(L))(RhoOrbRep(o, m), L!.rep);
return RhoOrbSchutzGp(o, m) ^ p;
end);
# different method for regular/inverse, same method for ideals
InstallMethod(SchutzenbergerGroup, "for a H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local lambda_o, lambda_m, lambda_schutz, lambda_stab, rho_o, rho_m,
rho_schutz, rho_stab, S, rep, lambda_mult, lambda_p, rho_mult, rho_p;
lambda_o := LambdaOrb(H);
lambda_m := LambdaOrbSCCIndex(H);
lambda_schutz := LambdaOrbSchutzGp(lambda_o, lambda_m);
lambda_stab := LambdaOrbStabChain(lambda_o, lambda_m);
if lambda_stab = false then
return lambda_schutz;
fi;
rho_o := RhoOrb(H);
rho_m := RhoOrbSCCIndex(H);
rho_schutz := RhoOrbSchutzGp(rho_o, rho_m);
rho_stab := RhoOrbStabChain(rho_o, rho_m);
if rho_stab = false then
return rho_schutz;
fi;
S := Parent(H);
rep := H!.rep;
lambda_mult := LambdaOrbMult(lambda_o,
lambda_m,
Position(lambda_o, LambdaFunc(S)(rep)))[2];
# the points acted on by LambdaSchutzGp mapped to the lambda value of rep
lambda_p := LambdaConjugator(S)(rep * lambda_mult, rep);
if rho_stab = true then
return lambda_schutz ^ lambda_p;
fi;
rho_mult := RhoOrbMult(rho_o, rho_m, Position(rho_o, RhoFunc(S)(rep)))[2];
# the points acted on by RhoSchutzGp mapped to the corresponding points for
# rep (the rho value mapped through the rep so that it is on the right)
rho_p := LambdaConjugator(S)(RhoOrbRep(rho_o, rho_m), rho_mult * rep);
return Intersection(lambda_schutz ^ lambda_p, rho_schutz ^ rho_p);
end);
#############################################################################
## 2. Technical Green's classes stuff . . .
#############################################################################
# Different method for regular/inverse
InstallMethod(\<, "for Green's D-classes of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass,
IsGreensDClass and IsActingSemigroupGreensClass],
function(x, y)
local scc;
if Parent(x) <> Parent(y) or x = y then
return false;
fi;
scc := OrbSCCLookup(SemigroupData(Parent(x)));
return scc[SemigroupDataIndex(x)] < scc[SemigroupDataIndex(y)];
end);
# Different method for regular/inverse
InstallMethod(\<, "for Green's R-classes of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass,
IsGreensRClass and IsActingSemigroupGreensClass],
function(x, y)
if Parent(x) <> Parent(y) or x = y then
return false;
fi;
return SemigroupDataIndex(x) < SemigroupDataIndex(y);
end);
# TODO(later) a method for L-classes?
InstallMethod(IsRegularDClass, "for a Green's D-class",
[IsGreensDClass and IsActingSemigroupGreensClass], IsRegularGreensClass);
# different method for regular/inverse
InstallMethod(DClassType, "for an acting semigroup",
[IsActingSemigroup],
function(S)
return NewType(FamilyObj(S), IsEquivalenceClass
and IsEquivalenceClassDefaultRep
and IsGreensDClass
and IsActingSemigroupGreensClass);
end);
# different method for regular/inverse
InstallMethod(HClassType, "for an acting semigroup",
[IsActingSemigroup],
function(S)
return NewType(FamilyObj(S), IsEquivalenceClass
and IsEquivalenceClassDefaultRep
and IsGreensHClass
and IsActingSemigroupGreensClass);
end);
# different method for regular/inverse
InstallMethod(LClassType, "for an acting semigroup",
[IsActingSemigroup],
function(S)
return NewType(FamilyObj(S), IsEquivalenceClass
and IsEquivalenceClassDefaultRep
and IsGreensLClass
and IsActingSemigroupGreensClass);
end);
# different method for regular/inverse
InstallMethod(RClassType, "for an acting semigroup",
[IsActingSemigroup],
function(S)
return NewType(FamilyObj(S), IsEquivalenceClass
and IsEquivalenceClassDefaultRep
and IsGreensRClass
and IsActingSemigroupGreensClass);
end);
#############################################################################
## 3. Individual classes . . .
#############################################################################
# same method for regular/ideals, different method for inverse
InstallMethod(DClassOfLClass, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
function(L)
local D;
D := SEMIGROUPS.CreateDClass(L);
SEMIGROUPS.CopyRho(L, D);
SEMIGROUPS.SetLambda(D);
SEMIGROUPS.RectifyLambda(D);
return D;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(DClassOfRClass, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
function(R)
local D;
D := SEMIGROUPS.CreateDClass(R);
SEMIGROUPS.CopyLambda(R, D);
SEMIGROUPS.SetRho(D);
SEMIGROUPS.RectifyRho(D);
return D;
end);
# same method for regular, different method for inverse semigroups,
# same for ideals
InstallMethod(DClassOfHClass, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local D;
D := SEMIGROUPS.CreateDClass(H);
SEMIGROUPS.CopyLambda(H, D);
SEMIGROUPS.RectifyLambda(D);
SEMIGROUPS.CopyRho(H, D);
SEMIGROUPS.RectifyRho(D);
return D;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(LClassOfHClass, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local L;
L := SEMIGROUPS.CreateLClass(H);
SEMIGROUPS.CopyRho(H, L);
SEMIGROUPS.RectifyRho(L);
return L;
end);
# same method for regular/inverse/ideals
InstallMethod(RClassOfHClass, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local R;
R := SEMIGROUPS.CreateRClass(H);
SEMIGROUPS.CopyLambda(H, R);
SEMIGROUPS.RectifyLambda(R);
return R;
end);
# same method for regular/ideals/inverse
InstallMethod(GreensDClassOfElement, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
function(S, x)
if not x in S then
ErrorNoReturn("the 2nd argument (a mult. elt.) does not belong ",
"to the 1st argument (a semigroup)");
fi;
return GreensDClassOfElementNC(S, x, false);
end);
# same method for regular/ideals/inverse
InstallMethod(GreensDClassOfElementNC, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
{S, x} -> GreensDClassOfElementNC(S, x, true));
# same method for regular/ideals, different method for inverse
InstallMethod(GreensDClassOfElementNC,
"for an acting semigroup, element, and bool",
[IsActingSemigroup, IsMultiplicativeElement, IsBool],
function(S, x, isGreensClassNC)
local D;
D := SEMIGROUPS.CreateDClass(S, x, isGreensClassNC);
SEMIGROUPS.SetLambda(D);
SEMIGROUPS.RectifyLambda(D);
SEMIGROUPS.SetRho(D);
SEMIGROUPS.RectifyRho(D);
return D;
end);
# same method for regular/ideals/inverse
InstallMethod(GreensLClassOfElement, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
function(S, x)
if not x in S then
ErrorNoReturn("the 2nd argument (a mult. elt.) does not belong ",
"to the 1st argument (a semigroup)");
fi;
return GreensLClassOfElementNC(S, x, false);
end);
# same method for regular/ideals/inverse
InstallMethod(GreensLClassOfElementNC, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
{S, x} -> GreensLClassOfElementNC(S, x, true));
# same method for regular/ideals, different method for inverse
InstallMethod(GreensLClassOfElementNC,
"for an acting semigroup, element, and bool",
[IsActingSemigroup, IsMultiplicativeElement, IsBool],
function(S, x, isGreensClassNC)
local L;
L := SEMIGROUPS.CreateLClass(S, x, isGreensClassNC);
SEMIGROUPS.SetRho(L);
SEMIGROUPS.RectifyRho(L);
return L;
end);
# same method for regular/ideals/inverse
InstallMethod(GreensLClassOfElement,
"for D-class of acting semigroup and element",
[IsGreensDClass and IsActingSemigroupGreensClass, IsMultiplicativeElement],
function(D, x)
if not x in D then
ErrorNoReturn("the 2nd argument (a mult. elt.) does not belong ",
"to the 1st argument (a Green's D-class)");
fi;
return GreensLClassOfElementNC(D, x, IsGreensClassNC(D));
end);
# same method for regular/ideals/inverse
InstallMethod(GreensLClassOfElementNC, "for D-class and multiplicative element",
[IsGreensDClass and IsActingSemigroupGreensClass, IsMultiplicativeElement],
{D, x} -> GreensLClassOfElementNC(D, x, true));
# same method for regular/ideals, different method for inverse
InstallMethod(GreensLClassOfElementNC,
"for D-class, multiplicative element, and bool",
[IsGreensDClass and IsActingSemigroupGreensClass, IsMultiplicativeElement,
IsBool],
function(D, x, isGreensClassNC)
local L;
L := SEMIGROUPS.CreateLClass(D, x, isGreensClassNC);
# this is a special case, D might not be an inverse-op class but
# L might be an inverse-op class.
if IsInverseActingRepGreensClass(L) then
SEMIGROUPS.CopyLambda(D, L);
SEMIGROUPS.InverseRectifyRho(L);
else
SEMIGROUPS.CopyRho(D, L);
SEMIGROUPS.RectifyRho(L);
fi;
SetDClassOfLClass(L, D);
return L;
end);
# same method for regular/inverse/ideals
InstallMethod(GreensRClassOfElement, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
function(S, x)
if not x in S then
ErrorNoReturn("the 2nd argument (a mult. elt.) does not belong ",
"to the 1st argument (a semigroup)");
fi;
return GreensRClassOfElementNC(S, x, false);
end);
# same method for regular/inverse/ideals
InstallMethod(GreensRClassOfElementNC, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
{S, x} -> GreensRClassOfElementNC(S, x, true));
# same method for regular/inverse/ideals
InstallMethod(GreensRClassOfElementNC,
"for an acting semigroup, multiplicative element, and bool",
[IsActingSemigroup, IsMultiplicativeElement, IsBool],
function(S, x, isGreensClassNC)
local R;
R := SEMIGROUPS.CreateRClass(S, x, isGreensClassNC);
SEMIGROUPS.SetLambda(R);
SEMIGROUPS.RectifyLambda(R);
return R;
end);
# same method for regular/inverse/ideals
InstallMethod(GreensRClassOfElement,
"for an acting semigroup D-class and multiplicative element",
[IsGreensDClass and IsActingSemigroupGreensClass, IsMultiplicativeElement],
function(D, x)
if not x in D then
ErrorNoReturn("the 2nd argument (a mult. elt.) does not belong ",
"to the 1st argument (a Green's D-class)");
fi;
return GreensRClassOfElementNC(D, x, IsGreensClassNC(D));
end);
# same method for regular/inverse/ideals
InstallMethod(GreensRClassOfElementNC, "for D-class and multiplicative element",
[IsGreensDClass and IsActingSemigroupGreensClass, IsMultiplicativeElement],
{D, x} -> GreensRClassOfElementNC(D, x, true));
# same method for regular/inverse/ideals
InstallMethod(GreensRClassOfElementNC,
"for a D-class, multiplicative element, and bool",
[IsGreensDClass and IsActingSemigroupGreensClass, IsMultiplicativeElement,
IsBool],
function(D, x, isGreensClassNC)
local R;
R := SEMIGROUPS.CreateRClass(D, x, isGreensClassNC);
SEMIGROUPS.CopyLambda(D, R);
SEMIGROUPS.RectifyLambda(R);
SetDClassOfRClass(R, D);
return R;
end);
# same method for regular/ideals/inverse
InstallMethod(GreensHClassOfElement, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
function(S, x)
if not x in S then
ErrorNoReturn("the element does not belong to the semigroup");
fi;
return GreensHClassOfElementNC(S, x, false);
end);
# same method for regular/ideals/inverse
InstallMethod(GreensHClassOfElementNC, "for an acting semigroup and element",
[IsActingSemigroup, IsMultiplicativeElement],
{S, x} -> GreensHClassOfElementNC(S, x, true));
# same method for regular/ideals, different for inverse
InstallMethod(GreensHClassOfElementNC,
"for an acting semigroup, element, and bool",
[IsActingSemigroup, IsMultiplicativeElement, IsBool],
function(S, x, isGreensClassNC)
local H;
H := SEMIGROUPS.CreateHClass(S, x, isGreensClassNC);
SEMIGROUPS.SetLambda(H);
SEMIGROUPS.SetRho(H);
return H;
end);
# same method for regular/ideals/inverse
InstallMethod(GreensHClassOfElement, "for a D/H-class and element",
[IsActingSemigroupGreensClass and IsGreensClass, IsMultiplicativeElement],
function(C, x)
if not x in C then
ErrorNoReturn("the 2nd argument (a mult. elt.) does not belong ",
"to the 1st argument (a Green's class)");
fi;
return GreensHClassOfElementNC(C, x, IsGreensClassNC(C));
end);
# same method for regular/ideals/inverse
InstallMethod(GreensHClassOfElementNC, "for a D/H-class and element",
[IsActingSemigroupGreensClass and IsGreensClass, IsMultiplicativeElement],
{C, x} -> GreensHClassOfElementNC(C, x, true));
# same method for regular/ideals, different method for inverse
InstallMethod(GreensHClassOfElementNC, "for a D/H-class, element, and bool",
[IsActingSemigroupGreensClass and IsGreensClass,
IsMultiplicativeElement,
IsBool],
function(C, x, isGreensClassNC)
local H;
H := SEMIGROUPS.CreateHClass(C, x, isGreensClassNC);
SEMIGROUPS.CopyLambda(C, H);
SEMIGROUPS.CopyRho(C, H);
if IsGreensDClass(C) then
SetDClassOfHClass(H, C);
fi;
return H;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(GreensHClassOfElementNC, "for an L-class, element, and bool",
[IsActingSemigroupGreensClass and IsGreensLClass, IsMultiplicativeElement,
IsBool],
function(L, x, isGreensClassNC)
local H;
H := SEMIGROUPS.CreateHClass(L, x, isGreensClassNC);
SEMIGROUPS.CopyRho(L, H);
SEMIGROUPS.SetLambda(H);
SetLClassOfHClass(H, L);
return H;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(GreensHClassOfElementNC, "for an R-class, element, and bool",
[IsActingSemigroupGreensClass and IsGreensRClass, IsMultiplicativeElement,
IsBool],
function(R, x, isGreensClassNC)
local H;
H := SEMIGROUPS.CreateHClass(R, x, isGreensClassNC);
SEMIGROUPS.CopyLambda(R, H);
SEMIGROUPS.SetRho(H);
SetRClassOfHClass(H, R);
return H;
end);
# different method for inverse/regular, same for ideals
InstallMethod(Size, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
local L, R;
L := LambdaOrbSchutzGp(LambdaOrb(D), LambdaOrbSCCIndex(D));
R := RhoOrbSchutzGp(RhoOrb(D), RhoOrbSCCIndex(D));
return Size(R) * Size(L) * Length(LambdaOrbSCC(D)) * Length(RhoOrbSCC(D)) /
Size(SchutzenbergerGroup(D));
end);
# same method for inverse/regular/ideals
InstallMethod(Size, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
R -> Size(SchutzenbergerGroup(R)) * Length(LambdaOrbSCC(R)));
# same method for regular/ideals, different method of inverse
InstallMethod(Size, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
L -> Size(SchutzenbergerGroup(L)) * Length(RhoOrbSCC(L)));
# same method for inverse/regular/ideals
InstallMethod(Size, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
H -> Size(SchutzenbergerGroup(H)));
# same method for regular/ideals, different for inverse
InstallMethod(\in, "for mult. elt. and D-class of acting semigroup",
[IsMultiplicativeElement, IsGreensDClass and IsActingSemigroupGreensClass],
function(x, D)
local S, rep, o, m, scc, l, schutz, cosets, membership, one, p;
S := Parent(D);
rep := Representative(D);
if ElementsFamily(FamilyObj(S)) <> FamilyObj(x)
or (IsActingSemigroupWithFixedDegreeMultiplication(S)
and ActionDegree(x) <> ActionDegree(rep))
or ActionRank(S)(x) <> ActionRank(S)(rep) then
return false;
fi;
x := ConvertToInternalElement(S, x);
o := LambdaOrb(D);
m := LambdaOrbSCCIndex(D);
scc := OrbSCC(o);
l := Position(o, LambdaFunc(S)(x));
if l = fail or OrbSCCLookup(o)[l] <> m then
return false;
elif l <> scc[m][1] then
x := x * LambdaOrbMult(o, m, l)[2];
fi;
o := RhoOrb(D);
m := RhoOrbSCCIndex(D);
scc := OrbSCC(o);
l := Position(o, RhoFunc(S)(x));
schutz := RhoOrbStabChain(D);
if l = fail or OrbSCCLookup(o)[l] <> m then
return false;
elif schutz = true then
return true;
elif l <> scc[m][1] then
x := RhoOrbMult(o, m, l)[2] * x;
fi;
cosets := LambdaCosets(D);
rep := D!.rep;
x := LambdaPerm(S)(rep, x);
membership := SchutzGpMembership(S);
one := LambdaIdentity(S)(ActionRank(S)(rep));
if schutz <> false then
for p in cosets do
if membership(schutz, x / p) then
return true;
fi;
od;
else
for p in cosets do
if x / p = one then
return true;
fi;
od;
fi;
return false;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(\in, "for multiplicative element and L-class of acting semigroup",
[IsMultiplicativeElement, IsGreensLClass and IsActingSemigroupGreensClass],
function(x, L)
local S, rep, o, m, scc, l, schutz;
S := Parent(L);
rep := Representative(L);
if ElementsFamily(FamilyObj(S)) <> FamilyObj(x)
or (IsActingSemigroupWithFixedDegreeMultiplication(S)
and ActionDegree(x) <> ActionDegree(rep))
or ActionRank(S)(x) <> ActionRank(S)(rep)
or LambdaFunc(S)(x) <> LambdaFunc(S)(rep) then
return false;
fi;
x := ConvertToInternalElement(S, x);
rep := L!.rep;
o := RhoOrb(L);
m := RhoOrbSCCIndex(L);
scc := OrbSCC(o);
l := Position(o, RhoFunc(S)(x));
schutz := RhoOrbStabChain(L);
if l = fail or OrbSCCLookup(o)[l] <> m then
return false;
elif schutz = true then
return true;
elif l <> scc[m][1] then
x := RhoOrbMult(o, m, l)[2] * x;
fi;
if x = rep then
return true;
elif schutz = false then
return false;
fi;
return SchutzGpMembership(S)(schutz, LambdaPerm(S)(rep, x));
end);
# same method for regular/inverse/ideals
InstallMethod(\in, "for multiplicative element and R-class of acting semigroup",
[IsMultiplicativeElement, IsGreensRClass and IsActingSemigroupGreensClass],
function(x, R)
local S, rep, o, m, scc, l, schutz;
S := Parent(R);
rep := Representative(R);
if ElementsFamily(FamilyObj(S)) <> FamilyObj(x)
or (IsActingSemigroupWithFixedDegreeMultiplication(S)
and ActionDegree(x) <> ActionDegree(rep))
or ActionRank(S)(x) <> ActionRank(S)(rep)
or RhoFunc(S)(x) <> RhoFunc(S)(rep) then
return false;
fi;
x := ConvertToInternalElement(S, x);
rep := R!.rep;
o := LambdaOrb(R);
m := LambdaOrbSCCIndex(R);
scc := OrbSCC(o);
l := Position(o, LambdaFunc(S)(x));
schutz := LambdaOrbStabChain(o, m);
if l = fail or OrbSCCLookup(o)[l] <> m then
return false;
elif schutz = true then
return true;
elif l <> scc[m][1] then
x := x * LambdaOrbMult(o, m, l)[2];
fi;
if x = rep then
return true;
elif schutz = false then
return false;
fi;
return SchutzGpMembership(S)(schutz, LambdaPerm(S)(rep, x));
end);
# same method for regular/inverse/ideals
InstallMethod(\in, "for element and acting semigroup H-class",
[IsMultiplicativeElement, IsGreensHClass and IsActingSemigroupGreensClass],
function(x, H)
local S, rep;
S := Parent(H);
rep := Representative(H);
if ElementsFamily(FamilyObj(S)) <> FamilyObj(x)
or (IsActingSemigroupWithFixedDegreeMultiplication(S)
and ActionDegree(x) <> ActionDegree(rep))
or ActionRank(S)(x) <> ActionRank(S)(rep)
or RhoFunc(S)(x) <> RhoFunc(S)(rep)
or LambdaFunc(S)(x) <> LambdaFunc(S)(rep) then
return false;
fi;
x := ConvertToInternalElement(S, x);
rep := H!.rep;
return LambdaPerm(S)(rep, x) in SchutzenbergerGroup(H);
end);
#############################################################################
## 4. Collections of classes, and reps
#############################################################################
# These are not rho-rectified!
# different methods for regular/inverse/ideals
InstallMethod(DClassReps, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local data, scc, out, i;
data := Enumerate(SemigroupData(S), infinity, ReturnFalse);
scc := OrbSCC(data);
out := EmptyPlist(Length(scc) - 1);
for i in [2 .. Length(scc)] do
out[i - 1] := ConvertToExternalElement(S, data[scc[i][1]][4]);
od;
return out;
end);
InstallMethod(RelativeDClassReps, "for an acting semigroup and subsemigroup",
[IsActingSemigroup, IsActingSemigroup],
function(S, T)
local data, D, gens, genstoapply, x, i, j;
if not IsSubsemigroup(S, T) then
ErrorNoReturn("the 2nd argument (an acting semigroup) must be ",
"a subsemigroup of the 1st argument (an acting semigroup)");
fi;
data := Enumerate(SemigroupData(S, RelativeLambdaOrb(S, T)));
D := List([1 .. Length(data)], x -> []);
gens := GeneratorsOfSemigroup(T);
genstoapply := [1 .. Length(gens)];
for i in [2 .. Length(data)] do
x := data[i][4];
for j in genstoapply do
Add(D[i], Position(data, gens[j] * x));
od;
od;
D := DigraphStronglyConnectedComponents(Digraph(D)).comps;
D := List(D, x -> x[1]){[2 .. Length(D)]};
return List(data{D}, x -> x[4]);
end);
InstallMethod(RelativeRClassReps, "for an acting semigroup and subsemigroup",
[IsActingSemigroup, IsActingSemigroup],
function(S, T)
local data;
if not IsSubsemigroup(S, T) then
ErrorNoReturn("the 2nd argument (an acting semigroup) must be ",
"a subsemigroup of the 1st argument (an acting semigroup)");
fi;
data := Enumerate(SemigroupData(S, RelativeLambdaOrb(S, T)));
return List(data, x -> x[4]);
end);
# different method for regular/inverse/ideals
InstallMethod(GreensDClasses, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local data, scc, out, CreateDClass, RectifyRho, next, D, i;
data := Enumerate(SemigroupData(S), infinity, ReturnFalse);
scc := OrbSCC(data);
out := EmptyPlist(Length(scc));
CreateDClass := SEMIGROUPS.CreateDClass;
RectifyRho := SEMIGROUPS.RectifyRho;
for i in [2 .. Length(scc)] do
next := data[scc[i][1]];
# don't use GreensDClassOfElementNC here since we don't have to lookup scc
# indices or rectify lambda
D := CreateDClass(S, next[4], false);
SetLambdaOrb(D, LambdaOrb(S));
SetLambdaOrbSCCIndex(D, next[2]);
SetRhoOrb(D, RhoOrb(S));
SetRhoOrbSCCIndex(D, OrbSCCLookup(RhoOrb(S))[data!.rholookup[next[6]]]);
RectifyRho(D);
SetSemigroupDataIndex(D, next[6]);
out[i - 1] := D;
od;
return out;
end);
# same method for regular/inverse/ideals
InstallMethod(LClassReps, "for an acting semigroup",
[IsActingSemigroup],
S -> Concatenation(List(GreensDClasses(S), LClassReps)));
# same method for regular/inverse/ideals
InstallMethod(GreensLClasses, "for an acting semigroup",
[IsActingSemigroup],
S -> Concatenation(List(GreensDClasses(S), GreensLClasses)));
# same method for regular/inverse/ideals
InstallMethod(LClassReps, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
local scc, mults, cosets, rep, act, out, nr, x, p, i;
scc := LambdaOrbSCC(D);
mults := LambdaOrbMults(LambdaOrb(D), LambdaOrbSCCIndex(D));
cosets := LambdaCosets(D);
rep := D!.rep;
act := StabilizerAction(Parent(D));
out := EmptyPlist(Length(scc) * Length(cosets));
nr := 0;
for p in cosets do
x := act(rep, p);
for i in scc do
nr := nr + 1;
# don't use GreensLClassOfElementNC cos we don't need to rectify the
# rho-value
out[nr] := x * mults[i][1];
od;
od;
return out;
end);
# same method for regular/ideals, different for inverse
InstallMethod(GreensLClasses, "for a D-class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensDClass],
function(D)
local reps, out, CreateLClass, CopyRho, i;
reps := LClassReps(D);
out := EmptyPlist(Length(reps));
CreateLClass := SEMIGROUPS.CreateLClass;
CopyRho := SEMIGROUPS.CopyRho;
for i in [1 .. Length(reps)] do
# don't use GreensLClassOfElementNC cos we don't need to rectify the
# rho-value
out[i] := CreateLClass(D, reps[i], IsGreensClassNC(D));
CopyRho(D, out[i]);
SetDClassOfLClass(out[i], D);
od;
return out;
end);
# different method for regular/inverse, same method for ideals
InstallMethod(RClassReps, "for an acting semigroup", [IsActingSemigroup],
function(S)
local data, out, i;
data := Enumerate(SemigroupData(S));
out := EmptyPlist(Length(data) - 1);
for i in [2 .. Length(data)] do
out[i - 1] := data[i][4];
od;
return out;
end);
# different method for regular/inverse, same for ideals
InstallMethod(GreensRClasses, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local reps, out, data, CreateRClass, i;
reps := RClassReps(S);
out := EmptyPlist(Length(reps));
data := SemigroupData(S);
CreateRClass := SEMIGROUPS.CreateRClass;
for i in [1 .. Length(reps)] do
# don't use GreensRClassOfElementNC cos we don't need to rectify the
# lambda-value
out[i] := CreateRClass(S, reps[i], false);
SetLambdaOrb(out[i], LambdaOrb(S));
SetLambdaOrbSCCIndex(out[i], data[i + 1][2]);
SetSemigroupDataIndex(out[i], i + 1);
od;
return out;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(RClassReps, "for a D-class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensDClass],
function(D)
local scc, mults, cosets, rep, act, out, nr, x, i, p;
scc := RhoOrbSCC(D);
mults := RhoOrbMults(RhoOrb(D), RhoOrbSCCIndex(D));
cosets := RhoCosets(D);
rep := D!.rep;
act := StabilizerAction(Parent(D));
out := EmptyPlist(Length(scc) * Length(cosets));
nr := 0;
for p in cosets do
x := act(rep, p ^ -1);
for i in scc do
nr := nr + 1;
out[nr] := mults[i][1] * x;
od;
od;
return out;
end);
# same method for regular/inverse/ideals
InstallMethod(GreensRClasses, "for a D-class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensDClass],
function(D)
local reps, out, CreateRClass, CopyLambda, i;
reps := RClassReps(D);
out := EmptyPlist(Length(reps));
CreateRClass := SEMIGROUPS.CreateRClass;
CopyLambda := SEMIGROUPS.CopyLambda;
for i in [1 .. Length(reps)] do
# don't use GreensRClassOfElementNC cos we don't need to rectify the
# lambda-value
out[i] := CreateRClass(D, reps[i], IsGreensClassNC(D));
CopyLambda(D, out[i]);
SetDClassOfRClass(out[i], D);
od;
return out;
end);
# same method for regular/inverse/ideals
InstallMethod(HClassReps, "for an acting semigroup",
[IsActingSemigroup], S -> Concatenation(List(GreensRClasses(S), HClassReps)));
# same method for regular/inverse/ideals
InstallMethod(GreensHClasses, "for an acting semigroup",
[IsActingSemigroup],
S -> Concatenation(List(GreensDClasses(S), GreensHClasses)));
# same method for regular/inverse/ideals
InstallMethod(HClassReps, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
D -> Concatenation(List(GreensRClasses(D), HClassReps)));
# same method for regular/inverse/ideals
InstallMethod(GreensHClasses, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
D -> Concatenation(List(GreensRClasses(D), GreensHClasses)));
# same method for regular/inverse/ideals
InstallMethod(HClassReps, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
function(R)
local scc, mults, cosets, rep, act, out, nr, x, i, p;
scc := LambdaOrbSCC(R);
mults := LambdaOrbMults(LambdaOrb(R), LambdaOrbSCCIndex(R));
cosets := LambdaCosets(DClassOfRClass(R));
rep := R!.rep;
act := StabilizerAction(Parent(R));
out := EmptyPlist(Length(scc) * Length(cosets));
nr := 0;
for p in cosets do
x := act(rep, p);
for i in scc do
nr := nr + 1;
out[nr] := ConvertToExternalElement(Parent(R), x * mults[i][1]);
od;
od;
return out;
end);
# same method for regular/inverse/ideals
InstallMethod(GreensHClasses, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
function(R)
local reps, out, i;
reps := HClassReps(R);
out := [GreensHClassOfElementNC(R, reps[1], IsGreensClassNC(R))];
# do this rather than GreensHClassOfElement(R, reps[i]) to
# avoid recomputing the RhoOrb.
for i in [2 .. Length(reps)] do
out[i] := GreensHClassOfElementNC(out[1], reps[i], IsGreensClassNC(R));
SetRClassOfHClass(out[i], R);
od;
return out;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(HClassReps, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
function(L)
local scc, mults, cosets, rep, act, out, nr, x, p, i;
scc := RhoOrbSCC(L);
mults := RhoOrbMults(RhoOrb(L), RhoOrbSCCIndex(L));
cosets := RhoCosets(L);
# These are the rho cosets of the D-class containing L rectified so that they
# correspond to the lambda value of the rep of L and not the lambda value of
# the rep of the D-class.
rep := L!.rep;
act := StabilizerAction(Parent(L));
out := EmptyPlist(Length(scc) * Length(cosets));
nr := 0;
for p in cosets do
x := act(rep, p ^ -1);
for i in scc do
nr := nr + 1;
out[nr] := ConvertToExternalElement(Parent(L), mults[i][1] * x);
od;
od;
return out;
end);
# same method for regular/ideals, different for inverse
InstallMethod(GreensHClasses, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
function(L)
local reps, out, i;
reps := HClassReps(L);
out := [GreensHClassOfElementNC(L, reps[1], IsGreensClassNC(L))];
# do this rather than GreensHClassOfElement(L, reps[i]) to
# avoid recomputing the RhoOrb.
for i in [2 .. Length(reps)] do
out[i] := GreensHClassOfElementNC(out[1], reps[i], IsGreensClassNC(L));
SetLClassOfHClass(out[i], L);
od;
return out;
end);
#############################################################################
# different method for regular/inverse, same for ideals
InstallMethod(NrDClasses, "for an acting semigroup",
[IsActingSemigroup],
S -> Length(OrbSCC(SemigroupData(S))) - 1);
# different method for regular/inverse, same for ideals
InstallMethod(NrLClasses, "for an acting semigroup",
[IsActingSemigroup], S -> Sum(List(GreensDClasses(S), NrLClasses)));
# different method for regular/inverse, same for ideals
InstallMethod(NrLClasses, "for a D-class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensDClass],
D -> Length(LambdaCosets(D)) * Length(LambdaOrbSCC(D)));
# different method for regular/inverse, same for ideals
InstallMethod(NrRClasses, "for an acting semigroup", [IsActingSemigroup],
S -> Length(Enumerate(SemigroupData(S), infinity, ReturnFalse)) - 1);
# different method for regular/inverse, same for ideals
InstallMethod(NrRClasses, "for a D-class of an acting semigroup",
[IsActingSemigroupGreensClass and IsGreensDClass],
D -> Length(RhoCosets(D)) * Length(RhoOrbSCC(D)));
# same method for regular/inverse/ideals
InstallMethod(NrHClasses, "for an acting semigroup", [IsActingSemigroup],
S -> Sum(List(GreensDClasses(S), NrHClasses)));
# same method for regular/ideals, different method for inverse
InstallMethod(GroupHClassOfGreensDClass,
"for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
local S, rho, o, scc, tester, rep, i;
if HasIsRegularGreensClass(D) and not IsRegularGreensClass(D) then
return fail;
fi;
S := Parent(D);
rho := RhoFunc(S)(D!.rep);
o := LambdaOrb(D);
scc := LambdaOrbSCC(D);
tester := IdempotentTester(S);
for i in scc do
if tester(o[i], rho) then
if not HasIsRegularGreensClass(D) then
SetIsRegularGreensClass(D, true);
fi;
rep := ConvertToExternalElement(S, IdempotentCreator(S)(o[i], rho));
return GreensHClassOfElementNC(D, rep, IsGreensClassNC(D));
fi;
od;
if not HasIsRegularGreensClass(D) then
SetIsRegularGreensClass(D, false);
fi;
return fail;
end);
# same method for regular/inverse/ideals
InstallMethod(IsGroupHClass, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local S, x;
S := Parent(H);
x := H!.rep;
return IdempotentTester(S)(LambdaFunc(S)(x), RhoFunc(S)(x));
end);
# same method for regular/inverse/ideals
InstallMethod(IsomorphismPermGroup, "for H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local map, id, iso, inv;
if not IsGroupHClass(H) then
ErrorNoReturn("the argument (a Green's H-class) is not a group");
elif not IsPermGroup(SchutzenbergerGroup(H)) then
map := IsomorphismPermGroup(SchutzenbergerGroup(H));
else
map := IdentityMapping(SchutzenbergerGroup(H));
fi;
id := ConvertToInternalElement(Parent(H), MultiplicativeNeutralElement(H));
iso := function(x)
if not x in H then
ErrorNoReturn("the argument does not belong to the domain of the ",
"function");
fi;
x := ConvertToInternalElement(Parent(H), x);
return LambdaPerm(Parent(H))(id, x) ^ map;
end;
inv := function(x)
local S, act;
if not x in Image(map) then
ErrorNoReturn("the argument does not belong to the domain of the ",
"function");
fi;
S := Parent(H);
act := StabilizerAction(S);
return ConvertToExternalElement(S,
act(id, x ^ InverseGeneralMapping(map)));
end;
return MappingByFunction(H, Range(map), iso, inv);
end);
# different method for regular/inverse/ideals
InstallMethod(PartialOrderOfDClasses, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local D, n, out, data, gens, graph, datalookup, i, j, k, x, f;
D := GreensDClasses(S);
n := Length(D);
out := List([1 .. n], x -> []);
data := SemigroupData(S);
gens := data!.gens;
graph := data!.graph;
datalookup := OrbSCCLookup(data) - 1;
for i in [1 .. n] do
# collect info about left multiplying R-class reps of D[i] by gens
for j in OrbSCC(data)[OrbSCCLookup(data)[SemigroupDataIndex(D[i])]] do
for k in graph[j] do
AddSet(out[i], datalookup[k]);
od;
od;
for x in gens do
for f in LClassReps(D[i]) do
AddSet(out[i], datalookup[Position(data, f * x)]);
od;
od;
od;
Perform(out, ShrinkAllocationPlist);
D := DigraphNC(IsMutableDigraph, out);
DigraphRemoveLoops(D);
MakeImmutable(D);
return D;
end);
InstallMethod(LeftGreensMultiplierNC,
"for an acting semigroup and L-related elements",
[IsActingSemigroup, IsMultiplicativeElement, IsMultiplicativeElement],
function(S, a, b)
local o, l, m, result, p;
o := Enumerate(RhoOrb(S));
l := Position(o, RhoFunc(S)(a));
m := OrbSCCLookup(o)[l];
# back to the first pos. in scc
result := RhoOrbMult(o, m, l)[2];
l := Position(o, RhoFunc(S)(b));
# out to the same pos. as b
result := RhoOrbMult(o, m, l)[1] * result;
# result * a * LambdaPerm(S)(result * a, b) = b
p := LambdaPerm(S)(result * a, b);
# Apply the inverse of the bijection \Psi in Proposition 3.11 of the Citrus
# paper, to convert p from acting on the right to action on the left
return result * StabilizerAction(S)(a, p) * WeakInverse(a);
end);
InstallMethod(RightGreensMultiplierNC,
"for an acting semigroup and R-related elements",
[IsActingSemigroup, IsMultiplicativeElement, IsMultiplicativeElement],
function(S, a, b)
local o, l, m, result, p;
o := Enumerate(LambdaOrb(S));
l := Position(o, LambdaFunc(S)(a));
m := OrbSCCLookup(o)[l];
# back to the first pos. in scc
result := LambdaOrbMult(o, m, l)[2];
l := Position(o, LambdaFunc(S)(b));
# out to the same pos. as b
result := result * LambdaOrbMult(o, m, l)[1];
# At this point StabilizerAction(a * result, LambdaPerm(S)(a * result, b)) =
# b.
p := LambdaPerm(S)(a * result, b);
return WeakInverse(a) * StabilizerAction(S)(a * result, p);
end);
#############################################################################
## 5. Idempotents . . .
#############################################################################
# same method for regular/ideals, different method for inverse
InstallMethod(Idempotents, "for an acting semigroup", [IsActingSemigroup],
function(S)
local out, nr, tester, creator, rho_o, scc, lambda_o, gens, rhofunc, lookup,
rep, rho, j, i, k;
if HasRClasses(S) or not IsRegularSemigroup(S) then
return Concatenation(List(GreensRClasses(S), Idempotents));
fi;
out := [];
nr := 0;
tester := IdempotentTester(S);
creator := IdempotentCreator(S);
rho_o := RhoOrb(S);
scc := OrbSCC(rho_o);
lambda_o := LambdaOrb(S);
Enumerate(lambda_o, infinity);
gens := lambda_o!.gens;
rhofunc := RhoFunc(S);
lookup := OrbSCCLookup(rho_o);
for i in [2 .. Length(lambda_o)] do
# TODO(later) this could be better, just take the product with the next
# schreiergen every time
rep := EvaluateWord(lambda_o, TraceSchreierTreeForward(lambda_o, i));
rho := rhofunc(rep);
j := lookup[Position(rho_o, rho)];
for k in scc[j] do
if tester(lambda_o[i], rho_o[k]) then
nr := nr + 1;
out[nr] := creator(lambda_o[i], rho_o[k]);
fi;
od;
od;
if not HasNrIdempotents(S) then
SetNrIdempotents(S, nr);
fi;
return out;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(Idempotents,
"for an acting semigroup and a positive integer",
[IsActingSemigroup, IsInt],
function(S, n)
local out, nr, tester, creator, rho_o, scc, lambda_o, gens, rhofunc, lookup,
rank, rep, rho, j, i, k;
if n < 0 then
ErrorNoReturn("the 2nd argument (an integer) is not non-negative");
elif n > Maximum(List(GeneratorsOfSemigroup(S), x -> ActionRank(S)(x))) then
return [];
elif HasIdempotents(S) or not IsRegularSemigroup(S) then
return Filtered(Idempotents(S), x -> ActionRank(S)(x) = n);
fi;
out := [];
nr := 0;
tester := IdempotentTester(S);
creator := IdempotentCreator(S);
rho_o := RhoOrb(S);
scc := OrbSCC(rho_o);
lambda_o := LambdaOrb(S);
gens := lambda_o!.gens;
rhofunc := RhoFunc(S);
lookup := OrbSCCLookup(rho_o);
rank := RhoRank(S);
Enumerate(lambda_o, infinity);
for i in [2 .. Length(lambda_o)] do
# TODO(later) this could be better, just take the product with the next
# schreiergen every time
rep := EvaluateWord(lambda_o, TraceSchreierTreeForward(lambda_o, i));
rho := rhofunc(rep);
j := lookup[Position(rho_o, rho)];
if rank(rho_o[scc[j][1]]) = n then
for k in scc[j] do
if tester(lambda_o[i], rho_o[k]) then
nr := nr + 1;
out[nr] := creator(lambda_o[i], rho_o[k]);
fi;
od;
fi;
od;
return out;
end);
# same method for regular/ideals, different method for inverse
InstallMethod(Idempotents, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
if HasIsRegularGreensClass(D) and not IsRegularGreensClass(D) then
# this avoids creating the R-classes, which is an unnecessary overhead
return [];
fi;
return Concatenation(List(GreensRClasses(D), Idempotents));
end);
# same method for regular/ideals, different method for inverse
InstallMethod(Idempotents, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
L -> SEMIGROUPS.Idempotents(L,
LambdaFunc(Parent(L))(L!.rep),
RhoOrbSCC(L),
RhoOrb(L),
false));
# same method for regular/ideals, different method for inverse
InstallMethod(Idempotents, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
R -> SEMIGROUPS.Idempotents(R,
RhoFunc(Parent(R))(R!.rep),
LambdaOrbSCC(R),
LambdaOrb(R),
true));
# same method for regular/inverse/ideals
InstallMethod(Idempotents, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
local S, x;
if not IsGroupHClass(H) then
return [];
fi;
S := Parent(H);
x := H!.rep;
return [ConvertToExternalElement(S,
IdempotentCreator(S)(LambdaFunc(S)(x),
RhoFunc(S)(x)))];
end);
# Number of idempotents . . .
# different method for regular/inverse, same for ideals
InstallMethod(NrIdempotents, "for an acting semigroup", [IsActingSemigroup],
function(S)
local data, lambda, rho, scc, lenreps, repslens, rholookup, repslookup,
tester, nr, rhoval, m, ind, i;
if HasIdempotents(S) then
return Length(Idempotents(S));
fi;
data := Enumerate(SemigroupData(S), infinity, ReturnFalse);
lambda := LambdaOrb(S);
rho := RhoOrb(S);
scc := OrbSCC(lambda);
lenreps := data!.lenreps;
repslens := data!.repslens;
rholookup := data!.rholookup;
repslookup := data!.repslookup;
tester := IdempotentTester(S);
nr := 0;
for m in [2 .. Length(scc)] do
for ind in [1 .. lenreps[m]] do
if repslens[m][ind] = 1 then
rhoval := rho[rholookup[repslookup[m][ind][1]]];
for i in scc[m] do
if tester(lambda[i], rhoval) then
nr := nr + 1;
fi;
od;
fi;
od;
od;
return nr;
end);
# same method for regular/inverse/ideals
InstallMethod(NrIdempotents, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
D -> Sum(List(GreensRClasses(D), NrIdempotents)));
# same method for regular/ideals, different method for inverse
InstallMethod(NrIdempotents, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
L -> SEMIGROUPS.NrIdempotents(L,
LambdaFunc(Parent(L))(L!.rep),
RhoOrbSCC(L),
RhoOrb(L),
false));
# same method for regular/ideals, different method inverse
InstallMethod(NrIdempotents, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
R -> SEMIGROUPS.NrIdempotents(R,
RhoFunc(Parent(R))(R!.rep),
LambdaOrbSCC(R),
LambdaOrb(R),
true));
# same method for regular/inverse/ideals
InstallMethod(NrIdempotents, "for a H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass],
function(H)
if IsGroupHClass(H) then
return 1;
fi;
return 0;
end);
#############################################################################
## 6. Regular classes . . .
#############################################################################
# not required for regular/inverse, same for ideals
InstallMethod(IsRegularGreensClass, "for an D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
D -> SEMIGROUPS.IsRegularGreensClass(D,
RhoFunc(Parent(D))(D!.rep),
LambdaOrbSCC(D),
LambdaOrb(D),
true));
# not required for regular/inverse, same for ideals
InstallMethod(IsRegularGreensClass, "for an L-class of an acting semigroup",
[IsGreensLClass and IsActingSemigroupGreensClass],
L -> SEMIGROUPS.IsRegularGreensClass(L,
LambdaFunc(Parent(L))(L!.rep),
RhoOrbSCC(L),
RhoOrb(L),
false));
# not required for regular/inverse, same for ideals
InstallMethod(IsRegularGreensClass, "for an R-class of an acting semigroup",
[IsGreensRClass and IsActingSemigroupGreensClass],
R -> SEMIGROUPS.IsRegularGreensClass(R,
RhoFunc(Parent(R))(R!.rep),
LambdaOrbSCC(R),
LambdaOrb(R),
true));
# same method for regular/inverse, same method for ideals
InstallMethod(IsRegularGreensClass, "for an H-class of an acting semigroup",
[IsGreensHClass and IsActingSemigroupGreensClass], IsGroupHClass);
# different method for regular/inverse/ideals
InstallMethod(NrRegularDClasses, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local data, datascc, rho, lambda, scc, rholookup, tester, nr, j, rhoval, i,
k;
data := SemigroupData(S);
datascc := OrbSCC(data);
rho := RhoOrb(S);
lambda := LambdaOrb(S);
scc := OrbSCC(lambda);
rholookup := data!.rholookup;
tester := IdempotentTester(S);
nr := 0;
for i in [2 .. Length(datascc)] do
j := datascc[i][1];
# data of the first R-class in the D-class corresponding to x
rhoval := rho[rholookup[j]];
for k in scc[data[j][2]] do
if tester(lambda[k], rhoval) then
nr := nr + 1;
break;
fi;
od;
od;
return nr;
end);
#############################################################################
## 7. Iterators and enumerators . . .
#############################################################################
#############################################################################
## 7.a. for all classes
#############################################################################
# different method for regular/inverse
InstallMethod(IteratorOfRClassReps, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local record;
record := rec();
record.i := 1;
record.parent := S;
record.NextIterator := function(iter)
local data;
iter!.i := iter!.i + 1;
data := Enumerate(SemigroupData(iter!.parent), iter!.i, ReturnFalse);
if iter!.i > Length(data!.orbit) then
return fail;
fi;
return data[iter!.i][4];
end;
record.ShallowCopy := iter -> rec(i := 1, parent := iter!.parent);
return IteratorByNextIterator(record);
end);
# same method for regular/inverse
InstallMethod(IteratorOfRClasses, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local record;
if HasGreensRClasses(S) then
return IteratorList(GreensRClasses(S));
fi;
record := rec();
record.parent := S;
return WrappedIterator(IteratorOfRClassReps(S),
{iter, x} -> GreensRClassOfElementNC(iter!.parent, x),
record);
end);
# different method for regular/inverse
InstallMethod(IteratorOfDClasses, "for an acting semigroup",
[IsActingSemigroup],
function(S)
local iter, convert, isnew;
if IsClosedData(SemigroupData(S)) then
return IteratorList(GreensDClasses(S));
fi;
convert := function(iter, x)
local D;
D := DClassOfRClass(GreensRClassOfElementNC(S, x));
Add(iter!.classes, D);
return D;
end;
isnew := {iter, x} -> x = fail or ForAll(iter!.classes, D -> not x in D);
return WrappedIterator(IteratorOfRClassReps(S),
convert,
rec(classes := []),
isnew);
end);
########################################################################
# 7.b. for individual classes
########################################################################
# different method for regular/inverse
InstallMethod(Enumerator, "for a D-class of an acting semigroup",
[IsGreensDClass and IsActingSemigroupGreensClass],
function(D)
local record, convert_out, convert_in, i;
record := rec();
record.parent := D; # required by WrappedEnumerator
record.underlying_enums := List(GreensRClasses(D), Enumerator);
record.lengths := [];
for i in [1 .. NrRClasses(D)] do
record.lengths[i] := Sum(record.underlying_enums{[1 .. i]}, Length);
od;
convert_out := function(enum, pos)
local index;
index := PositionSorted(enum!.lengths, pos);
if index > 1 then
pos := pos - enum!.lengths[index - 1];
fi;
--> --------------------
--> maximum size reached
--> --------------------
[ Dauer der Verarbeitung: 0.45 Sekunden
(vorverarbeitet)
]
|