|
###########################################################################
##
## libsemigroups/sims1.gi
## Copyright (C) 2022 James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##
DeclareOperation("LibsemigroupsSims1",
[IsSemigroup, IsPosInt, IsList, IsString]);
InstallMethod(LibsemigroupsSims1,
[IsSemigroup, IsPosInt, IsList, IsString],
function(S, n, extra, kind)
local P, rules, sims1, Q, pair, r;
Assert(1,
CanUseFroidurePin(S)
or IsFpSemigroup(S)
or IsFpMonoid(S)
or (HasIsFreeSemigroup(S) and IsFreeSemigroup(S))
or (HasIsFreeMonoid(S) and IsFreeMonoid(S)));
Assert(1, IsEmpty(extra) or IsMultiplicativeElementCollColl(extra));
Assert(1, kind in ["left", "right"]);
if IsFpSemigroup(S) then
rules := List(RelationsOfFpSemigroup(S),
r -> List(r,
x -> SEMIGROUPS.ExtRepObjToWord(ExtRepOfObj(x))));
elif IsFpMonoid(S) then
rules := List(RelationsOfFpMonoid(S),
r -> List(r,
x -> SEMIGROUPS.ExtRepObjToWord(ExtRepOfObj(x))));
elif (HasIsFreeSemigroup(S) and IsFreeSemigroup(S))
or (HasIsFreeMonoid(S) and IsFreeMonoid(S)) then
rules := [];
else
Assert(1, CanUseFroidurePin(S));
rules := RulesOfSemigroup(S);
fi;
P := libsemigroups.Presentation.make();
for r in rules do
libsemigroups.presentation_add_rule(P, r[1] - 1, r[2] - 1);
od;
if not IsEmpty(rules) then
libsemigroups.Presentation.alphabet_from_rules(P);
elif (HasIsFreeMonoid(S) and IsFreeMonoid(S)) or IsFpMonoid(S) then
libsemigroups.Presentation.set_alphabet(
P, [0 .. Size(GeneratorsOfMonoid(S)) - 1]);
elif (HasIsFreeSemigroup(S) and IsFreeSemigroup(S)) or IsFpSemigroup(S) then
libsemigroups.Presentation.set_alphabet(
P, [0 .. Size(GeneratorsOfSemigroup(S)) - 1]);
fi;
libsemigroups.Presentation.validate(P);
# RulesOfSemigroup always returns the rules of an isomorphic fp semigroup
libsemigroups.Presentation.contains_empty_word(
P, IsFpMonoid(S) or (HasIsFreeMonoid(S) and IsFreeMonoid(S)));
sims1 := libsemigroups.Sims1.make(kind);
libsemigroups.Sims1.short_rules(sims1, P);
if not IsEmpty(extra) then
Q := libsemigroups.Presentation.make();
libsemigroups.Presentation.contains_empty_word(Q, IsMonoid(S));
libsemigroups.Presentation.set_alphabet(Q,
libsemigroups.Presentation.alphabet(P));
for pair in extra do
libsemigroups.presentation_add_rule(
Q,
MinimalFactorization(S, pair[1]) - 1,
MinimalFactorization(S, pair[2]) - 1);
od;
libsemigroups.Presentation.validate(Q);
libsemigroups.Sims1.extra(sims1, Q);
fi;
if n > 64 and libsemigroups.hardware_concurrency() > 2 then
libsemigroups.Sims1.number_of_threads(
sims1, libsemigroups.hardware_concurrency() - 2);
fi;
return sims1;
end);
BindGlobal("_CheckExtraPairs", function(S, extra)
local pair;
for pair in extra do
if not (IsList(pair) and Length(pair) = 2) then
ErrorNoReturn("the 3rd argument (a list) must consist of ",
"lists of length 2");
elif not pair[1] in S or not pair[2] in S then
ErrorNoReturn("the 3rd argument (a list of length 2) must consist ",
"of pairs of elements of the 1st argument (a semigroup)");
fi;
od;
end);
InstallMethod(NumberOfRightCongruences, "for a semigroup", [IsSemigroup],
S -> NumberOfRightCongruences(S, Size(S), []));
InstallMethod(NumberOfLeftCongruences, "for a semigroup", [IsSemigroup],
S -> NumberOfLeftCongruences(S, Size(S), []));
InstallMethod(NumberOfRightCongruences,
"for a semigroup and positive integer",
[IsSemigroup, IsPosInt],
{S, n} -> NumberOfRightCongruences(S, n, []));
InstallMethod(NumberOfLeftCongruences,
"for a semigroup and positive integer",
[IsSemigroup, IsPosInt],
{S, n} -> NumberOfLeftCongruences(S, n, []));
InstallMethod(NumberOfRightCongruences,
"for a semigroup, pos. int., and list ",
[IsSemigroup, IsPosInt, IsList],
function(S, n, extra)
local sims1;
_CheckExtraPairs(S, extra);
if HasRightCongruencesOfSemigroup(S) then
return Number(RightCongruencesOfSemigroup(S),
x -> NrEquivalenceClasses(x) <= n
and ForAll(extra, y -> y in x));
elif not (CanUseFroidurePin(S) or IsFpSemigroup(S) or IsFpMonoid(S)
or (HasIsFreeSemigroup(S) and IsFreeSemigroup(S))
or (HasIsFreeMonoid(S) and IsFreeMonoid(S))) then
TryNextMethod();
fi;
sims1 := LibsemigroupsSims1(S, n, extra, "right");
return libsemigroups.Sims1.number_of_congruences(sims1, n);
end);
InstallMethod(NumberOfLeftCongruences,
"for a semigroup, pos. int., and list",
[IsSemigroup, IsPosInt, IsList],
function(S, n, extra)
local sims1;
_CheckExtraPairs(S, extra);
if HasLeftCongruencesOfSemigroup(S) then
return Number(LeftCongruencesOfSemigroup(S),
x -> NrEquivalenceClasses(x) <= n
and ForAll(extra, y -> y in x));
elif not (CanUseFroidurePin(S) or IsFpSemigroup(S) or IsFpMonoid(S)
or (HasIsFreeSemigroup(S) and IsFreeSemigroup(S))
or (HasIsFreeMonoid(S) and IsFreeMonoid(S))) then
TryNextMethod();
fi;
sims1 := LibsemigroupsSims1(S, n, extra, "left");
return libsemigroups.Sims1.number_of_congruences(sims1, n);
end);
InstallMethod(SmallerDegreeTransformationRepresentation,
"for semigroup with CanUseFroidurePin",
[IsSemigroup and CanUseFroidurePin],
function(S)
local map1, map2;
map1 := IsomorphismFpSemigroup(S);
map2 := SmallerDegreeTransformationRepresentation(Range(map1));
return CompositionMapping(map2, map1);
end);
InstallMethod(SmallerDegreeTransformationRepresentation,
"for an fp semigroup", [IsFpSemigroup],
function(S)
local P, ro, map, max, D, deg, imgs, pts, r, j, i;
if not IsFinite(S) then
ErrorNoReturn("the argument (an fp semigroup) must be finite");
fi;
P := libsemigroups.Presentation.make();
for r in RelationsOfFpSemigroup(S) do
r := List(r, x -> SEMIGROUPS.ExtRepObjToWord(ExtRepOfObj(x)));
libsemigroups.presentation_add_rule(P, r[1] - 1, r[2] - 1);
od;
libsemigroups.Presentation.alphabet_from_rules(P);
libsemigroups.Presentation.contains_empty_word(P, true);
libsemigroups.Presentation.validate(P);
ro := libsemigroups.RepOrc.make();
libsemigroups.RepOrc.short_rules(ro, P);
libsemigroups.RepOrc.min_nodes(ro, 1);
if HasIsomorphismTransformationSemigroup(S)
or IsTransformationSemigroup(S) then
map := IsomorphismTransformationSemigroup(S);
max := DegreeOfTransformationSemigroup(Range(map)) - 1;
else
max := Size(S);
fi;
libsemigroups.RepOrc.max_nodes(ro, max);
libsemigroups.RepOrc.target_size(ro, Size(S));
if Size(S) > 64 and libsemigroups.hardware_concurrency() > 2 then
libsemigroups.RepOrc.number_of_threads(
ro, libsemigroups.hardware_concurrency() - 2);
fi;
D := libsemigroups.RepOrc.digraph(ro);
deg := Length(D);
if deg = 0 then
# Should only occur if HasIsomorphismTransformationSemigroup since
# otherwise we'll always find the right regular representation eventually.
return IsomorphismTransformationSemigroup(S);
fi;
imgs := [];
for j in [1 .. Length(GeneratorsOfSemigroup(S))] do
pts := [1 .. deg];
for i in pts do
pts[i] := D[i][j];
od;
Add(imgs, TransformationNC(pts));
od;
return SemigroupIsomorphismByImagesNC(S,
Semigroup(imgs),
GeneratorsOfSemigroup(S),
imgs);
end);
BindGlobal("NextIterator_Sims1", function(iter)
local result;
result := libsemigroups.Sims1Iterator.deref(iter!.it);
libsemigroups.Sims1Iterator.increment(iter!.it);
if IsEmpty(result) then
return fail;
fi;
result := Filtered(result, x -> not IsEmpty(x));
result := DigraphNC(result);
SetFilterObj(result, IsWordGraph);
return iter!.construct(result);
end);
InstallMethod(IteratorOfRightCongruences,
"for a semigroup, pos. int., list or coll.",
[IsSemigroup, IsPosInt, IsListOrCollection],
function(S, n, extra)
local sims1, iter;
_CheckExtraPairs(S, extra);
if HasRightCongruencesOfSemigroup(S) then
return IteratorFiniteList(Filtered(RightCongruencesOfSemigroup(S),
x -> NrEquivalenceClasses(x) <= n
and ForAll(extra, y -> y in x)));
elif not (CanUseFroidurePin(S) or IsFpSemigroup(S) or IsFpMonoid(S)
or (HasIsFreeSemigroup(S) and IsFreeSemigroup(S))
or (HasIsFreeMonoid(S) and IsFreeMonoid(S))) then
TryNextMethod();
fi;
sims1 := LibsemigroupsSims1(S, n, extra, "right");
iter := rec(it := libsemigroups.Sims1.cbegin(sims1, n),
construct := x -> RightCongruenceByWordGraphNC(S, x));
iter.NextIterator := NextIterator_Sims1;
iter.ShallowCopy := x -> rec(it := libsemigroups.Sims1.cbegin(sims1, n),
construct :=
x -> RightCongruenceByWordGraphNC(S, x));
return IteratorByNextIterator(iter);
end);
InstallMethod(IteratorOfLeftCongruences,
"for CanUseFroidurePin, pos. int., list or coll.",
[IsSemigroup and CanUseFroidurePin, IsPosInt, IsListOrCollection],
function(S, n, extra)
local sims1, iter;
_CheckExtraPairs(S, extra);
if HasLeftCongruencesOfSemigroup(S) then
return IteratorFiniteList(Filtered(LeftCongruencesOfSemigroup(S),
x -> NrEquivalenceClasses(x) <= n
and ForAll(extra, y -> y in x)));
elif not (CanUseFroidurePin(S) or IsFpSemigroup(S) or IsFpMonoid(S)
or (HasIsFreeSemigroup(S) and IsFreeSemigroup(S))
or (HasIsFreeMonoid(S) and IsFreeMonoid(S))) then
fi;
sims1 := LibsemigroupsSims1(S, n, extra, "left");
iter := rec(it := libsemigroups.Sims1.cbegin(sims1, n),
construct := x -> LeftCongruenceByWordGraphNC(S, x));
iter.NextIterator := NextIterator_Sims1;
iter.ShallowCopy := x -> rec(it := libsemigroups.Sims1.cbegin(sims1, n),
construct :=
x -> LeftCongruenceByWordGraphNC(S, x));
return IteratorByNextIterator(iter);
end);
InstallMethod(IteratorOfRightCongruences,
"for a semigroup and pos. int.",
[IsSemigroup, IsPosInt],
{S, n} -> IteratorOfRightCongruences(S, n, []));
InstallMethod(IteratorOfLeftCongruences,
"for a semigroup and pos. int.",
[IsSemigroup, IsPosInt],
{S, n} -> IteratorOfLeftCongruences(S, n, []));
InstallMethod(IteratorOfRightCongruences, "for a semigroup",
[IsSemigroup], S -> IteratorOfRightCongruences(S, Size(S), []));
InstallMethod(IteratorOfLeftCongruences, "for a semigroup",
[IsSemigroup], S -> IteratorOfLeftCongruences(S, Size(S), []));
[ Dauer der Verarbeitung: 0.32 Sekunden
(vorverarbeitet)
]
|