Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sandwich semigroup #1042

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions doc/sandwich.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#############################################################################
##
#W sandwich.xml
#Y Copyright (C) 2024 Murray T. Whyte
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##

<#GAPDoc Label="SandwichSemigroup">
<ManSection>
<Oper Name = "DualSemigroup" Arg = "S, a"/>
<Returns>The sandwich variant semigroup of the given semigroup, with respect
to the given element.</Returns>
<Description>
The sandwich semigroup of a semigroup <A>S</A> with respect to an element
<A>a</A> of <A>S</A> is the semigroup with the
same underlying set as <A>S</A>, but with multiplication *
defined as x * y = x a y.

This operation returns a semigroup isomorphic to the sandwich semigroup
of <A>S</A> with respect to <A>a</A>.
<Example>
<![CDATA[
gap> T := FullTransformationMonoid(5);
<full transformation monoid of degree 5>
gap> S := SandwichSemigroup(T, Transformation([1, 1]));
<sandwich semigroup of size 3125 and sandwich element Transformation( [ 1, 1 ] )
]]></Example> </Description> </ManSection>
<#/GAPDoc>

<#GAPDoc Label="BijectionSandwichSemigroup">
<ManSection>
<Attr Name= "BijectionSandwichSemigroup" Arg = "S, a"/>
<Returns>
An isomorphism from semigroup <A>S</A> to the sandwich semigroup of
<A>S</A> with respect to <A>a</A>.
</Returns>
<Description>
The sandwich semigroup of <A>S</A> with respect to <A>a</A>
mathematically has the same underlying set as <A>S</A>,
but is represented with a different set of elements in
&SEMIGROUPS;. This function returns a mapping which is an isomorphism
from <A>S</A> to the sandwich semigroup of <A>S</A> with respect
<A>a</A>.
<Example>
<![CDATA[
gap> T := FullTransformationMonoid(5);
<full transformation monoid of degree 5>
f := BijectionSandwichSemigroup(T, Transformation([1, 1]));
MappingByFunction( <full transformation monoid of degree 5>, <sandwich semigroup of si\
ze 3125 and sandwich element Transformation( [ 1, 1 ] ) >, function( s ) ... end, function( s ) ... end)
gap> Transformation([3, 2, 2]) ^ f;
<Transformation( [ 3, 2, 2 ] ) in sandwich semigroup>]]></Example> </Description> </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsSandwichSemigroupElement">
<ManSection>
<Filt Name = "IsSandwichSemigroupElement" Type = "Category" Arg="elt"/>
<Returns>Returns <K>true</K> if <A>elt</A> has the representation of a
sandwich semigroup element.</Returns>
<Description>
Elements of a sandwich semigroup obtained using
<Ref Attr = "AntiIsomorphismDualSemigroup"/> normally lie in this
category. The exception is elements obtained by applying
the map <Ref Attr = "AntiIsomorphismDualSemigroup"/> to elements already
in this category. That is, the elements of a semigroup lie in the
category <Ref Filt="IsDualSemigroupElement"/> if and only if the
elements of the corresponding dual semigroup do not.
<Example>
<![CDATA[
gap> S := SingularPartitionMonoid(4);;
gap> D := DualSemigroup(S);;
gap> s := GeneratorsOfSemigroup(S)[1];;
gap> map := AntiIsomorphismDualSemigroup(S);;
gap> t := s ^ map;
<<block bijection: [ 1, 2, -1, -2 ], [ 3, -3 ], [ 4, -4 ]>
in the dual semigroup>
gap> IsDualSemigroupElement(t);
true
gap> inv := InverseGeneralMapping(map);;
gap> x := t ^ inv;
<block bijection: [ 1, 2, -1, -2 ], [ 3, -3 ], [ 4, -4 ]>
gap> IsDualSemigroupElement(x);
false]]></Example> </Description> </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsDualSemigroupRep">
<ManSection>
<Filt Name = "IsDualSemigroupRep" Type = "Category" Arg="sgrp"/>
<Returns>Returns <K>true</K> if <A>sgrp</A> lies in the category of
dual semigroups.</Returns>
<Description>
Semigroups created using <Ref Func="DualSemigroup"/>
normally lie in this category. The exception is semigroups
which are the dual of semigroups already lying in this category.
That is, a semigroup lies in the category
<Ref Filt="IsDualSemigroupRep"/> if and only if the corresponding
dual semigroup does not. Note that this is not a Representation in the
GAP sense, and will likely be renamed in a future major release of the
package.
<Example>
<![CDATA[
gap> S := Semigroup([Transformation([3, 5, 1, 1, 2]),
> Transformation([1, 2, 4, 4, 3])]);
<transformation semigroup of degree 5 with 2 generators>
gap> D := DualSemigroup(S);
<dual semigroup of <transformation semigroup of degree 5 with 2
generators>>
gap> IsDualSemigroupRep(D);
true
gap> R := DualSemigroup(D);
<transformation semigroup of degree 5 with 2 generators>
gap> IsDualSemigroupRep(R);
false
gap> R = S;
true
gap> T := Range(IsomorphismTransformationSemigroup(D));
<transformation semigroup of size 16, degree 17 with 2 generators>
gap> IsDualSemigroupRep(T);
false
gap> x := Representative(D);
<Transformation( [ 3, 5, 1, 1, 2 ] ) in the dual semigroup>
gap> V := Semigroup(x);
<dual semigroup of <commutative transformation semigroup of degree 5
with 1 generator>>
gap> IsDualSemigroupRep(V);
true]]></Example> </Description> </ManSection>
<#/GAPDoc>
25 changes: 25 additions & 0 deletions gap/attributes/sandwich.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
############################################################################
##
## attributes/sandwich.gd
## Copyright (C) 2024 Murray T. Whyte
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##

DeclareCategory("IsSandwichSemigroupElement", IsAssociativeElement);
DeclareCategoryCollections("IsSandwichSemigroupElement");
DeclareOperation("SandwichSemigroup", [IsSemigroup, IsAssociativeElement]);
DeclareCategory("IsSandwichSemigroup", IsSemigroup);
DeclareAttribute("SandwichElement", IsSandwichSemigroup);
DeclareAttribute("SandwichSemigroupOfFamily", IsFamily);
DeclareOperation("BijectionSandwichSemigroup",
[IsSemigroup, IsAssociativeElement]);

DeclareSynonym("IsSandwichSubsemigroup",
IsSemigroup and IsSandwichSemigroupElementCollection);

InstallTrueMethod(CanUseGapFroidurePin, IsSandwichSubsemigroup);
DeclareAttribute("InverseBijectionSandwichSemigroup",
IsSandwichSemigroup);
167 changes: 167 additions & 0 deletions gap/attributes/sandwich.gi
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#############################################################################
##
## attributes/sandwich.gi
## Copyright (C) 2024 Murray T. Whyte
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##

# This file contains an implementation of sandwich variants of semigroups.
#
# TODO: Write a method for getting generating sets for sandwich semigroups.

InstallMethod(SandwichSemigroup, "for a semigroup and an element",
[IsSemigroup, IsAssociativeElement],
function(S, a)
local fam, sandwich, filts, type, forward, backward, map;

if not a in S then
ErrorNoReturn("expected 2nd argument to be an element of 1st argument");
fi;

fam := NewFamily("SandwichSemigroupElementsFamily",
IsSandwichSemigroupElement, CanEasilyCompareElements);
sandwich := rec();
Objectify(NewType(CollectionsFamily(fam),
IsSandwichSemigroup and
IsWholeFamily and
IsAttributeStoringRep),
sandwich);
filts := IsSandwichSemigroupElement;

type := NewType(fam, filts);
fam!.type := type;

SetSandwichSemigroupOfFamily(fam, sandwich);
SetElementsFamily(FamilyObj(sandwich), fam);

# TODO(MTW) set the bijection from the original semigroup into the sandwich
SetSandwichElement(sandwich, a);
SetSandwichElement(fam, a);

SetUnderlyingSemigroup(sandwich, S);
SetUnderlyingSemigroup(fam, S);

forward := s -> SEMIGROUPS.SandwichSemigroupElementNC(sandwich, s);
backward := s -> s![1];

map := MappingByFunction(sandwich, S, backward, forward);
SetInverseBijectionSandwichSemigroup(sandwich, map);

return sandwich;
end);

SEMIGROUPS.SandwichSemigroupElementNC := function(SandwichSemigroup, s)
return Objectify(ElementsFamily(FamilyObj(SandwichSemigroup))!.type, [s]);
end;

InstallMethod(BijectionSandwichSemigroup, "for a semigroup and an element",
[IsSemigroup, IsAssociativeElement],
function(S, a)
local forward, backward, sandwich_S;

sandwich_S := SandwichSemigroup(S, a);

forward := s -> SEMIGROUPS.SandwichSemigroupElementNC(sandwich_S, s);
backward := s -> s![1];

return MappingByFunction(S, sandwich_S, forward, backward);
end);

## Technical methods
InstallMethod(\*, "for sandwich semigroup elements",
IsIdenticalObj,
[IsSandwichSemigroupElement, IsSandwichSemigroupElement],
{x, y} -> Objectify(FamilyObj(x)!.type, [x![1] * SandwichElement(FamilyObj(x)) * y![1]]));

InstallMethod(\=, "for sandwich semigroup elements",
IsIdenticalObj,
[IsSandwichSemigroupElement, IsSandwichSemigroupElement],
{x, y} -> x![1] = y![1]);

InstallMethod(Size, "for a sandwich semigroup",
[IsSandwichSemigroup],
S -> Size(UnderlyingSemigroup(S)));

InstallMethod(AsList, "for a sandwich semigroup",
[IsSandwichSemigroup],
10, # add rank to beat enumeration methods
S -> List(UnderlyingSemigroup(S), s -> SEMIGROUPS.SandwichSemigroupElementNC(S, s)));

InstallMethod(\<, "for sandwich semigroup elements",
IsIdenticalObj,
[IsSandwichSemigroupElement, IsSandwichSemigroupElement],
{x, y} -> x![1] < y![1]);

InstallMethod(AsSSortedList, "for a sandwich semigroup",
[IsSandwichSemigroup], S -> SortedList(AsList(S)));

InstallMethod(ChooseHashFunction, "for a sandwich semigroup element and int",
[IsSandwichSemigroupElement, IsInt],
function(x, data)
local H, hashfunc;

H := ChooseHashFunction(x![1], data);
hashfunc := {a, b} -> H.func(a![1], b);
return rec(func := hashfunc, data := H.data);
end);

InstallMethod(PrintObj, "for a sandwich semigroup",
[IsSandwichSemigroup],
function(S)
# If we know the name of the underlying semigroup, it would be cool to use it
Print("<sandwich semigroup of size ", Size(S), " and sandwich element ", SandwichElement(S), ">");
end);

InstallMethod(ViewObj, "for a sandwich semigroup",
[IsSandwichSemigroup], PrintObj);

InstallMethod(PrintObj, "for a sandwich semigroup element",
[IsSandwichSemigroupElement],
function(x)
Print("<", x![1], " in sandwich semigroup>");
end);

InstallMethod(ViewObj, "for a sandwich semigroup element",
[IsSandwichSemigroupElement], PrintObj);

InstallMethod(GeneratorsOfSemigroup, "for a sandwich semigroup",
[IsSandwichSemigroup],
function(S)
local T, a, i, P, A, B, map, gens, U, D, y, j, layer, x;

T := UnderlyingSemigroup(S);
a := SandwichElement(S);
i := Position(DClasses(T), DClass(T, a));
P := PartialOrderOfDClasses(T);
A := VerticesReachableFrom(P, i);
AddSet(A, i);
B := Difference(DigraphVertices(P), A);

map := InverseGeneralMapping(InverseBijectionSandwichSemigroup(S));

gens := [];
for j in B do
Append(gens, List(DClasses(T)[j], x -> x ^ map));
od;

U := Semigroup(gens);

while Size(U) < Size(S) do
for layer in DigraphLayers(P, i) do
for j in layer do
D := DClasses(T)[j];
for x in D do
y := x ^ map;
if not y in U then
Add(gens, y);
U := Semigroup(gens);
fi;
od;
od;
od;
od;
return gens;
end);
1 change: 1 addition & 0 deletions init.g
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ ReadPackage("semigroups", "gap/attributes/isorms.gd");
ReadPackage("semigroups", "gap/attributes/maximal.gd");
ReadPackage("semigroups", "gap/attributes/properties.gd");
ReadPackage("semigroups", "gap/attributes/homomorph.gd");
ReadPackage("semigroups", "gap/attributes/sandwich.gd");
ReadPackage("semigroups", "gap/attributes/semifp.gd");
ReadPackage("semigroups", "gap/attributes/translat.gd");
ReadPackage("semigroups", "gap/attributes/rms-translat.gd");
Expand Down
1 change: 1 addition & 0 deletions read.g
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ ReadPackage("semigroups", "gap/attributes/isomorph.gi");
ReadPackage("semigroups", "gap/attributes/isorms.gi");
ReadPackage("semigroups", "gap/attributes/maximal.gi");
ReadPackage("semigroups", "gap/attributes/properties.gi");
ReadPackage("semigroups", "gap/attributes/sandwich.gi");
ReadPackage("semigroups", "gap/attributes/semifp.gi");
ReadPackage("semigroups", "gap/attributes/translat.gi");
ReadPackage("semigroups", "gap/attributes/rms-translat.gi");
Expand Down
Loading