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");