diff --git a/doc/sandwich.xml b/doc/sandwich.xml new file mode 100644 index 000000000..5e4d89a89 --- /dev/null +++ b/doc/sandwich.xml @@ -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"> + + + The sandwich variant semigroup of the given semigroup, with respect + to the given element. + + The sandwich semigroup of a semigroup S with respect to an element + a of S is the semigroup with the + same underlying set as S, but with multiplication * + defined as x * y = x a y. + + This operation returns a semigroup isomorphic to the sandwich semigroup + of S with respect to a. + + T := FullTransformationMonoid(5); + +gap> S := SandwichSemigroup(T, Transformation([1, 1])); + +<#/GAPDoc> + +<#GAPDoc Label="BijectionSandwichSemigroup"> + + + + An isomorphism from semigroup S to the sandwich semigroup of + S with respect to a. + + + The sandwich semigroup of S with respect to a + mathematically has the same underlying set as S, + but is represented with a different set of elements in + &SEMIGROUPS;. This function returns a mapping which is an isomorphism + from S to the sandwich semigroup of S with respect + a. + + T := FullTransformationMonoid(5); + +f := BijectionSandwichSemigroup(T, Transformation([1, 1])); +MappingByFunction( , , function( s ) ... end, function( s ) ... end) +gap> Transformation([3, 2, 2]) ^ f; +]]> +<#/GAPDoc> + +<#GAPDoc Label="IsSandwichSemigroupElement"> + + + Returns true if elt has the representation of a + sandwich semigroup element. + + Elements of a sandwich semigroup obtained using + normally lie in this + category. The exception is elements obtained by applying + the map to elements already + in this category. That is, the elements of a semigroup lie in the + category if and only if the + elements of the corresponding dual semigroup do not. + + S := SingularPartitionMonoid(4);; +gap> D := DualSemigroup(S);; +gap> s := GeneratorsOfSemigroup(S)[1];; +gap> map := AntiIsomorphismDualSemigroup(S);; +gap> t := s ^ map; +< + in the dual semigroup> +gap> IsDualSemigroupElement(t); +true +gap> inv := InverseGeneralMapping(map);; +gap> x := t ^ inv; + +gap> IsDualSemigroupElement(x); +false]]> +<#/GAPDoc> + +<#GAPDoc Label="IsDualSemigroupRep"> + + + Returns true if sgrp lies in the category of + dual semigroups. + + Semigroups created using + 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 + 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. + + S := Semigroup([Transformation([3, 5, 1, 1, 2]), +> Transformation([1, 2, 4, 4, 3])]); + +gap> D := DualSemigroup(S); +> +gap> IsDualSemigroupRep(D); +true +gap> R := DualSemigroup(D); + +gap> IsDualSemigroupRep(R); +false +gap> R = S; +true +gap> T := Range(IsomorphismTransformationSemigroup(D)); + +gap> IsDualSemigroupRep(T); +false +gap> x := Representative(D); + +gap> V := Semigroup(x); +> +gap> IsDualSemigroupRep(V); +true]]> +<#/GAPDoc> diff --git a/gap/attributes/sandwich.gd b/gap/attributes/sandwich.gd new file mode 100644 index 000000000..ac949b91a --- /dev/null +++ b/gap/attributes/sandwich.gd @@ -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); diff --git a/gap/attributes/sandwich.gi b/gap/attributes/sandwich.gi new file mode 100644 index 000000000..827d2c69e --- /dev/null +++ b/gap/attributes/sandwich.gi @@ -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(""); +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); diff --git a/init.g b/init.g index 1c01899ef..f6d205422 100644 --- a/init.g +++ b/init.g @@ -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"); diff --git a/read.g b/read.g index f89150a42..bc3b1b7d6 100644 --- a/read.g +++ b/read.g @@ -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");