Skip to content

Commit

Permalink
Merge pull request #407 from wilfwilson/minimal-genset
Browse files Browse the repository at this point in the history
Add some basic methods for MinimalSemigroupGeneratingSet
  • Loading branch information
james-d-mitchell authored Nov 21, 2017
2 parents 15e5ecc + 44f36c1 commit fa3f5ab
Show file tree
Hide file tree
Showing 3 changed files with 304 additions and 26 deletions.
43 changes: 17 additions & 26 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -332,33 +332,21 @@ gap> Length(SmallGeneratingSet(S));
<ManSection>
<Attr Name="MinimalSemigroupGeneratingSet" Arg="S"/>
<Attr Name="MinimalMonoidGeneratingSet" Arg="S"/>
<Attr Name="MinimalInverseSemigroupGeneratingSet" Arg="S"/>
<Attr Name="MinimalInverseMonoidGeneratingSet" Arg="S"/>
<Returns>A minimal generating set for a semigroup.</Returns>
<Description>

<B>Warning:</B> currently, no methods are installed to compute these
attributes.<P/>

The attributes <C>MinimalXGeneratingSet</C> return a minimal generating set
The attribute <C>MinimalXGeneratingSet</C> returns a minimal generating set
for the semigroup <A>S</A>, with respect to length. The returned value of
<C>MinimalXGeneratingSet</C>, where applicable, is a minimal-length list
of elements of <A>S</A> with the property that
<Log>
X(MinimalXGeneratingSet(S)) = S;
</Log>
where <C>X</C> is any of
<Ref Func="Semigroup" BookName="ref"/>,
<Ref Func="Monoid" BookName="ref"/>,
<Ref Func="InverseSemigroup" BookName="ref"/>, or
<Ref Func="InverseMonoid" BookName="ref"/>.<P/>
where <C>X</C> is either
<Ref Func="Semigroup" BookName="ref"/>, or
<Ref Func="Monoid" BookName="ref"/>.<P/>

For certain types of semigroup, for example monogenic semigroups, a
<C>MinimalXGeneratingSet</C> may be known a priori, or may be deduced as a
by-product of other functions. However, since there are no methods installed
to compute these attributes directly, for most semigroups it is not
currently possible to find a <C>MinimalXGeneratingSet</C> with the
&Semigroups; package. <P/>
For many types of semigroup, it is not currently possible to find a
<C>MinimalXGeneratingSet</C> with the &Semigroups; package. <P/>

See also <Ref Attr="SmallGeneratingSet"/> and <Ref
Oper="IrredundantGeneratingSubset"/>.
Expand All @@ -367,15 +355,18 @@ gap> Length(SmallGeneratingSet(S));
gap> S := MonogenicSemigroup(3, 6);;
gap> MinimalSemigroupGeneratingSet(S);
[ Transformation( [ 2, 3, 4, 5, 6, 1, 6, 7, 8 ] ) ]
gap> S := Semigroup([
> PartialPerm([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]),
> PartialPerm([1, 2, 3, 4], [5, 2, 4, 1]),
> PartialPerm([1, 2, 4, 5], [4, 2, 3, 1])]);
<partial perm monoid of rank 5 with 2 generators>
gap> IsMonogenicInverseMonoid(S);
gap> S := FullTransformationMonoid(4);;
gap> MinimalSemigroupGeneratingSet(S);
[ Transformation( [ 1, 4, 2, 3 ] ), Transformation( [ 4, 3, 1, 2 ] ),
Transformation( [ 1, 2, 3, 1 ] ) ]
gap> S := Monoid([
> PartialPerm([2, 3, 4, 5, 1, 0, 6, 7]),
> PartialPerm([3, 4, 5, 1, 2, 0, 0, 6])]);
<partial perm monoid of rank 8 with 2 generators>
gap> IsMonogenicMonoid(S);
true
gap> MinimalInverseMonoidGeneratingSet(S);
[ [3,4,1,5](2) ]]]></Example>
gap> MinimalMonoidGeneratingSet(S);
[ [8,7,6](1,2,3,4,5) ]]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
Expand Down
120 changes: 120 additions & 0 deletions gap/attributes/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,123 @@ function(S)
od;
return out;
end);

InstallMethod(MinimalSemigroupGeneratingSet, "for a free semigroup",
[IsFreeSemigroup],
GeneratorsOfSemigroup);

InstallMethod(MinimalSemigroupGeneratingSet, "for a semigroup",
[IsSemigroup],
function(S)
local gens, indecomp, id, T, zero, iso, inv, G, x, D, non_unit_gens, classes,
po, nbs;

if IsTrivial(S) then
return [Representative(S)];
elif IsGroupAsSemigroup(S) then
iso := IsomorphismPermGroup(S);
inv := InverseGeneralMapping(iso);
G := Range(iso);
return Images(inv, MinimalGeneratingSet(G));
elif IsMonogenicSemigroup(S) then
return [Representative(MaximalDClasses(S)[1])];
fi;

gens := IrredundantGeneratingSubset(S);

# A semigroup that has a 2-generating set but is not monogenic has rank 2.
if Length(gens) = 2 then
return gens;
fi;

# A generating set for a semigroup that has either a one/zero adjoined is
# minimal if and only if it contains that one/zero, and is minimal for the
# semigroup without the one/zero.
if IsMonoidAsSemigroup(S) and IsTrivial(GroupOfUnits(S)) then
id := MultiplicativeNeutralElement(S);
T := Semigroup(Filtered(gens, x -> x <> id));
return Concatenation([id], MinimalSemigroupGeneratingSet(T));
elif IsSemigroupWithAdjoinedZero(S) then
zero := MultiplicativeZero(S);
T := Semigroup(Filtered(gens, x -> x <> zero));
return Concatenation([zero], MinimalSemigroupGeneratingSet(T));
fi;

# The indecomposable elements are contains in any generating set. If the
# indecomposable elements (or if not, the indecomposable elements plus a
# single element) generate the semigroup, then you have a minimal generating
# set.
indecomp := IndecomposableElements(S);
if Length(gens) = Length(indecomp) then
return indecomp;
elif not IsEmpty(indecomp) then
x := Difference(gens, Semigroup(indecomp));
if Length(x) = 1 then
return Concatenation(x, indecomp);
fi;
fi;

# A generating set for a monoid that consists of a minimal generating set for
# the group of units and exactly one generator in each D-class immediately
# below the group of units is minimal.
if IsMonoidAsSemigroup(S) then
D := DClass(S, MultiplicativeNeutralElement(S));
non_unit_gens := Filtered(gens, x -> not x in D);
classes := List(non_unit_gens, x -> Position(DClasses(S), DClass(S, x)));
if IsDuplicateFreeList(classes) then
po := Digraph(PartialOrderOfDClasses(S));
po := DigraphReflexiveTransitiveReduction(po);
nbs := OutNeighboursOfVertex(po, Position(DClasses(S), D));
if ForAll(classes, x -> x in nbs) then
iso := IsomorphismPermGroup(GroupOfUnits(S));
inv := InverseGeneralMapping(iso);
G := Range(iso);
return Concatenation(Images(inv, MinimalGeneratingSet(G)),
non_unit_gens);
fi;
fi;
fi;

# An irredundant generating set of a finite semigroup that contains at most
# one generator per D-class is minimal.
if IsFinite(S) and (IsDTrivial(S) or
Length(Set(gens, x -> DClass(S, x))) = Length(gens)) then
return gens;
fi;

ErrorNoReturn("Semigroups: MinimalSemigroupGeneratingSet: error,\n",
"no further methods for computing minimal generating sets ",
"are implemented,");
end);

InstallMethod(MinimalMonoidGeneratingSet, "for a free monoid",
[IsFreeMonoid],
GeneratorsOfMonoid);

InstallMethod(MinimalMonoidGeneratingSet, "for a monoid",
[IsMonoid],
function(S)
local one, gens, new;

one := One(S);
if IsTrivial(S) then
return [one];
fi;

gens := MinimalSemigroupGeneratingSet(S);
if not IsTrivial(GroupOfUnits(S)) then
return gens;
fi;
new := Difference(gens, [one]);
if One(new) = one then
# The One of the non-identity generators is the One, so One is not needed.
return new;
fi;

# This currently applies to only partial perm monoids: sometimes, the One
# of the non-One generators is not the One of the monoid. Therefore the One
# has to be included in the GeneratorsOfMonoid. WARNING: therefore
# MinimalMonoidGeneratingSet may include the One even though, mathematically,
# it shouldn't be needed. For example, see symmetric inverse monoid on 1 pt.
return gens;
end);
167 changes: 167 additions & 0 deletions tst/standard/attr.tst
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,173 @@ gap> S := MonogenicSemigroup(3, 2);;
gap> IndecomposableElements(S) = [S.1];
true

#T# MinimalSemigroupGeneratingSet: for a monogenic semigroup, 1
gap> S := MonogenicSemigroup(IsTransformationSemigroup, 4, 5);
<commutative non-regular transformation semigroup of size 8, degree 9 with 1
generator>
gap> MinimalSemigroupGeneratingSet(S);
[ Transformation( [ 2, 3, 4, 5, 1, 5, 6, 7, 8 ] ) ]
gap> x := MinimalSemigroupGeneratingSet(S)[1];
Transformation( [ 2, 3, 4, 5, 1, 5, 6, 7, 8 ] )
gap> S := Semigroup(x, x ^ 2);
<transformation semigroup of degree 9 with 2 generators>
gap> x := MinimalSemigroupGeneratingSet(S);
[ Transformation( [ 2, 3, 4, 5, 1, 5, 6, 7, 8 ] ) ]
gap> Length(x);
1
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: for a 2-generated semigroup, 1
gap> S := SymmetricInverseMonoid(1);
<symmetric inverse monoid of degree 1>
gap> x := MinimalSemigroupGeneratingSet(S);
[ <empty partial perm>, <identity partial perm on [ 1 ]> ]
gap> Length(x);
2
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: for a semigroup with identity adjoined, 1
gap> S := Monoid(RectangularBand(IsBipartitionSemigroup, 2, 2));
<bipartition monoid of degree 2 with 2 generators>
gap> x := MinimalSemigroupGeneratingSet(S);;
gap> Length(x);
3
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: for a semigroup with zero adjoined, 1
gap> S := ReesZeroMatrixSemigroup(Group(()), [[(), ()]]);
<Rees 0-matrix semigroup 2x1 over Group(())>
gap> x := MinimalSemigroupGeneratingSet(S);
[ 0, (1,(),1), (2,(),1) ]
gap> Length(x);
3
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: decomposable elements, 1
gap> S := Semigroup(ZeroSemigroup(IsPartialPermSemigroup, 4));
<partial perm semigroup of rank 3 with 3 generators>
gap> x := MinimalSemigroupGeneratingSet(S);
[ [1,2], [3,4], [5,6] ]
gap> Length(x);
3
gap> S = Semigroup(x);
true
gap> S := Semigroup(Elements(S));
<partial perm semigroup of rank 3 with 4 generators>
gap> x := MinimalSemigroupGeneratingSet(S);
[ [1,2], [3,4], [5,6] ]
gap> Length(x);
3

#T# MinimalSemigroupGeneratingSet: decomposable elements, 2
gap> S := Monoid([
> Transformation([1, 1, 1, 2]),
> Transformation([1, 1, 2, 1]),
> Transformation([1, 1, 2, 2]),
> Transformation([1, 1, 1, 1, 6, 5])]);
<transformation monoid of degree 6 with 4 generators>
gap> x := MinimalSemigroupGeneratingSet(S);
[ IdentityTransformation, Transformation( [ 1, 1, 1, 1, 6, 5 ] ),
Transformation( [ 1, 1, 1, 2 ] ), Transformation( [ 1, 1, 2, 1 ] ),
Transformation( [ 1, 1, 2, 2 ] ) ]
gap> Length(x);
5
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: for a group as semigroup, 1
gap> S = Semigroup(x);
true
gap> S := Semigroup([
> Transformation([1, 3, 2, 1]),
> Transformation([2, 1, 3, 2]),
> Transformation([3, 1, 2, 3])]);
<transformation semigroup of degree 4 with 3 generators>
gap> x := MinimalSemigroupGeneratingSet(S);;
gap> Length(x);
2
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: for a monoid, 1
gap> S := FullTransformationMonoid(4);
<full transformation monoid of degree 4>
gap> x := MinimalSemigroupGeneratingSet(S);;
gap> Length(x);
3
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: for a trivial semigroup, 1
gap> S := FreeSemigroup(1);;
gap> S := S / [[S.1 ^ 2, S.1]];
<fp semigroup on the generators [ s1 ]>
gap> MinimalSemigroupGeneratingSet(S);
[ s1 ]

#T# MinimalSemigroupGeneratingSet: for a D-trivial semigroup, 1
gap> n := 3;;
gap> S := UnitriangularBooleanMatMonoid(n);
<monoid of 3x3 boolean matrices with 3 generators>
gap> x := MinimalSemigroupGeneratingSet(S);;
gap> Length(x);
4
gap> S = Semigroup(x);
true

#T# MinimalSemigroupGeneratingSet: not yet implemented, 1
gap> S := PartitionMonoid(4);
<regular bipartition *-monoid of size 4140, degree 4 with 4 generators>
gap> x := MinimalSemigroupGeneratingSet(S);
Error, Semigroups: MinimalSemigroupGeneratingSet: error,
no further methods for computing minimal generating sets are implemented,

#T# MinimalMonoidGeneratingSet: for a trivial monoid, 1
gap> S := FreeMonoid(1);;
gap> S := S / [[S.1, S.1 ^ 0]];
<fp monoid on the generators [ m1 ]>
gap> MinimalMonoidGeneratingSet(S);
[ <identity ...> ]

#T# MinimalMonoidGeneratingSet: for a monoid, 1
gap> S := FullTransformationMonoid(3);;
gap> x := MinimalMonoidGeneratingSet(S);;
gap> Length(x);
3
gap> Monoid(x) = S;
true

#T# MinimalMonoidGeneratingSet: for a monoid, 2
gap> S := SymmetricInverseMonoid(2);
<symmetric inverse monoid of degree 2>
gap> MinimalMonoidGeneratingSet(S);
[ <identity partial perm on [ 1 ]>, (1,2) ]
gap> S := AsSemigroup(IsBlockBijectionSemigroup, S);
<inverse block bijection monoid of degree 3 with 2 generators>
gap> MinimalMonoidGeneratingSet(S);
[ <block bijection: [ 1, -1 ], [ 2, 3, -2, -3 ]>,
<block bijection: [ 1, -2 ], [ 2, -1 ], [ 3, -3 ]> ]

#T# MinimalMonoidGeneratingSet: for a monoid, 2
gap> S := SymmetricInverseMonoid(1);
<symmetric inverse monoid of degree 1>
gap> MinimalMonoidGeneratingSet(S);
[ <empty partial perm>, <identity partial perm on [ 1 ]> ]
gap> S := AsSemigroup(IsBlockBijectionSemigroup, S);;
gap> MinimalMonoidGeneratingSet(S);
[ <block bijection: [ 1, 2, -1, -2 ]> ]

#T# MinimalMonoidGeneratingSet: for a monoid, 3
gap> x := Bipartition([[1, 3, -1, -2], [2, -3]]);;
gap> S := Monoid(x, x ^ 2);
<block bijection monoid of degree 3 with 2 generators>
gap> MinimalMonoidGeneratingSet(S) = [x];
true

#T# SEMIGROUPS_UnbindVariables
gap> Unbind(D);
gap> Unbind(G);
Expand Down

0 comments on commit fa3f5ab

Please sign in to comment.