|
|
|
|
Quelle froidure-pin.gi
Sprache: unbekannt
|
|
###########################################################################
##
## libsemigroups/froidure-pin.gi
## Copyright (C) 2022 James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
###########################################################################
##
# We have the following loop instead of IsMatrixOverSemiringSemigroup because
# semigroups of matrices over a finite field below to
# IsMatrixOverSemiringSemigroup, but cannot compute LibsemigroupsFroidurePin
InstallTrueMethod(CanUseFroidurePin, CanUseLibsemigroupsFroidurePin);
for x in [IsFpSemigroup,
IsFpMonoid,
IsTransformationSemigroup,
IsBooleanMatSemigroup,
IsIntegerMatrixSemigroup,
IsIntegerMatrixMonoid,
IsMaxPlusMatrixSemigroup,
IsMinPlusMatrixSemigroup,
IsTropicalMinPlusMatrixSemigroup,
IsTropicalMaxPlusMatrixSemigroup,
IsNTPMatrixSemigroup,
IsProjectiveMaxPlusMatrixSemigroup,
IsBipartitionSemigroup,
IsPBRSemigroup,
IsTransformationSemigroup,
IsPartialPermSemigroup] do
InstallTrueMethod(CanUseLibsemigroupsFroidurePin,
x and HasGeneratorsOfSemigroup);
InstallTrueMethod(CanUseLibsemigroupsFroidurePin,
x and IsSemigroupIdeal);
od;
InstallMethod(CanUseLibsemigroupsFroidurePin, "for a semigroup", [IsSemigroup],
ReturnFalse);
InstallImmediateMethod(CanUseLibsemigroupsFroidurePin,
IsQuotientSemigroup and HasQuotientSemigroupCongruence, 0,
Q -> CanUseLibsemigroupsCongruence(QuotientSemigroupCongruence(Q)));
###########################################################################
## Function for getting the correct record from the `libsemigroups` record.
###########################################################################
DeclareOperation("FroidurePinMemFnRec", [IsSemigroup]);
DeclareOperation("FroidurePinMemFnRec",
[IsSemigroup, IsListOrCollection]);
InstallMethod(FroidurePinMemFnRec, "for a semigroup",
[IsSemigroup], S -> FroidurePinMemFnRec(S, []));
InstallMethod(FroidurePinMemFnRec, "for a semigroup",
[IsSemigroup, IsListOrCollection], {S, coll} -> FroidurePinMemFnRec(S));
InstallMethod(FroidurePinMemFnRec,
"for a transformation semigroup and list or coll.",
[IsTransformationSemigroup, IsListOrCollection],
function(S, coll)
local N;
N := DegreeOfTransformationSemigroup(S);
if IsTransformationCollection(coll) then
N := Maximum(N, DegreeOfTransformationCollection(coll));
elif not IsEmpty(coll) then
Error("Expected a transf. coll. or empty list, found ",
TNAM_OBJ(coll));
fi;
if N <= 16
and IsBound(LIBSEMIGROUPS_HPCOMBI_ENABLED) then
return libsemigroups.FroidurePinTransf16;
elif N <= 2 ^ 16 then
return libsemigroups.FroidurePinTransfUInt2;
elif N <= 2 ^ 32 then
return libsemigroups.FroidurePinTransfUInt4;
else
# Cannot currently test the next line
Error("transformation degree is too high!");
fi;
end);
InstallMethod(FroidurePinMemFnRec,
"for a partial perm. semigroup and list or coll.",
[IsPartialPermSemigroup, IsListOrCollection],
function(S, coll)
local N;
N := Maximum(DegreeOfPartialPermSemigroup(S),
CodegreeOfPartialPermSemigroup(S));
if IsPartialPermCollection(coll) then
N := Maximum(N,
DegreeOfPartialPermCollection(coll),
CodegreeOfPartialPermCollection(coll));
elif not IsEmpty(coll) then
Error("Expected a partial perm. coll. or empty list, found ",
TNAM_OBJ(coll));
fi;
if N <= 16 and IsBound(LIBSEMIGROUPS_HPCOMBI_ENABLED) then
return libsemigroups.FroidurePinPPerm16;
elif N <= 2 ^ 16 then
return libsemigroups.FroidurePinPPermUInt2;
elif N <= 2 ^ 32 then
return libsemigroups.FroidurePinPPermUInt4;
else
# Cannot currently test the next line
Error("partial perm degree is too high!");
fi;
end);
InstallMethod(FroidurePinMemFnRec, "for a boolean matrix semigroup",
[IsBooleanMatSemigroup],
function(S)
local N;
N := DimensionOfMatrixOverSemiring(Representative(S));
if N <= 8 then
return libsemigroups.FroidurePinBMat8;
else
return libsemigroups.FroidurePinBMat;
fi;
end);
InstallMethod(FroidurePinMemFnRec, "for a bipartition semigroup",
[IsBipartitionSemigroup], S -> libsemigroups.FroidurePinBipart);
InstallMethod(FroidurePinMemFnRec, "for an integer matrix semigroup",
[IsIntegerMatrixSemigroup], S -> libsemigroups.FroidurePinIntMat);
InstallMethod(FroidurePinMemFnRec, "for an integer matrix monoid",
[IsIntegerMatrixMonoid], S -> libsemigroups.FroidurePinIntMat);
InstallMethod(FroidurePinMemFnRec, "for an max-plus matrix semigroup",
[IsMaxPlusMatrixSemigroup], S -> libsemigroups.FroidurePinMaxPlusMat);
InstallMethod(FroidurePinMemFnRec, "for an min-plus matrix semigroup",
[IsMinPlusMatrixSemigroup], S -> libsemigroups.FroidurePinMinPlusMat);
InstallMethod(FroidurePinMemFnRec, "for a tropical max-plus matrix semigroup",
[IsTropicalMaxPlusMatrixSemigroup],
S -> libsemigroups.FroidurePinMaxPlusTruncMat);
InstallMethod(FroidurePinMemFnRec, "for a tropical min-plus matrix semigroup",
[IsTropicalMinPlusMatrixSemigroup],
S -> libsemigroups.FroidurePinMinPlusTruncMat);
InstallMethod(FroidurePinMemFnRec, "for an ntp matrix semigroup",
[IsNTPMatrixSemigroup], S -> libsemigroups.FroidurePinNTPMat);
InstallMethod(FroidurePinMemFnRec,
"for a projective max-plus matrix semigroup",
[IsProjectiveMaxPlusMatrixSemigroup],
S -> libsemigroups.FroidurePinProjMaxPlusMat);
InstallMethod(FroidurePinMemFnRec, "for a pbr semigroup",
[IsPBRSemigroup], S -> libsemigroups.FroidurePinPBR);
InstallMethod(FroidurePinMemFnRec, "for an fp semigroup",
[IsFpSemigroup], S -> libsemigroups.FroidurePinBase);
InstallMethod(FroidurePinMemFnRec, "for an fp monoid",
[IsFpMonoid], S -> libsemigroups.FroidurePinBase);
InstallMethod(FroidurePinMemFnRec, "for quotient semigroup",
[IsQuotientSemigroup], S -> libsemigroups.FroidurePinBase);
BindGlobal("_GetElement",
function(coll, x)
Assert(1, IsMultiplicativeElementCollection(coll) or IsMatrixObj(x));
Assert(1, IsMultiplicativeElement(x) or IsMatrixObj(x));
if IsPartialPermCollection(coll) then
return [x, Maximum(DegreeOfPartialPermCollection(coll),
CodegreeOfPartialPermCollection(coll))];
elif IsTransformationCollection(coll) then
return [x, DegreeOfTransformationCollection(coll)];
elif IsElementOfFpSemigroupCollection(coll) then
return SEMIGROUPS.ExtRepObjToWord(ExtRepOfObj(x)) - 1;
elif IsElementOfFpMonoidCollection(coll) then
if IsOne(x) then
return [0];
fi;
return SEMIGROUPS.ExtRepObjToWord(ExtRepOfObj(x));
fi;
return x;
end);
###########################################################################
## Constructor - constructs a libsemigroups LibsemigroupsFroidurePin object, #
## and adds the generators of the semigroup to that.
###########################################################################
InstallMethod(HasLibsemigroupsFroidurePin,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
return IsBound(S!.LibsemigroupsFroidurePin)
and IsValidGapbind14Object(S!.LibsemigroupsFroidurePin);
end);
InstallMethod(HasLibsemigroupsFroidurePin,
"for a semigroup",
[IsSemigroup],
ReturnFalse);
InstallGlobalFunction(LibsemigroupsFroidurePin,
function(S)
local C, record, T, add_generator, coll, x;
Assert(1, IsSemigroup(S));
Assert(1, CanUseLibsemigroupsFroidurePin(S));
if HasLibsemigroupsFroidurePin(S) then
return S!.LibsemigroupsFroidurePin;
elif IsFpSemigroup(S) or IsFpMonoid(S) then
C := LibsemigroupsCongruence(UnderlyingCongruence(S));
return libsemigroups.Congruence.quotient_froidure_pin(C);
elif IsQuotientSemigroup(S) then
C := QuotientSemigroupCongruence(S);
if not HasGeneratingPairsOfMagmaCongruence(C) then
GeneratingPairsOfMagmaCongruence(C);
fi;
C := LibsemigroupsCongruence(C);
return libsemigroups.Congruence.quotient_froidure_pin(C);
fi;
Unbind(S!.LibsemigroupsFroidurePin);
record := FroidurePinMemFnRec(S);
T := record.make();
add_generator := record.add_generator;
coll := GeneratorsOfSemigroup(S);
for x in coll do
add_generator(T, _GetElement(coll, x));
od;
S!.LibsemigroupsFroidurePin := T;
return T;
end);
###########################################################################
## Size/IsFinite
###########################################################################
InstallMethod(Size, "for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
if not IsFinite(S) then
return infinity;
fi;
return FroidurePinMemFnRec(S).size(LibsemigroupsFroidurePin(S));
end);
InstallMethod(IsFinite, "for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
if IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
TryNextMethod();
fi;
return FroidurePinMemFnRec(S).size(LibsemigroupsFroidurePin(S)) < infinity;
end);
###########################################################################
## AsSet/AsList etc
###########################################################################
InstallMethod(AsSet, "for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local result, sorted_at, T, i;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
elif IsPartialPermSemigroup(S) or IsFpSemigroup(S) or IsFpMonoid(S)
or IsQuotientSemigroup(S) then
# Special case required because < for libsemigroups PartialPerms and < for
# GAP partial perms are different; and also for IsFpSemigroup and
# IsFpMonoid and IsQuotientSemigroup because there's no sorted_at
return AsSet(AsList(S));
fi;
result := EmptyPlist(Size(S));
sorted_at := FroidurePinMemFnRec(S).sorted_at;
T := LibsemigroupsFroidurePin(S);
for i in [1 .. Size(S)] do
result[i] := sorted_at(T, i - 1);
od;
SetIsSSortedList(result, true);
return result;
end);
InstallMethod(AsListCanonical,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local result, at, T, i;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
elif IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
at := {T, i} -> EvaluateWord(GeneratorsOfSemigroup(S),
FroidurePinMemFnRec(S).factorisation(T, i) + 1);
else
at := FroidurePinMemFnRec(S).at;
fi;
result := EmptyPlist(Size(S));
T := LibsemigroupsFroidurePin(S);
for i in [1 .. Size(S)] do
result[i] := at(T, i - 1);
od;
return result;
end);
InstallMethod(AsList,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin], AsListCanonical);
###########################################################################
## Position etc
###########################################################################
InstallMethod(PositionCanonical,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
local T, record, word, pos, C;
if IsPartialPermSemigroup(S) then
if DegreeOfPartialPermSemigroup(S) < DegreeOfPartialPerm(x)
or CodegreeOfPartialPermSemigroup(S) < CodegreeOfPartialPerm(x) then
return fail;
fi;
elif IsTransformationSemigroup(S) then
if DegreeOfTransformationSemigroup(S) < DegreeOfTransformation(x) then
return fail;
fi;
elif IsFpSemigroup(S) or IsFpMonoid(S) then
if not x in S then
return fail;
fi;
T := LibsemigroupsFroidurePin(S);
record := FroidurePinMemFnRec(S);
word := _GetElement(S, x);
pos := record.current_position(T, word);
while pos < 0 do
record.enumerate(T, record.current_size(T) + 1);
pos := record.current_position(T, word);
od;
return pos + 1;
elif IsQuotientSemigroup(S) then
T := QuotientSemigroupPreimage(S);
C := QuotientSemigroupCongruence(S);
return CongruenceWordToClassIndex(C, Factorization(T, Representative(x)));
fi;
pos := FroidurePinMemFnRec(S).position(LibsemigroupsFroidurePin(S),
_GetElement(S, x));
if pos < 0 then
return fail;
fi;
return pos + 1;
end);
InstallMethod(Position,
"for a semigroup with CanUseLibsemigroupsFroidurePin, mult. element, and zero",
[IsSemigroup and CanUseLibsemigroupsFroidurePin,
IsMultiplicativeElement,
IsZeroCyc],
PositionOp);
InstallMethod(PositionOp,
"for a semigroup with CanUseLibsemigroupsFroidurePin, mult. element, and zero",
[IsSemigroup and CanUseLibsemigroupsFroidurePin,
IsMultiplicativeElement,
IsZeroCyc],
function(S, x, _)
local pos;
if IsPartialPermSemigroup(S) then
if DegreeOfPartialPermSemigroup(S) < DegreeOfPartialPerm(x)
or CodegreeOfPartialPermSemigroup(S) < CodegreeOfPartialPerm(x) then
return fail;
fi;
elif IsTransformationSemigroup(S) then
if DegreeOfTransformationSemigroup(S) < DegreeOfTransformation(x) then
return fail;
fi;
fi;
pos := FroidurePinMemFnRec(S).current_position(LibsemigroupsFroidurePin(S),
_GetElement(S, x));
if pos < 0 then
return fail;
else
return pos + 1;
fi;
end);
InstallMethod(PositionSortedOp,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
local pos;
if not IsFinite(S) then
Error("the 1st argument (a semigroup) is not finite");
elif IsPartialPermSemigroup(S) then
if DegreeOfPartialPermSemigroup(S) < DegreeOfPartialPerm(x)
or CodegreeOfPartialPermSemigroup(S) < CodegreeOfPartialPerm(x) then
return fail;
fi;
# Special case required because < for libsemigroups PartialPerms and < for
# GAP partial perms are different.
return Position(AsSet(S), x);
elif IsTransformationSemigroup(S) then
if DegreeOfTransformationSemigroup(S) < DegreeOfTransformation(x) then
return fail;
fi;
fi;
pos := FroidurePinMemFnRec(S).sorted_position(LibsemigroupsFroidurePin(S),
_GetElement(S, x));
if pos < 0 then
return fail;
else
return pos + 1;
fi;
end);
###########################################################################
## Membership
###########################################################################
InstallMethod(\in,
"for mult. element and a semigroup with CanUseLibsemigroupsFroidurePin",
[IsMultiplicativeElement, IsSemigroup and CanUseLibsemigroupsFroidurePin],
{x, S} -> PositionCanonical(S, x) <> fail);
###########################################################################
## NrIdempotents
###########################################################################
InstallMethod(NrIdempotents,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local F;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
elif IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
return Length(IdempotentsSubset(S, [1 .. Size(S)]));
fi;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).number_of_idempotents(F);
end);
InstallMethod(Idempotents,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
return FroidurePinMemFnRec(S).idempotents(LibsemigroupsFroidurePin(S));
end);
###########################################################################
## MinimalFactorization
###########################################################################
InstallMethod(MinimalFactorization,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos. int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsPosInt],
function(S, i)
local F;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).factorisation(F, i - 1) + 1;
end);
InstallMethod(MinimalFactorization,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
if not x in S then
Error("the 2nd argument (a mult. elt.) must belong to the ",
"1st argument (a semigroup)");
fi;
return MinimalFactorization(S, PositionCanonical(S, x));
end);
InstallMethod(Factorization,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos. int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsPosInt],
MinimalFactorization);
InstallMethod(Factorization,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
MinimalFactorization);
###########################################################################
## Prefixes, Suffixes, etc.
###########################################################################
InstallMethod(FirstLetter,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos. int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsPosInt],
function(S, i)
local F;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).first_letter(F, i - 1) + 1;
end);
InstallMethod(FirstLetter,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
if not x in S then
Error("the 2nd argument (a mult. elt.) must belong to the ",
"1st argument (a semigroup)");
fi;
return FirstLetter(S, PositionCanonical(S, x));
end);
InstallMethod(FinalLetter,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos. int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsPosInt],
function(S, i)
local F;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).final_letter(F, i - 1) + 1;
end);
InstallMethod(FinalLetter,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
if not x in S then
Error("the 2nd argument (a mult. elt.) must belong to the ",
"1st argument (a semigroup)");
fi;
return FinalLetter(S, PositionCanonical(S, x));
end);
InstallMethod(Prefix,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos. int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsPosInt],
function(S, i)
local F;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).prefix(F, i - 1) + 1;
end);
InstallMethod(Prefix,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
if not x in S then
Error("the 2nd argument (a mult. elt.) must belong to the ",
"1st argument (a semigroup)");
fi;
return Prefix(S, PositionCanonical(S, x));
end);
InstallMethod(Suffix,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos. int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsPosInt],
function(S, i)
local F;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).suffix(F, i - 1) + 1;
end);
InstallMethod(Suffix,
"for a semigroup with CanUseLibsemigroupsFroidurePin and mult. element",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsMultiplicativeElement],
function(S, x)
if not x in S then
Error("the 2nd argument (a mult. elt.) must belong to the ",
"1st argument (a semigroup)");
fi;
return Suffix(S, PositionCanonical(S, x));
end);
###########################################################################
## Enumerate
###########################################################################
InstallMethod(Enumerate,
"for a semigroup with CanUseLibsemigroupsFroidurePin and pos int",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsInt],
function(S, n)
FroidurePinMemFnRec(S).enumerate(LibsemigroupsFroidurePin(S), n);
return S;
end);
InstallMethod(Enumerate,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
FroidurePinMemFnRec(S).enumerate(LibsemigroupsFroidurePin(S), -1);
return S;
end);
InstallMethod(IsEnumerated,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
S -> FroidurePinMemFnRec(S).finished(LibsemigroupsFroidurePin(S)));
###########################################################################
## Cayley graphs etc
###########################################################################
InstallMethod(LeftCayleyGraphSemigroup,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local F;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).left_cayley_graph(F) + 1;
end);
InstallMethod(LeftCayleyDigraph,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local D;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
D := DigraphNC(LeftCayleyGraphSemigroup(S));
SetFilterObj(D, IsCayleyDigraph);
SetSemigroupOfCayleyDigraph(D, S);
SetGeneratorsOfCayleyDigraph(D, GeneratorsOfSemigroup(S));
return D;
end);
InstallMethod(RightCayleyGraphSemigroup,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local F;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
F := LibsemigroupsFroidurePin(S);
return FroidurePinMemFnRec(S).right_cayley_graph(F) + 1;
end);
InstallMethod(RightCayleyDigraph,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local D;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
D := DigraphNC(RightCayleyGraphSemigroup(S));
SetFilterObj(D, IsCayleyDigraph);
SetSemigroupOfCayleyDigraph(D, S);
SetGeneratorsOfCayleyDigraph(D, GeneratorsOfSemigroup(S));
return D;
end);
########################################################################
## Enumerators
########################################################################
InstallMethod(EnumeratorSorted,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local sorted_at, T, enum;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
elif IsPartialPermSemigroup(S) or IsFpSemigroup(S) or IsFpMonoid(S)
or IsQuotientSemigroup(S) then
# Special case required because < for libsemigroups ParialPerms and < for
# GAP partial perms are different.
return AsSet(S);
fi;
sorted_at := FroidurePinMemFnRec(S).sorted_at;
T := LibsemigroupsFroidurePin(S);
enum := rec();
enum.NumberElement := {enum, x} -> PositionSortedOp(S, x);
enum.ElementNumber := {enum, nr} -> sorted_at(T, nr - 1);
enum.Length := enum -> Size(S);
enum.Membership := {x, enum} -> PositionCanonical(S, x) <> fail;
enum.IsBound\[\] := {enum, nr} -> nr <= Size(S);
enum := EnumeratorByFunctions(S, enum);
SetIsSemigroupEnumerator(enum, true);
SetIsSSortedList(enum, true);
return enum;
end);
InstallMethod(Enumerator,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin], 6, EnumeratorCanonical);
InstallMethod(EnumeratorCanonical,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local T, enum, factorisation, at;
if HasAsListCanonical(S) then
return AsListCanonical(S);
fi;
T := LibsemigroupsFroidurePin(S);
enum := rec();
enum.NumberElement := {enum, x} -> PositionCanonical(S, x);
if IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
factorisation := FroidurePinMemFnRec(S).minimal_factorisation;
enum.ElementNumber := function(enum, nr)
if nr > Length(enum) then
return fail;
fi;
return EvaluateWord(GeneratorsOfSemigroup(S),
factorisation(T, nr - 1) + 1);
end;
else
at := FroidurePinMemFnRec(S).at;
enum.ElementNumber := function(enum, nr)
if nr > Length(enum) then
return fail;
else
return at(T, nr - 1);
fi;
end;
fi;
# TODO shouldn't S be stored in enum?
enum.Length := function(_)
if not IsFinite(S) then
return infinity;
else
return Size(S);
fi;
end;
enum.Membership := {x, enum} -> PositionCanonical(S, x) <> fail;
enum.IsBound\[\] := {enum, nr} -> nr <= Size(S);
enum := EnumeratorByFunctions(S, enum);
SetIsSemigroupEnumerator(enum, true);
return enum;
end);
# The next method is necessary since it does not necessarily involve
# enumerating the entire semigroup in the case that the semigroup is partially
# enumerated and <list> only contains indices that are within the so far
# enumerated range. The default methods in the library do, because they require
# the length of the enumerator to check that the list of positions is valid.
InstallMethod(ELMS_LIST, "for a semigroup enumerator and a list",
[IsSemigroupEnumerator, IsList],
function(enum, list)
local S, result, factorisation, at, T, i;
S := UnderlyingCollection(enum);
if not CanUseLibsemigroupsFroidurePin(S) then
TryNextMethod();
fi;
result := EmptyPlist(Length(list));
if IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
factorisation := FroidurePinMemFnRec(S).minimal_factorisation;
at := {T, nr} -> EvaluateWord(GeneratorsOfSemigroup(S),
factorisation(T, nr) + 1);
else
at := FroidurePinMemFnRec(S).at;
fi;
T := LibsemigroupsFroidurePin(S);
for i in list do
Add(result, at(T, i - 1));
od;
return result;
end);
########################################################################
## Iterators
########################################################################
InstallMethod(IteratorCanonical,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
S -> IteratorList(EnumeratorCanonical(S)));
InstallMethod(Iterator,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin], IteratorCanonical);
InstallMethod(IteratorSorted,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
S -> IteratorList(EnumeratorSorted(S)));
########################################################################
## MultiplicationTable
########################################################################
InstallMethod(MultiplicationTable,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
local N, result, pos_to_pos_sorted, product, T, next, k, i, j;
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
N := Size(S);
result := List([1 .. N], x -> EmptyPlist(N));
T := LibsemigroupsFroidurePin(S);
if IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
pos_to_pos_sorted := {T, i} -> i;
product := FroidurePinMemFnRec(S).product_by_reduction;
FroidurePinMemFnRec(S).enumerate(T, N + 1);
else
pos_to_pos_sorted := FroidurePinMemFnRec(S).position_to_sorted_position;
product := FroidurePinMemFnRec(S).fast_product;
fi;
for i in [0 .. N - 1] do
next := result[pos_to_pos_sorted(T, i) + 1];
for j in [0 .. N - 1] do
k := pos_to_pos_sorted(T, j) + 1;
next[k] := pos_to_pos_sorted(T, product(T, i, j)) + 1;
od;
od;
return result;
end);
########################################################################
## ClosureSemigroupOrMonoidNC
########################################################################
# TODO(later) require a ClosureSemigroupDestructive that uses closure directly,
# not copy then closure.
InstallMethod(ClosureSemigroupOrMonoidNC,
"for fn, CanUseLibsemigroupsFroidurePin, finite list, and record",
[IsFunction,
IsSemigroup and CanUseLibsemigroupsFroidurePin,
IsFinite and IsList,
IsRecord],
function(Constructor, S, coll, opts)
local n, R, M, N, CppT, add_generator, generator, T, x, i;
# opts must be copied and processed before calling this function
# coll must be copied before calling this function
if ForAll(coll, x -> x in S) then
# To avoid copying unless necessary!
return S;
fi;
if not IsMutable(coll) then
coll := ShallowCopy(coll);
fi;
coll := Shuffle(coll);
if IsGeneratorsOfActingSemigroup(coll) then
n := ActionDegree(coll);
Sort(coll, {x, y} -> ActionRank(x, n) > ActionRank(y, n));
elif Length(coll) < 120 then
Sort(coll, IsGreensDGreaterThanFunc(Semigroup(coll)));
fi;
R := FroidurePinMemFnRec(S, coll);
# Perform the closure
if IsPartialPermSemigroup(S) or IsTransformationSemigroup(S) then
if IsPartialPermSemigroup(S) then
M := Maximum(DegreeOfPartialPermCollection(coll),
CodegreeOfPartialPermCollection(coll));
N := Maximum(DegreeOfPartialPermSemigroup(S),
CodegreeOfPartialPermSemigroup(S));
else
M := DegreeOfTransformationCollection(coll);
N := DegreeOfTransformationSemigroup(S);
fi;
if M > N then
# Can't use closure, TODO(later) use copy_closure
CppT := R.make();
add_generator := R.add_generator;
for x in GeneratorsOfSemigroup(S) do
add_generator(CppT, [x, M]);
od;
R.closure(CppT, List(coll, x -> [x, M]));
else
CppT := R.copy(LibsemigroupsFroidurePin(S));
R.closure(CppT, List(coll, x -> [x, N]));
fi;
else
CppT := R.copy(LibsemigroupsFroidurePin(S));
R.closure(CppT, coll);
fi;
generator := R.generator;
# Recover the new generating set from the closure
coll := EmptyPlist(R.number_of_generators(CppT));
for i in [1 .. R.number_of_generators(CppT)] do
Add(coll, generator(CppT, i - 1));
od;
# Construct new semigroup so as to reset all attributes
T := Constructor(coll, opts);
T!.LibsemigroupsFroidurePin := CppT;
return T;
end);
########################################################################
## New in v4
########################################################################
InstallMethod(RulesOfSemigroup,
"for a semigroup with CanUseLibsemigroupsFroidurePin",
[IsSemigroup and CanUseLibsemigroupsFroidurePin],
function(S)
if not IsFinite(S) then
Error("the argument (a semigroup) is not finite");
fi;
Enumerate(S);
return FroidurePinMemFnRec(S).rules(LibsemigroupsFroidurePin(S)) + 1;
end);
InstallMethod(IdempotentsSubset,
"for a semigroup with CanUseLibsemigroupsFroidurePin and hom. list",
[IsSemigroup and CanUseLibsemigroupsFroidurePin, IsHomogeneousList],
function(S, list)
local product_by_reduction, is_idempotent, T;
if not IsFinite(S) then
Error("the 1st argument (a semigroup) is not finite");
elif IsFpSemigroup(S) or IsFpMonoid(S) or IsQuotientSemigroup(S) then
product_by_reduction := FroidurePinMemFnRec(S).product_by_reduction;
is_idempotent := {T, x} -> product_by_reduction(T, x, x) = x;
else
is_idempotent := FroidurePinMemFnRec(S).is_idempotent;
fi;
T := LibsemigroupsFroidurePin(S);
return Filtered(list, x -> is_idempotent(T, x - 1));
end);
[ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet)
]
|
2026-04-02
|
|
|
|
|