From 900f06d503563856bf90dbb606958bab0c41c0d2 Mon Sep 17 00:00:00 2001 From: Murray Whyte Date: Fri, 30 Aug 2024 11:29:33 +0100 Subject: [PATCH 1/4] Add some sandwich semigroup functionality --- gap/attributes/sandwich.gd | 23 ++++++++ gap/attributes/sandwich.gi | 112 +++++++++++++++++++++++++++++++++++++ init.g | 1 + read.g | 1 + 4 files changed, 137 insertions(+) create mode 100644 gap/attributes/sandwich.gd create mode 100644 gap/attributes/sandwich.gi diff --git a/gap/attributes/sandwich.gd b/gap/attributes/sandwich.gd new file mode 100644 index 000000000..f7547f57e --- /dev/null +++ b/gap/attributes/sandwich.gd @@ -0,0 +1,23 @@ +############################################################################ +## +## 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); diff --git a/gap/attributes/sandwich.gi b/gap/attributes/sandwich.gi new file mode 100644 index 000000000..dbf3d028a --- /dev/null +++ b/gap/attributes/sandwich.gi @@ -0,0 +1,112 @@ +############################################################################# +## +## 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. + +InstallMethod(SandwichSemigroup, "for a semigroup and an element", +[IsSemigroup, IsAssociativeElement], +function(S, a) + local fam, sandwich, filts, type; + + fam := NewFamily("SandwichSemigroupElementsFamily", + IsSandwichSemigroupElement); + 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); + + SetSandwichElement(sandwich, a); + SetSandwichElement(fam, a); + + SetUnderlyingSemigroup(sandwich, S); + SetUnderlyingSemigroup(fam, S); + + 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(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); 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"); From 2ccc38fe10a27541eb5afc81481cce820d52154c Mon Sep 17 00:00:00 2001 From: Murray Whyte Date: Fri, 30 Aug 2024 12:09:32 +0100 Subject: [PATCH 2/4] Fix slowness with Elements() --- gap/attributes/sandwich.gi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gap/attributes/sandwich.gi b/gap/attributes/sandwich.gi index dbf3d028a..7258abb74 100644 --- a/gap/attributes/sandwich.gi +++ b/gap/attributes/sandwich.gi @@ -82,6 +82,9 @@ 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) From 29bfc2513819a8a03fd8678746a5a2f40160ef3e Mon Sep 17 00:00:00 2001 From: Murray Whyte Date: Fri, 18 Oct 2024 15:41:26 +0100 Subject: [PATCH 3/4] Tmp --- doc/sandwich.xml | 130 +++++++++++++++++++++++++++++++++++++ gap/attributes/sandwich.gi | 9 +++ 2 files changed, 139 insertions(+) create mode 100644 doc/sandwich.xml 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.gi b/gap/attributes/sandwich.gi index 7258abb74..beadc66cf 100644 --- a/gap/attributes/sandwich.gi +++ b/gap/attributes/sandwich.gi @@ -9,12 +9,18 @@ ## # 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; + if not a in S then + ErrorNoReturn("expected 2nd argument to be an element of 1st argument"); + fi; + fam := NewFamily("SandwichSemigroupElementsFamily", IsSandwichSemigroupElement); sandwich := rec(); @@ -63,6 +69,9 @@ IsIdenticalObj, [IsSandwichSemigroupElement, IsSandwichSemigroupElement], {x, y} -> Objectify(FamilyObj(x)!.type, [x![1] * SandwichElement(FamilyObj(x)) * y![1]])); +a :=2; +ba :=3; + InstallMethod(\=, "for sandwich semigroup elements", IsIdenticalObj, [IsSandwichSemigroupElement, IsSandwichSemigroupElement], From 09982efb2dd9b631935861e6fcdec76e8e8b25fc Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Fri, 18 Oct 2024 17:13:05 +0100 Subject: [PATCH 4/4] Add generators method --- gap/attributes/sandwich.gd | 2 ++ gap/attributes/sandwich.gi | 53 ++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/gap/attributes/sandwich.gd b/gap/attributes/sandwich.gd index f7547f57e..ac949b91a 100644 --- a/gap/attributes/sandwich.gd +++ b/gap/attributes/sandwich.gd @@ -21,3 +21,5 @@ DeclareSynonym("IsSandwichSubsemigroup", IsSemigroup and IsSandwichSemigroupElementCollection); InstallTrueMethod(CanUseGapFroidurePin, IsSandwichSubsemigroup); +DeclareAttribute("InverseBijectionSandwichSemigroup", + IsSandwichSemigroup); diff --git a/gap/attributes/sandwich.gi b/gap/attributes/sandwich.gi index beadc66cf..827d2c69e 100644 --- a/gap/attributes/sandwich.gi +++ b/gap/attributes/sandwich.gi @@ -15,14 +15,14 @@ InstallMethod(SandwichSemigroup, "for a semigroup and an element", [IsSemigroup, IsAssociativeElement], function(S, a) - local fam, sandwich, filts, type; + 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); + IsSandwichSemigroupElement, CanEasilyCompareElements); sandwich := rec(); Objectify(NewType(CollectionsFamily(fam), IsSandwichSemigroup and @@ -37,12 +37,19 @@ function(S, a) 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); @@ -69,9 +76,6 @@ IsIdenticalObj, [IsSandwichSemigroupElement, IsSandwichSemigroupElement], {x, y} -> Objectify(FamilyObj(x)!.type, [x![1] * SandwichElement(FamilyObj(x)) * y![1]])); -a :=2; -ba :=3; - InstallMethod(\=, "for sandwich semigroup elements", IsIdenticalObj, [IsSandwichSemigroupElement, IsSandwichSemigroupElement], @@ -122,3 +126,42 @@ function(x) 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);