diff --git a/gap/attributes/translat.gd b/gap/attributes/translat.gd index b6bdb0608..630aa9477 100644 --- a/gap/attributes/translat.gd +++ b/gap/attributes/translat.gd @@ -172,6 +172,8 @@ DeclareCategoryCollections("IsBitranslation"); #! the left translation `l`, and `RightPartOfBitranslation(h)` returns #! the right translation `r`. DeclareGlobalFunction("LeftPartOfBitranslation"); + +#! @Arguments h DeclareGlobalFunction("RightPartOfBitranslation"); #! @EndGroup @@ -208,7 +210,9 @@ DeclareSynonym("IsBitranslationsSemigroup", #! S must be a normalised Rees matrix semigroup and `y` must be #! a Transformation of `Columns(S)`; #! `LeftTranslation` and `RightTranslation` return the corresponding -#! translations. +#! translations. The `NC` versions of these functions do not check that +#! the provided arguments define a translation, which in general can be +#! quite expensive. #! @BeginExampleSession #! gap> S := RectangularBand(3, 4);; #! gap> L := LeftTranslations(S);; @@ -222,10 +226,19 @@ DeclareSynonym("IsBitranslationsSemigroup", #! @EndExampleSession DeclareOperation("LeftTranslation", [IsLeftTranslationsSemigroup, IsGeneralMapping]); + +#! @Arguments T, x[, y] DeclareOperation("RightTranslation", [IsRightTranslationsSemigroup, IsGeneralMapping]); + +#! @Arguments T, x[, y] +DeclareGlobalFunction("LeftTranslationNC"); + +#! @Arguments T, x[, y] +DeclareGlobalFunction("RightTranslationNC"); #! @EndGroup +#! @BeginGroup Bitranslation #! @Returns a bitranslation #! @Arguments H, l, r #! @Description @@ -233,7 +246,8 @@ DeclareOperation("RightTranslation", #! and r are linked left and right translations respectively over #! S, then this function returns the bitranslation #! (l, r). If l and r are not linked, then -#! an error is produced. +#! an error is produced. The `NC` version of this function does not check that +#! the provided translations are linked, though this is usually quite cheap. #! @BeginExampleSession #! gap> G := Group((1, 2), (3, 4));; #! gap> A := AsList(G);; @@ -251,9 +265,53 @@ DeclareOperation("RightTranslation", DeclareOperation("Bitranslation", [IsBitranslationsSemigroup, IsLeftTranslation, IsRightTranslation]); -DeclareGlobalFunction("LeftTranslationNC"); -DeclareGlobalFunction("RightTranslationNC"); +#! @Arguments H, l, r DeclareGlobalFunction("BitranslationNC"); +#! @EndGroup + +#! @BeginGroup InducedXTranslation +#! @Returns a left-, right-, or bi-translation +#! @Arguments T, s +#! @Description +#! If T is the semigroup of left or right translations or the +#! translational hull of a semigroup S, and s is an +#! element of a semigroup U containing S as a left, right +#! or two-sided ideal as appropriate, then s induces a left-, +#! right-, or bi-translation by multiplication, in the same way as the +#! inner translations are induced by elements of S. The NC +#! versions of these functions do not check that the provided element +#! induces a translation, which in general can be quite expensive. +#! @BeginExampleSession +#! gap> S := FullTransformationMonoid(4);; +#! gap> I := SemigroupIdeal(S, Transformation([1, 1, 1, 2]));; +#! gap> L := LeftTranslations(I);; +#! gap> l := InducedLeftTranslation(L, Transformation([2, 3, 3, 1]));; +#! gap> Transformation([1, 3, 3, 1]) ^ l; +#! Transformation( [ 3, 3, 3, 1 ] ) +#! @EndExampleSession +DeclareOperation("InducedLeftTranslation", + [IsLeftTranslationsSemigroup, IsAssociativeElement]); + +#! @Arguments T, s +DeclareOperation("InducedLeftTranslationNC", + [IsLeftTranslationsSemigroup, IsAssociativeElement]); + +#! @Arguments T, s +DeclareOperation("InducedRightTranslation", + [IsRightTranslationsSemigroup, IsAssociativeElement]); + +#! @Arguments T, s +DeclareOperation("InducedRightTranslationNC", + [IsRightTranslationsSemigroup, IsAssociativeElement]); + +#! @Arguments T, s +DeclareOperation("InducedBitranslation", + [IsBitranslationsSemigroup, IsAssociativeElement]); + +#! @Arguments T, s +DeclareOperation("InducedBitranslationNC", + [IsBitranslationsSemigroup, IsAssociativeElement]); +#! @EndGroup #! @BeginGroup UnderlyingSemigroup #! @GroupTitle UnderlyingSemigroup @@ -263,6 +321,8 @@ DeclareGlobalFunction("BitranslationNC"); #! Given a semigroup of translations or bitranslations, returns the #! semigroup on which these translations act. DeclareAttribute("UnderlyingSemigroup", IsTranslationsSemigroup); + +#! @Arguments S DeclareAttribute("UnderlyingSemigroup", IsBitranslationsSemigroup); #! @EndGroup @@ -286,7 +346,11 @@ DeclareAttribute("UnderlyingSemigroup", IsBitranslationsSemigroup); #! true #! @EndExampleSession DeclareAttribute("LeftTranslationsSemigroupOfFamily", IsFamily); + +#! @Arguments fam DeclareAttribute("RightTranslationsSemigroupOfFamily", IsFamily); + +#! @Arguments fam DeclareAttribute("TranslationalHullOfFamily", IsFamily); #! @EndGroup @@ -321,6 +385,8 @@ DeclareAttribute("TypeBitranslations", IsBitranslationsSemigroup); #! @EndExampleSession DeclareAttribute("LeftTranslations", IsSemigroup and CanUseFroidurePin and IsFinite); + +#! @Arguments S DeclareAttribute("RightTranslations", IsSemigroup and CanUseFroidurePin and IsFinite); #! @EndGroup @@ -363,8 +429,12 @@ DeclareAttribute("TranslationalHull", #! @EndExampleSession DeclareAttribute("NrLeftTranslations", IsSemigroup and CanUseFroidurePin and IsFinite); + +#! @Arguments S DeclareAttribute("NrRightTranslations", IsSemigroup and CanUseFroidurePin and IsFinite); + +#! @Arguments S DeclareAttribute("NrBitranslations", IsSemigroup and CanUseFroidurePin and IsFinite); #! @EndGroup @@ -392,6 +462,8 @@ DeclareAttribute("NrBitranslations", #! @EndExampleSession DeclareAttribute("InnerLeftTranslations", IsSemigroup and CanUseFroidurePin and IsFinite); + +#! @Arguments S DeclareAttribute("InnerRightTranslations", IsSemigroup and CanUseFroidurePin and IsFinite); #! @EndGroup diff --git a/gap/attributes/translat.gi b/gap/attributes/translat.gi index e673b49c8..9c8c7edb7 100644 --- a/gap/attributes/translat.gi +++ b/gap/attributes/translat.gi @@ -814,34 +814,24 @@ end); InstallMethod(InnerLeftTranslations, "for a semigroup", [IsSemigroup and CanUseFroidurePin and IsFinite], function(S) - local A, I, L, l, s; + local L, A; - I := []; L := LeftTranslations(S); A := GeneratorsOfSemigroup(S); - for s in A do - l := LeftTranslationNC(L, MappingByFunction(S, S, x -> s * x)); - Add(I, l); - od; - return Semigroup(I); + return Semigroup(List(A, s -> InducedLeftTranslationNC(L, s))); end); # Create and calculate the semigroup of inner right translations InstallMethod(InnerRightTranslations, "for a semigroup", [IsSemigroup and CanUseFroidurePin and IsFinite], function(S) - local A, I, R, r, s; + local R, A; - I := []; R := RightTranslations(S); A := GeneratorsOfSemigroup(S); - for s in A do - r := RightTranslationNC(R, MappingByFunction(S, S, x -> x * s)); - Add(I, r); - od; - return Semigroup(I); + return Semigroup(List(A, s -> InducedRightTranslationNC(R, s))); end); InstallMethod(LeftTranslation, @@ -930,6 +920,24 @@ function(L, l, opt...) return Objectify(TypeLeftTranslationsSemigroupElements(L), [map_as_list]); end); +InstallMethod(InducedLeftTranslation, +"for a left translations semigroup and a semigroup element", +[IsLeftTranslationsSemigroup, IsAssociativeElement], +function(L, s) + local S; + S := UnderlyingSemigroup(L); + return LeftTranslation(L, MappingByFunction(S, S, x -> s * x)); +end); + +InstallMethod(InducedLeftTranslationNC, +"for a left translations semigroup and a semigroup element", +[IsLeftTranslationsSemigroup, IsAssociativeElement], +function(L, s) + local S; + S := UnderlyingSemigroup(L); + return LeftTranslationNC(L, MappingByFunction(S, S, x -> s * x)); +end); + InstallMethod(RightTranslation, "for a right translations semigroup and a general mapping", [IsRightTranslationsSemigroup, IsGeneralMapping], @@ -1017,25 +1025,22 @@ function(R, r, opt...) return Objectify(TypeRightTranslationsSemigroupElements(R), [map_as_list]); end); -# Creates the ideal of the translational hull consisting of -# all inner bitranslations -InstallMethod(InnerTranslationalHull, "for a semigroup", -[IsSemigroup and CanUseFroidurePin and IsFinite], -function(S) - local A, I, H, L, R, l, r, s; - - I := []; - H := TranslationalHull(S); - L := LeftTranslations(S); - R := RightTranslations(S); - A := GeneratorsOfSemigroup(S); +InstallMethod(InducedRightTranslation, +"for a right translations semigroup and a semigroup element", +[IsRightTranslationsSemigroup, IsAssociativeElement], +function(R, s) + local S; + S := UnderlyingSemigroup(R); + return RightTranslation(R, MappingByFunction(S, S, x -> x * s)); +end); - for s in A do - l := LeftTranslationNC(L, MappingByFunction(S, S, x -> s * x)); - r := RightTranslationNC(R, MappingByFunction(S, S, x -> x * s)); - Add(I, BitranslationNC(H, l, r)); - od; - return Semigroup(I); +InstallMethod(InducedRightTranslationNC, +"for a right translations semigroup and a semigroup element", +[IsRightTranslationsSemigroup, IsAssociativeElement], +function(R, s) + local S; + S := UnderlyingSemigroup(R); + return RightTranslationNC(R, MappingByFunction(S, S, x -> x * s)); end); # Creates a bitranslation (l, r) from a left translation l and a right @@ -1067,6 +1072,41 @@ end); InstallGlobalFunction(BitranslationNC, {H, l, r} -> Objectify(TypeBitranslations(H), [l, r])); +InstallMethod(InducedBitranslation, +"for a translational hull and a semigroup element", +[IsBitranslationsSemigroup, IsAssociativeElement], +function(H, s) + local S; + S := UnderlyingSemigroup(H); + return Bitranslation(H, + InducedLeftTranslation(LeftTranslations(S), s), + InducedRightTranslation(RightTranslations(S), s)); +end); + +InstallMethod(InducedBitranslationNC, +"for a translational hull and a semigroup element", +[IsBitranslationsSemigroup, IsAssociativeElement], +function(H, s) + local S; + S := UnderlyingSemigroup(H); + return BitranslationNC(H, + InducedLeftTranslationNC(LeftTranslations(S), s), + InducedRightTranslationNC(RightTranslations(S), s)); +end); + +# Creates the ideal of the translational hull consisting of +# all inner bitranslations +InstallMethod(InnerTranslationalHull, "for a semigroup", +[IsSemigroup and CanUseFroidurePin and IsFinite], +function(S) + local H, A; + + H := TranslationalHull(S); + A := GeneratorsOfSemigroup(S); + + return Semigroup(List(A, s -> InducedBitranslationNC(H, s))); +end); + ############################################################################# # 3. Methods for rectangular bands ############################################################################# @@ -1322,27 +1362,26 @@ function(T) end); InstallMethod(RepresentativeMultipliers, -"for a semigroup of left translation", +"for a semigroup of translations", [IsTranslationsSemigroup], function(T) - local S, reps, M, out, x, i, j; + local S, reps, out, x, i, j, product; S := UnderlyingSemigroup(T); reps := UnderlyingRepresentatives(T); - if IsLeftTranslationsSemigroup(T) then - M := MultiplicationTableWithCanonicalPositions(S); - else - M := TransposedMultiplicationTableWithCanonicalPositions(S); - fi; - - out := ListWithIdenticalEntries(Length(M), fail); + out := ListWithIdenticalEntries(Size(S), fail); for i in [1 .. Length(reps)] do x := PositionCanonical(S, reps[i]); for j in [1 .. Size(S)] do - if out[M[x][j]] = fail then + if IsLeftTranslationsSemigroup(T) then + product := PositionCanonical(S, reps[i] * EnumeratorCanonical(S)[j]); + else + product := PositionCanonical(S, EnumeratorCanonical(S)[j] * reps[i]); + fi; + if out[product] = fail then # store [i, j] instead of [x, j] for efficiency - out[M[x][j]] := [i, j]; + out[product] := [i, j]; fi; od; out[x] := [i, 0]; @@ -1583,62 +1622,56 @@ IsIdenticalObj, [IsRightTranslation, IsRightTranslation], InstallMethod(\^, "for a semigroup element and a translation", [IsAssociativeElement, IsSemigroupTranslation], function(x, t) - local T, S, M, enum, y; + local T, S, enum, y; if IsLeftTranslation(t) then T := LeftTranslationsSemigroupOfFamily(FamilyObj(t)); S := UnderlyingSemigroup(T); - M := MultiplicationTableWithCanonicalPositions(S); else T := RightTranslationsSemigroupOfFamily(FamilyObj(t)); S := UnderlyingSemigroup(T); - M := TransposedMultiplicationTableWithCanonicalPositions(S); fi; + + S := UnderlyingSemigroup(T); if not x in S then ErrorNoReturn("the first argument must be an element of the domain of ", "the second"); fi; + enum := EnumeratorCanonical(S); x := PositionCanonical(S, x); y := RepresentativeMultipliers(T)[x]; if y[2] = 0 then return enum[t![1][y[1]]]; else - return enum[M[t![1][y[1]]][y[2]]]; + if IsLeftTranslation(t) then + return enum[t![1][y[1]]] * enum[y[2]]; + else + return enum[y[2]] * enum[t![1][y[1]]]; + fi; fi; end); -SEMIGROUPS.ImagePositionsOfTranslation := function(x) - local T, S, tab, images, g; - if IsLeftTranslation(x) then - T := LeftTranslationsSemigroupOfFamily(FamilyObj(x)); - S := UnderlyingSemigroup(T); - tab := MultiplicationTableWithCanonicalPositions(S); - else - T := RightTranslationsSemigroupOfFamily(FamilyObj(x)); - S := UnderlyingSemigroup(T); - tab := TransposedMultiplicationTableWithCanonicalPositions(S); - fi; - images := []; - for g in UnderlyingRepresentatives(T) do - UniteSet(images, tab[PositionCanonical(S, g ^ x)]); - od; - return images; -end; - InstallMethod(ImageSetOfTranslation, "for a left or right translation", [IsSemigroupTranslation], -function(x) - local T, S, enum; - if IsLeftTranslation(x) then - T := LeftTranslationsSemigroupOfFamily(FamilyObj(x)); +function(t) + local T, S, enum, gens; + + if IsLeftTranslation(t) then + T := LeftTranslationsSemigroupOfFamily(FamilyObj(t)); S := UnderlyingSemigroup(T); else - T := RightTranslationsSemigroupOfFamily(FamilyObj(x)); + T := RightTranslationsSemigroupOfFamily(FamilyObj(t)); S := UnderlyingSemigroup(T); fi; enum := EnumeratorCanonical(S); - return Set(List(SEMIGROUPS.ImagePositionsOfTranslation(x), i -> enum[i])); + gens := enum{t![1]}; + if IsLeftTranslation(t) then + # the image of a left translation is a *right* ideal + return Set(RightMagmaIdealByGenerators(S, gens)); + else + return Set(LeftMagmaIdealByGenerators(S, gens)); + fi; end); InstallMethod(\*, "for bitranslations", @@ -1659,12 +1692,12 @@ InstallMethod(UnderlyingSemigroup, function(T) if IsLeftTranslationsSemigroup(T) then return UnderlyingSemigroup(LeftTranslationsSemigroupOfFamily( - ElementsFamily( - FamilyObj(T)))); + ElementsFamily( + FamilyObj(T)))); else return UnderlyingSemigroup(RightTranslationsSemigroupOfFamily( - ElementsFamily( - FamilyObj(T)))); + ElementsFamily( + FamilyObj(T)))); fi; end); diff --git a/tst/standard/attributes/translat.tst b/tst/standard/attributes/translat.tst index 35e87ba18..405561187 100644 --- a/tst/standard/attributes/translat.tst +++ b/tst/standard/attributes/translat.tst @@ -1,7 +1,7 @@ ############################################################################# ## #W standard/translat.tst -#Y Copyright (C) 2016-17 Finn Smith +#Y Copyright (C) 2016-26 Finn Smith ## ## Licensing information can be found in the README file of this package. ## @@ -792,6 +792,17 @@ gap> S := ReesZeroMatrixSemigroup(G, mat);; gap> NrBitranslations(S); 14977 +# Induced translations +gap> S := FullTransformationMonoid(4);; +gap> I := SemigroupIdeal(S, Transformation([1, 1, 1, 2]));; +gap> Size(Set(S, s -> InducedBitranslation(TranslationalHull(I), s))); +256 +gap> S := JonesMonoid(7);; +gap> a := Bipartition([[1, -1], [2, -2], [3, -3], [4, 5], [-4, -5], [6, 7], [-6, -7]]);; +gap> I := SemigroupIdeal(S, a);; +gap> Size(Set(S, s -> InducedBitranslationNC(TranslationalHull(I), s))); +429 + # gap> SEMIGROUPS.StopTest(); gap> STOP_TEST("Semigroups package: standard/translat.tst");