|
#############################################################################
##
## enums.gi Smallsemi - a GAP library of semigroups
## Copyright (C) 2008-2024 Andreas Distler & James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##
BindGlobal("SmallSemigroupEnumeratorFamily",
NewFamily("SmallSemigroupEnumeratorFamily",
IsEnumeratorOfSmallSemigroups));
BindGlobal("SmallSemigroupIteratorFamily",
NewFamily("SmallSemigroupIteratorFamily",
IsIteratorOfSmallSemigroups));
#############################################################################
# Internal stuff
#############################################################################
BindGlobal("SMALLSEMI_ValidateTypeArgs",
function(arg...)
local x, i;
if not IsOddInt(Length(arg)) then
Error("there must be an odd number arguments");
elif not ForAny([IsPosInt,
IsCyclotomicCollection,
IsEnumeratorOfSmallSemigroups,
IsIteratorOfSmallSemigroups], f -> f(arg[1])) then
Error("the 1st argument must be a positive integer, cyclotomic collection, ",
"enumerator, or iterator of small semigroups");
fi;
if IsPosInt(arg[1]) and arg[1] > 8 then
Error("the 1st argument (a positive integer) must be at most 8, found ",
arg[1]);
elif IsCyclotomicCollection(arg[1]) then
for i in [1 .. Length(arg[1])] do
x := arg[1][i];
if not IsPosInt(x) then
Error("the 1st argument (a list) must consist of positive integers",
", found ", TNAM_OBJ(x), " in position ", i);
elif x = 0 or x > 8 then
Error("the 1st argument (a list) must consist of positive integers",
" in the range [1, 8), found ", x);
fi;
od;
fi;
for i in [2, 4 .. Length(arg) - 1] do
if not IsFunction(arg[i]) then
Error("the argument in even positions must be functions, found ",
TNAM_OBJ(arg[i]), " in position ", i);
fi;
od;
end);
# <A>arg</A> is assumed to satisfy SMALLSEMI_ValidateTypeArgs(arg)=true but
# this is not checked.
#
# <C>SMALLSEMI_NormalizeArgs</C> replaces every function <A>arg[2i]</A> by an
# equivalent function in <Ref Var="PrecomputedSmallSemisInfo"
# BookName="smallsemi"/> if it exists.
BindGlobal("SMALLSEMI_NormalizeArgs",
function(arg...)
local func_val_pairs, pos, cmp, i;
func_val_pairs := [];
for i in [2, 4 .. Length(arg) - 1] do
pos := PositionProperty(SMALLSEMI_EQUIV, x -> [arg[i], arg[i + 1]] = x[1]);
if pos <> fail then
Add(func_val_pairs, SMALLSEMI_EQUIV[pos][2]);
elif not (arg[i] in SMALLSEMI_ALWAYS_FALSE and not arg[i + 1]) then
Add(func_val_pairs, [arg[i], arg[i + 1]]);
fi;
od;
cmp := function(x, y)
if x[2] < y[2] then
return true;
elif x[2] = y[2] then
return NameFunction(x[1]) < NameFunction(y[1]);
fi;
end;
Sort(func_val_pairs, cmp);
return Concatenation([arg[1]], Concatenation(func_val_pairs));
end);
# only allow precomputed, sorted, and converted functions as input
# Must declare this and not BindGlobal, since the function calls itself
DeclareGlobalFunction("SMALLSEMI_CanCreateEnumerator");
InstallGlobalFunction(SMALLSEMI_CanCreateEnumerator,
function(arg...)
if IsEnumeratorOfSmallSemigroups(arg[1]) then
return true;
elif IsIteratorOfSmallSemigroups(arg[1]) then
arg := Concatenation([SizesOfSmallSemigroupsIn(arg[1])],
arg{[2 .. Length(arg)]},
ArgumentsUsedToCreate(arg[1]));
arg := CallFuncList(SMALLSEMI_NormalizeArgs, arg);
return CallFuncList(SMALLSEMI_CanCreateEnumerator, arg);
elif IsPosInt(arg[1]) then
arg[1] := [arg[1]];
fi;
if Maximum(arg[1]) < 8 then
return true;
fi;
if Length(arg) > 1 then
# at least one precomputed value must be true
return ForAny([2, 4 .. Length(arg) - 1],
i -> NameFunction(arg[i])
in PrecomputedSmallSemisInfo[8] and arg[i + 1]);
fi;
return GAPInfo.BytesPerVariable >= 8;
end);
BindGlobal("SMALLSEMI_ValidateEnumeratorArgs",
function(arg...)
if not CallFuncList(SMALLSEMI_CanCreateEnumerator, arg) then
Error("It is only possible to create an enumerator containing ",
"semigroups of order 8 if it describes a subset of at ",
"least one of the precomputed sets of values in the library.");
fi;
end);
BindGlobal("SMALLSEMI_MakeEnumeratorNC",
function(sizes, positions, funcs)
local sum, Lengths, record, enum, position;
sum := 0;
Lengths := [0];
for position in positions do
sum := sum + Length(position);
Add(Lengths, sum);
od;
record := rec();
record.Lengths := Lengths;
record.ElementNumber := function(enum, pos)
local i, S, funcs;
i := PositionProperty(enum!.Lengths, x -> pos <= x);
if i = fail then
return fail;
fi;
i := i - 1;
pos := pos - enum!.Lengths[i];
S := SmallSemigroupNC(SizesOfSmallSemigroupsIn(enum)[i],
PositionsOfSmallSemigroupsIn(enum)[i][pos]);
funcs := ArgumentsUsedToCreate(enum);
for i in [1, 3 .. Length(funcs) - 1] do
if IsAttribute(funcs[i]) or IsProperty(funcs[i]) then
Setter(funcs[i])(S, funcs[i + 1]);
fi;
od;
return S;
end;
record.NumberElement := function(enum, elm)
local id, size, index;
id := IdSmallSemigroup(elm);
size := Position(SizesOfSmallSemigroupsIn(enum), id[1]);
index := Position(PositionsOfSmallSemigroupsIn(enum), id[2]);
return index + enum!.Lengths[size - 1];
end;
record.Length := enum -> enum!.Lengths[Length(enum!.Lengths)];
record.PrintObj := function(enum)
local sizes, msg;
if IsEmpty(enum) then
Print("<empty enumerator of semigroups>");
return;
fi;
sizes := SizesOfSmallSemigroupsIn(enum);
msg := "size";
if Length(sizes) > 1 then
Append(msg, "s");
else
sizes := sizes[1];
fi;
PrintFormatted("<enumerator of semigroups of {} {}>", msg, sizes);
end;
enum := EnumeratorByFunctions(SmallSemigroupEnumeratorFamily, record);
SetPositionsOfSmallSemigroupsIn(enum, positions);
SetSizesOfSmallSemigroupsIn(enum, sizes);
SetArgumentsUsedToCreate(enum, funcs);
return enum;
end);
########################################################################
# Functions with the same args as Enumerator/IteratorOfSmallSemigroups
########################################################################
InstallGlobalFunction(IdsOfSmallSemigroups,
function(arg...)
local enum, size, pos;
enum := CallFuncList(EnumeratorOfSmallSemigroups, arg);
size := SizesOfSmallSemigroupsIn(enum);
pos := PositionsOfSmallSemigroupsIn(enum);
return Concatenation(List([1 .. Length(size)],
x -> List(pos[x], y -> [size[x], y])));
end);
InstallGlobalFunction(AllSmallSemigroups,
function(arg...)
return ConstantTimeAccessList(
CallFuncList(EnumeratorOfSmallSemigroups, arg));
end);
InstallGlobalFunction(NrSmallSemigroups,
function(arg...)
local numb, positions;
if Length(arg) = 1 and IsPosInt(arg[1]) then
numb := [1, 4, 18, 126, 1160, 15973, 836021, 1843120128];
if arg[1] > 0 and arg[1] <= 8 then
return numb[arg[1]];
else
Error("only semigroups of sizes from 1 to 8 are in the library");
fi;
fi;
positions := CallFuncList(PositionsOfSmallSemigroups, arg);
return Sum(List(positions, Length));
end);
InstallGlobalFunction(RandomSmallSemigroup,
function(arg...)
local iter, i, j, s, t, enum;
if Length(arg) = 1 and IsPosInt(arg[1]) then
i := Random(RandomSource(IsMersenneTwister), 1, NrSmallSemigroups(arg[1]));
return SmallSemigroupNC(arg[1], i);
elif CallFuncList(SMALLSEMI_CanCreateEnumerator, arg) then
enum := CallFuncList(EnumeratorOfSmallSemigroups, arg);
if not IsEmpty(enum) then
i := Random(RandomSource(IsMersenneTwister), 1, Length(enum));
return enum[i];
fi;
return fail;
fi;
iter := CallFuncList(IteratorOfSmallSemigroups, arg);
i := 0;
j := Random(RandomSource(IsMersenneTwister), 1, 500);
t := Runtime();
if not IsDoneIterator(iter) then # in case of the empty iterator
repeat
i := i + 1;
s := NextIterator(iter);
until IsDoneIterator(iter) or Runtime() - t > j;
if IsDoneIterator(iter) and i > 1 then
iter := IteratorOfSmallSemigroups(arg);
for j in [1 .. RandomList([1 .. i - 1])] do
s := NextIterator(iter);
od;
elif IsDoneIterator(iter) and i = 1 then # iterators of length 1
iter := IteratorOfSmallSemigroups(arg);
s := NextIterator(iter);
fi;
return s;
fi;
return fail;
end);
InstallGlobalFunction(OneSmallSemigroup,
function(arg...)
local iter;
if Length(arg) = 1 then
if IsEnumeratorOfSmallSemigroups(arg[1]) and IsEmpty(arg[1]) then
return fail;
elif IsIteratorOfSmallSemigroups(arg[1]) then
iter := arg[1];
else
iter := CallFuncList(IteratorOfSmallSemigroups, arg);
fi;
else
iter := CallFuncList(IteratorOfSmallSemigroups, arg);
fi;
# TODO not sure this makes sense in case arg[1] is the iterator
if not IsDoneIterator(iter) then
return NextIterator(CallFuncList(IteratorOfSmallSemigroups, arg));
fi;
return fail;
end);
########################################################################
# Related functionality
########################################################################
InstallGlobalFunction(IsIdSmallSemigroup,
function(arg...)
local m, n, nr;
if Length(arg) = 2 and IsPosInt(arg[1]) and IsPosInt(arg[2]) then
m := arg[1];
n := arg[2];
elif Length(arg) = 1 and IsCyclotomicCollection(arg[1])
and Length(arg[1]) = 2 then
return IsIdSmallSemigroup(arg[1][1], arg[1][2]);
else
return false;
fi;
nr := NrSmallSemigroups(m);
return 0 < m and m < 9 and 1 <= n and n <= nr;
end);
InstallMethod(UpToIsomorphism, "for a list of non-equivalent semigroups",
[IsList], # TODO replace with something better?
function(list)
local out, dual, equi, S;
if not ForAll(list, IsSmallSemigroup) then
Error("the argument must be a list of semigroups obtained from ",
"the smallsemi library");
fi;
out := [];
for S in list do
Add(out, S);
if not IsSelfDualSemigroup(S) then
# creator for small semigroups cannot be used here as this would
# result in an object with 'IsSmallSemi' being true but not in
# the library
dual := SemigroupByMultiplicationTableNC(
TransposedMat(MultiplicationTable(S)));
equi := MappingByFunction(dual, S, x -> AsSSortedList(S)[x![1]]);
SetRespectsMultiplication(equi, false);
SetIsBijective(equi, true);
SetEquivalenceSmallSemigroup(dual, equi);
SetIdSmallSemigroup(dual, IdSmallSemigroup(S));
Add(out, dual);
fi;
od;
return out;
end);
InstallMethod(UpToIsomorphism, "for a small semigroup", [IsSmallSemigroup],
S -> UpToIsomorphism([S]));
########################################################################
# Positions
########################################################################
# This function does all of the work for enumerators, computes a list of
# lists of the positions the small semigroups that satisfy the
# arguments.
# TODO add a no-check version that doesn't validate the args etc
InstallGlobalFunction(PositionsOfSmallSemigroups,
function(arg...)
local stored, sizes, prec, user, positions, i, enum, out, s, j;
CallFuncList(SMALLSEMI_ValidateTypeArgs, arg);
arg := CallFuncList(SMALLSEMI_NormalizeArgs, arg);
CallFuncList(SMALLSEMI_ValidateEnumeratorArgs, arg);
# a single stored value
if IsPosInt(arg[1]) and Length(arg) = 3 and arg[3] = true then
stored := STORED_INFO(arg[1], NameFunction(arg[2]));
if stored <> fail then
return [stored];
fi;
fi;
# all semigroups not of order 8
if Length(arg) = 1 then
if IsPosInt(arg[1]) then
return [[1 .. NrSmallSemigroups(arg[1])]];
elif IsEnumeratorOfSmallSemigroups(arg[1]) then
return PositionsOfSmallSemigroupsIn(arg[1]);
fi;
fi;
# find sizes of semigroups
# TODO set positions here too
if IsPosInt(arg[1]) then
sizes := [arg[1]];
elif IsEnumeratorOfSmallSemigroups(arg[1])
or IsIteratorOfSmallSemigroups(arg[1]) then
sizes := SizesOfSmallSemigroupsIn(arg[1]);
# TODO set arg as below here too
elif IsCyclotomicCollection(arg[1]) and ForAll(arg[1], IsPosInt) then
# TODO just use else here because type checked above
sizes := arg[1];
fi;
prec := [arg[1]];
user := [];
if IsIteratorOfSmallSemigroups(arg[1]) then
arg := Concatenation([SizesOfSmallSemigroupsIn(arg[1])],
arg{[2 .. Length(arg)]},
ArgumentsUsedToCreate(arg[1]));
arg := CallFuncList(SMALLSEMI_NormalizeArgs, arg);
fi;
# split input into precomputed and user
for i in [2, 4 .. Length(arg) - 1] do
if NameFunction(arg[i]) in SMALLSEMI_ALWAYS_FALSE and arg[i + 1] then
return [];
elif ForAll(sizes,
j -> NameFunction(arg[i]) in PrecomputedSmallSemisInfo[j]) then
prec := Concatenation(prec, [arg[i], arg[i + 1]]);
else # user function
user := Concatenation(user, [arg[i], arg[i + 1]]);
fi;
od;
# initialize positions
if IsEnumeratorOfSmallSemigroups(arg[1]) then
positions := List(PositionsOfSmallSemigroupsIn(arg[1]), ShallowCopy);
elif ForAny([3, 5 .. Length(prec)], i -> prec[i] = true) then
i := First([3, 5 .. Length(prec)], i -> prec[i] = true);
positions := List(sizes,
j -> ShallowCopy(
STORED_INFO(j, NameFunction(prec[i - 1]))));
else
positions := List(sizes, i -> [1 .. NrSmallSemigroups(i)]);
fi;
# find what function values are stored already
for j in [1 .. Length(sizes)] do
if Length(prec) > 1 then # not just arg[1]
i := 0;
repeat
i := i + 2;
stored := STORED_INFO(sizes[j], NameFunction(prec[i]));
if stored <> fail then
if prec[i + 1] = true then
IntersectSet(positions[j], stored);
elif prec[i + 1] = false then
SubtractSet(positions[j], stored);
fi;
fi;
until i = Length(prec) - 1 or IsEmpty(positions[j]);
fi;
# compute the values of any remaining functions
if not IsEmpty(user) and not IsEmpty(positions[j]) then
i := -1;
repeat
enum := EnumeratorOfSmallSemigroupsByIds(sizes[j], positions[j]);
i := i + 2;
out := [];
for s in [1 .. Length(enum)] do
if InfoLevel(InfoSmallsemiEnums) = 4 then
Print(" #I at ", s, " of ", Length(enum), "\r");
fi;
s := enum[s];
if user[i](s) = user[i + 1] then
Add(out, IdSmallSemigroup(s)[2]);
fi;
od;
IntersectSet(positions[j], out);
until i = Length(user) - 1 or IsEmpty(positions[j]);
fi;
od;
if InfoLevel(InfoSmallsemiEnums) = 4 then
Print("\n");
fi;
return positions;
end);
########################################################################
# Enumerators
########################################################################
# TODO remove
InstallMethod(SizesOfSmallSemigroupsIn, "for an iterator",
[IsIteratorOfSmallSemigroups], it -> it!.sizes);
# TODO remove
InstallMethod(ArgumentsUsedToCreate, "for an iterator",
[IsIteratorOfSmallSemigroups], it -> it!.funcs);
InstallGlobalFunction(EnumeratorOfSmallSemigroups,
function(arg...)
local sizes, positions, non_empty;
CallFuncList(SMALLSEMI_ValidateTypeArgs, arg);
if Length(arg) = 1 and IsEnumeratorOfSmallSemigroups(arg[1]) then
# do nothing
return arg[1];
fi;
if IsPosInt(arg[1]) then
sizes := [arg[1]];
elif IsEnumeratorOfSmallSemigroups(arg[1])
or IsIteratorOfSmallSemigroups(arg[1]) then
sizes := SizesOfSmallSemigroupsIn(arg[1]);
Append(arg, ArgumentsUsedToCreate(arg[1]));
else
sizes := arg[1];
fi;
arg := CallFuncList(SMALLSEMI_NormalizeArgs, arg);
CallFuncList(SMALLSEMI_ValidateEnumeratorArgs, arg);
# TODO use PositionsOfSmallSemigroupsNC when available
positions := CallFuncList(PositionsOfSmallSemigroups, arg);
Assert(0, Length(positions) = Length(sizes));
# some inherited sizes may now not occur, TODO still necessary?
non_empty := Filtered([1 .. Length(positions)],
i -> not IsEmpty(positions[i]));
sizes := sizes{non_empty};
positions := positions{non_empty};
return SMALLSEMI_MakeEnumeratorNC(sizes, positions, arg{[2 .. Length(arg)]});
end);
# input ids, a list of ids, a pos. int. & list of positions, a list of pos.
# ints. and a list of positions of equal length
InstallMethod(EnumeratorOfSmallSemigroupsByIds,
"for a set of pos. ints. and list of sets of positions",
[IsCyclotomicCollection, IsCyclotomicCollColl],
function(sizes, positions)
if not IsSet(sizes) then
Info(InfoWarning,
1,
"the 1st argument (a cyclotomic coll.) must be a set!");
return fail;
elif not ForAll(sizes, x -> x > 0 and x < 9) then
Info(InfoWarning,
1,
"the 1st argument (a set of integers) must be in the range [0, 9)!");
return fail;
elif Length(sizes) <> Length(positions) then
Info(InfoWarning, 1, "the 1st and 2nd arguments must have equal length");
return fail;
elif not ForAll(positions, x -> ForAll(x, IsPosInt))
or not ForAll(positions, IsSet) then
Info(InfoWarning,
1,
"the 2nd argument must be a list of sets of positive integers");
return fail;
elif ForAny([1 .. Length(positions)],
i -> Maximum(positions[i]) > NrSmallSemigroups(sizes[i])) then
Info(InfoWarning,
1,
"all sets in 2nd argument must be in the range 1 to the number ",
"of semigroups");
return fail;
fi;
return EnumeratorOfSmallSemigroupsByIdsNC(sizes, positions);
end);
InstallMethod(EnumeratorOfSmallSemigroupsByIdsNC,
"for a set of pos. ints. and list of sets of positions",
[IsCyclotomicCollection, IsCyclotomicCollColl],
{sizes, positions} -> SMALLSEMI_MakeEnumeratorNC(sizes, positions, []));
InstallMethod(EnumeratorOfSmallSemigroupsByIds,
"for a pos. int. and set of positions", [IsPosInt, IsCyclotomicCollection],
{sizes, positions} -> EnumeratorOfSmallSemigroupsByIds([sizes], [positions]));
InstallMethod(EnumeratorOfSmallSemigroupsByIdsNC,
"for a pos. int. and set of positions", [IsPosInt, IsCyclotomicCollection],
{sizes, positions} -> EnumeratorOfSmallSemigroupsByIdsNC([sizes], [positions]));
InstallMethod(EnumeratorOfSmallSemigroupsByIds,
"for a list of smallsemi ids", [IsList],
function(ids)
local sizes, positions, pos, i;
ids := Set(ids);
if not ForAll(ids, IsIdSmallSemigroup) then
Info(InfoWarning, 1,
"argument must be a list of ids of small semigroups");
return fail;
fi;
sizes := [];
positions := [];
for i in ids do
pos := PositionSet(sizes, i[1]);
if pos = fail then
AddSet(sizes, i[1]);
positions[PositionSet(sizes, i[1])] := [i[2]];
else
AddSet(positions[pos], i[2]);
fi;
od;
return EnumeratorOfSmallSemigroupsByIdsNC(sizes, positions);
end);
# TODO some arg checks here
InstallGlobalFunction(EnumeratorOfSmallSemigroupsByDiagonals,
function(diagonals)
local sizes, ranges, diag, n, sizepos, diagpos, start, ende, i, offset, id;
sizes := [];
ranges := [];
for diag in diagonals do
n := Length(diag);
sizepos := Position(sizes, n);
diagpos := Position(MOREDATA2TO8[n].diags, diag);
start := MOREDATA2TO8[n].endpositions[diagpos] + 1;
ende := MOREDATA2TO8[n].endpositions[diagpos + 1];
if sizepos = fail then
Add(sizes, n);
sizepos := Length(sizes);
Add(ranges, [start .. ende]);
else
ranges[sizepos] := Union(ranges[sizepos], [start .. ende]);
fi;
offset := 11433106;
if n = 8 then
for i in [3 .. 8] do
diagpos := Position(MOREDATA2TO8[n].3nildiags, diag{[i .. n]});
if diagpos <> fail then
start := MOREDATA2TO8[n].3nilendpositions[diagpos] + 1;
ende := MOREDATA2TO8[n].3nilendpositions[diagpos + 1];
id := start + offset;
repeat
Add(ranges[sizepos], id);
id := id + 1;
until id > ende + offset;
fi;
od;
fi;
od;
return EnumeratorOfSmallSemigroupsByIds(sizes, ranges);
end);
########################################################################
# Iterators
########################################################################
# TODO remove
InstallGlobalFunction(EmptyIteratorOfSmallSemigroups,
function()
local record, type;
record := rec();
record.IsDoneIterator := ReturnTrue;
record.NextIterator := ReturnFail;
record.PrintObj := function(_)
Print("<empty iterator of semigroups>");
end;
record.ShallowCopy := SHALLOWCOPYITERATORSMALLSEMI;
record.at := 0;
record.max := 0;
record.enum := [];
record.user := [];
record.sizes := [0];
type := NewType(SmallSemigroupIteratorFamily,
IsIteratorOfSmallSemigroups and IsMutable);
return Objectify(type, record);
end);
BindGlobal("PrintObj_IsIteratorOfSmallSemigroups",
function(iter)
local sizes, msg;
if SizesOfSmallSemigroupsIn(iter) = [0] then
Print("<empty iterator of semigroups>");
return;
fi;
sizes := SizesOfSmallSemigroupsIn(iter);
msg := "size";
if Length(sizes) > 1 then
Append(msg, "s");
else
sizes := sizes[1];
fi;
PrintFormatted("<iterator of semigroups of {} {}>", msg, sizes);
end);
InstallGlobalFunction(IteratorOfSmallSemigroups,
function(arg...)
local record, type, sizes, funcs, enum, user, max, i;
CallFuncList(SMALLSEMI_ValidateTypeArgs, arg);
if Length(arg) = 1 and IsPosInt(arg[1]) then
# all semigroups
record := rec();
record.IsDoneIterator := iter -> iter!.next(iter, false) = fail;
record.NextIterator := iter -> iter!.next(iter, true);
record.PrintObj := PrintObj_IsIteratorOfSmallSemigroups;
record.next := function(iter, advance)
if iter!.at = iter!.max then
return fail;
elif advance then
iter!.at := iter!.at + 1;
return SmallSemigroupNC(arg[1], iter!.at);
fi;
return true;
end;
record.ShallowCopy := SHALLOWCOPYITERATORSMALLSEMI;
record.at := 0;
record.max := NrSmallSemigroups(arg[1]);
record.enum := [];
record.user := [];
record.sizes := [arg[1]];
record.funcs := [];
type := NewType(SmallSemigroupIteratorFamily,
IsIteratorOfSmallSemigroups and IsMutable);
return Objectify(type, record);
fi;
if IsPosInt(arg[1]) then
sizes := [arg[1]];
funcs := [];
elif IsEnumeratorOfSmallSemigroups(arg[1]) then
if IsEmpty(arg[1]) then
return EmptyIteratorOfSmallSemigroups();
fi;
sizes := SizesOfSmallSemigroupsIn(arg[1]);
funcs := ArgumentsUsedToCreate(arg[1]);
elif IsIteratorOfSmallSemigroups(arg[1]) then
sizes := SizesOfSmallSemigroupsIn(arg[1]);
funcs := ArgumentsUsedToCreate(arg[1]);
else
# list of positive integers
sizes := arg[1];
funcs := [];
fi;
arg := CallFuncList(SMALLSEMI_NormalizeArgs, arg);
enum := [arg[1]];
user := [];
for i in [2, 4 .. Length(arg) - 1] do
if NameFunction(arg[i]) in SMALLSEMI_ALWAYS_FALSE and arg[i + 1] then
return EmptyIteratorOfSmallSemigroups();
elif ForAll(sizes,
j -> NameFunction(arg[i]) in PrecomputedSmallSemisInfo[j]) then
# precomputed function
enum := Concatenation(enum, [arg[i], arg[i + 1]]);
else
# user function
user := Concatenation(user, [arg[i], arg[i + 1]]);
fi;
od;
if IsEnumeratorOfSmallSemigroups(arg[1]) and enum = [arg[1]] then
enum := enum[1];
max := Length(enum);
if IsEmpty(enum) then
return EmptyIteratorOfSmallSemigroups();
fi;
elif enum <> [arg[1]]
and CallFuncList(SMALLSEMI_CanCreateEnumerator, enum) then
enum := CallFuncList(EnumeratorOfSmallSemigroups, enum);
max := Length(enum);
if IsEmpty(enum) then
return EmptyIteratorOfSmallSemigroups();
fi;
else
enum := [];
max := Sum(sizes, NrSmallSemigroups);
user := arg{[2 .. Length(arg)]};
fi;
record := rec();
record.IsDoneIterator := iter -> iter!.next(iter, IsDoneIterator) = fail;
record.NextIterator := iter -> iter!.next(iter, NextIterator);
record.PrintObj := PrintObj_IsIteratorOfSmallSemigroups;
record.next := function(iter, called_by)
local enum, user, s;
if iter!.last_called = IsDoneIterator then
iter!.last_called := called_by;
return iter!.last_value;
fi;
if iter!.last_called = NextIterator then
iter!.last_called := called_by;
if iter!.at = iter!.max or iter!.last_value = fail then
iter!.last_value := fail;
return fail;
fi;
enum := iter!.enum;
user := iter!.user;
if not IsEmpty(enum) and Length(enum) <= iter!.at then
iter!.last_value := fail;
return fail;
fi;
repeat
iter!.at := iter!.at + 1;
if not IsEmpty(enum) then
s := enum[iter!.at];
else
s := SmallSemigroupNC(iter!.at_size,
iter!.at -
Sum(Filtered(iter!.sizes,
x -> x < iter!.at_size),
NrSmallSemigroups));
fi;
if not IsEmpty(enum) then
iter!.at_size := Size(s);
elif Length(iter!.sizes) > 1
and iter!.at < iter!.max
and iter!.at - Sum(Filtered(iter!.sizes, x -> x < iter!.at_size),
NrSmallSemigroups) >=
NrSmallSemigroups(iter!.at_size) then
iter!.at_size := iter!.sizes[Position(iter!.sizes, iter!.at_size) + 1];
fi;
if IsEmpty(user) then
iter!.last_value := s;
return s;
elif ForAll([1, 3 .. Length(user) - 1],
i -> user[i](s) = user[i + 1]) then
iter!.last_value := s;
return s;
else
iter!.last_value := fail;
fi;
until iter!.at = iter!.max;
iter!.last_value := fail;
return fail;
fi;
end;
record.last_called := NextIterator;
record.last_value := 0;
record.ShallowCopy := SHALLOWCOPYITERATORSMALLSEMI;
record.at := 0;
record.max := max;
record.enum := enum;
record.user := user;
record.sizes := sizes;
record.at_size := sizes[1];
record.funcs := Concatenation(funcs, arg{[2 .. Length(arg)]});
type := NewType(SmallSemigroupIteratorFamily,
IsIteratorOfSmallSemigroups and IsMutable);
return Objectify(type, record);
end);
########################################################################
# Internal Functions
########################################################################
InstallGlobalFunction(SHALLOWCOPYITERATORSMALLSEMI,
function(it)
return rec(at := 0,
max := it!.max,
enum := it!.enum,
user := it!.user,
n := it!.n);
end);
[ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet)
]
|