Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  translat.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

#############################################################################
##
# W  translat.gi
# Y  Copyright (C) 2015-22                     James D. Mitchell, Finn Smith
##
##  Licensing information can be found in the README file of this package.
##
#############################################################################
##
##
#############################################################################
## This file contains methods for dealing with left and right translation
## semigroups, as well as translational hulls.
##
## Some of the implementation in this file was based on the implementation of
## RMS in reesmatsemi.gi in the GAP library - in particular, the creation of
## the semigroups and their relation to their elements.
##
## The code specific to rectangular bands is based on
## Howie, J.M. (1995) 'Fundamentals of Semigroup theory'.
## United Kingdom: Oxford University Press. (p. 116)
##
## This file is organised as follows:
##    1. Internal functions
##    2. Functions for the creation of left/right translations semigroup
##        and translational hulls, and their elements
##    3. Methods for rectangular bands
##    4. Methods for monoids
##    5. Technical methods, eg. PrintObj, *, =, etc.
##
#############################################################################

#############################################################################
# 1. Internal Functions
#############################################################################

SEMIGROUPS.HasEasyTranslationsGenerators := function(T)
  local S;

  S := UnderlyingSemigroup(T);
  return IsZeroSimpleSemigroup(S) or
         IsRectangularBand(S) or
         IsSimpleSemigroup(S) or
         SEMIGROUPS.IsNormalRMSOverGroup(S) or
         IsMonogenicSemigroup(S) or
         IsMonoid(S);
end;

SEMIGROUPS.HasEasyBitranslationsGenerators := function(T)
  local S;

  S := UnderlyingSemigroup(T);
  return IsRectangularBand(S) or
         IsMonogenicSemigroup(S);
end;

# Hash translations by their underlying transformations
SEMIGROUPS.HashFunctionForTranslations :=
{x, data} -> ORB_HashFunctionForPlainFlatList(x![1], data);

# Hash bitranslations as sum of underlying transformation hashes
SEMIGROUPS.HashFunctionForBitranslations := function(x, data)
    return (SEMIGROUPS.HashFunctionForTranslations(x![1], data)
      + SEMIGROUPS.HashFunctionForTranslations(x![2], data)) mod data + 1;
end;

SEMIGROUPS.LeftTranslationsBacktrackData := function(S)
  local n, m, id, repspos, multtable, multsets, r_classes, r_class_map,
  r_class_inv_map, r_classes_below, max_R_intersects, intersect, reps,
  left_canon_inverse_by_gen, left_inverses_by_rep, x, right_inverses, seen, t,
  s, transposed_multtable, transposed_multsets, U, Ui, keep, B, sb, r, i, j, a,
  u;

  n       := Size(S);
  reps    := UnderlyingRepresentatives(LeftTranslations(S));
  m       := Size(reps);
  id      := n + 1;
  repspos := List(reps, x -> PositionCanonical(S, x));

  multtable := List(MultiplicationTableWithCanonicalPositions(S), ShallowCopy);
  for i in [1 .. n] do
    Add(multtable[i], i);
  od;
  Add(multtable, [1 .. id]);

  multsets := List(multtable, Set);

  r_classes := RClasses(S);
  r_class_map := [];

  for i in [1 .. Length(r_classes)] do
    for s in r_classes[i] do
      r_class_map[PositionCanonical(S, s)] := i;
    od;
  od;

  r_class_inv_map := List(r_classes,
                          x -> PositionCanonical(S, Representative(x)));
  r_classes_below := List([1 .. m],
                          i -> Set(r_class_map{multsets[repspos[i]]}));
  max_R_intersects := List([1 .. m], x -> []);

  for i in [1 .. m - 1] do
    for j in [i + 1 .. m] do
      intersect := Intersection(r_classes_below[i], r_classes_below[j]);
      reps := r_class_inv_map{intersect};

      max_R_intersects[i][j] := Filtered(reps,
                                         x -> not ForAny(reps,
                                                         y -> x <> y and
                                                           x in multsets[y]));

      max_R_intersects[j][i] := max_R_intersects[i][j];
    od;
  od;

  left_canon_inverse_by_gen := List([1 .. n], x -> []);

  # for all s in S, store the elements t such that reps[i] * t = s for each i
  left_inverses_by_rep := List([1 .. n], x -> List([1 .. m], y -> []));
  for i in [1 .. m] do
    for t in [1 .. id] do
      x := multtable[repspos[i]][t];
      Add(left_inverses_by_rep[x][i], t);
      if not IsBound(left_canon_inverse_by_gen[x][i]) then
        left_canon_inverse_by_gen[x][i] := t;
      fi;
    od;
  od;

  # for each t in the left inverses of some a in max_R_intersects[i][j] by
  # reps[j], compute the right inverses of each s in S under t
  right_inverses := List([1 .. n], x -> ListWithIdenticalEntries(n + 1, fail));
  seen := List([1 .. id], ReturnFalse);
  for i in [1 .. m] do
    for j in [1 .. m] do
      if i = j then
        continue;
      fi;
      for a in max_R_intersects[i][j] do
        t := left_canon_inverse_by_gen[a][j];
        # don't repeat the calculation if we've already done it for t!
        if not seen[t] then
          seen[t] := true;
          for u in [1 .. n] do
            s := multtable[u][t];
            if right_inverses[s][t] = fail then
              right_inverses[s][t] := [];
            fi;
            Add(right_inverses[s][t], u);
          od;
        fi;
      od;
    od;
  od;

  transposed_multtable := TransposedMat(multtable);
  transposed_multsets  := List(transposed_multtable, Set);

  # compute intersection over a of the sets U_{i, a} from the paper
  U := [];
  for i in [1 .. m] do
    Ui := BlistList([1 .. n], []);
    for s in [1 .. n] do
      if Ui[s] then
        continue;
      fi;
      keep := true;
      for a in multsets[repspos[i]] do
        B := left_inverses_by_rep[a][i];
        sb := multtable[s][B[1]];
        if multtable[s]{B} <> ListWithIdenticalEntries(Size(B), sb) then
          keep := false;
          break;
        fi;
      od;
      if keep then
        UniteBlistList([1 .. n], Ui, transposed_multsets[s]);
        Ui[s] := true;
      fi;
    od;
    U[i] := ListBlist([1 .. n], Ui);
  od;

  r := rec();
  r.left_canon_inverse_by_gen := left_canon_inverse_by_gen;
  r.left_inverses_by_rep := left_inverses_by_rep;
  r.max_R_intersects := max_R_intersects;
  r.multsets := multsets;
  r.multtable := multtable;
  r.n := n;
  r.right_inverses := right_inverses;
  r.U := U;
  r.V := List([1 .. m], j -> List([1 .. n], a -> []));
  r.W := List([1 .. m], i -> List([1 .. m], j -> []));
  return r;
end;

SEMIGROUPS.RightInversesLeftReps := function(S)
  local n, reps, m, multtable, out, k, x, i, t;

  n         := Size(S);
  reps      := UnderlyingRepresentatives(LeftTranslations(S));
  m         := Size(reps);
  multtable := MultiplicationTableWithCanonicalPositions(S);
  out       := List([1 .. n], x -> List([1 .. m], y -> []));

  for i in [1 .. m] do
    k := PositionCanonical(S, reps[i]);
    for t in [1 .. n] do
      x := multtable[t][k];
      Add(out[x][i], t);
    od;
  od;
  return out;
end;

SEMIGROUPS.LeftInversesRightReps := function(S)
  local n, reps, m, multtable, out, k, x, i, t;

  n         := Size(S);
  reps      := UnderlyingRepresentatives(RightTranslations(S));
  m         := Size(reps);
  multtable := MultiplicationTableWithCanonicalPositions(S);
  out       := List([1 .. n], x -> List([1 .. m], y -> []));

  for i in [1 .. m] do
    k := PositionCanonical(S, reps[i]);
    for t in [1 .. n] do
      x := multtable[k][t];
      Add(out[x][i], t);
    od;
  od;
  return out;
end;

SEMIGROUPS.RightTranslationsBacktrackData := function(S)
  local n, m, id, repspos, transpose_multtable, transpose_multsets, l_classes,
  l_class_map, l_class_inv_map, l_classes_below, max_L_intersects, intersect,
  reps, right_canon_inverse_by_gen, right_inverses_by_rep, x, left_inverses,
  seen, s, multsets, T, Ti, keep, B, sb, r, i, j, t, a, u, multtable;

  n       := Size(S);
  reps    := UnderlyingRepresentatives(RightTranslations(S));
  m       := Size(reps);
  id      := n + 1;
  repspos := List(reps, x -> PositionCanonical(S, x));

  transpose_multtable :=
    List(TransposedMultiplicationTableWithCanonicalPositions(S),
         ShallowCopy);
  for i in [1 .. n] do
    Add(transpose_multtable[i], i);
  od;
  Add(transpose_multtable, [1 .. id]);
  transpose_multsets := List(transpose_multtable, Set);

  multtable := TransposedMat(transpose_multtable);  # For the added identity

  l_classes := LClasses(S);
  l_class_map := [];

  for i in [1 .. Length(l_classes)] do
    for s in l_classes[i] do
      l_class_map[PositionCanonical(S, s)] := i;
    od;
  od;

  l_class_inv_map := List(l_classes,
                          x -> PositionCanonical(S, Representative(x)));
  l_classes_below := List([1 .. m],
                      i -> Set(l_class_map{transpose_multsets[repspos[i]]}));
  max_L_intersects := List([1 .. m], x -> []);

  for i in [1 .. m - 1] do
    for j in [i + 1 .. m] do
      intersect := Intersection(l_classes_below[i], l_classes_below[j]);
      reps := l_class_inv_map{intersect};

      max_L_intersects[i][j] := Filtered(reps,
                                  x -> not ForAny(reps,
                                            y -> x <> y and
                                                 x in transpose_multsets[y]));

      max_L_intersects[j][i] := max_L_intersects[i][j];
    od;
  od;

  right_canon_inverse_by_gen := List([1 .. n], x -> []);

  # for all s in S, store the elements t such that t * reps[i] = s for each i
  right_inverses_by_rep := List([1 .. n], x -> List([1 .. m], y -> []));
  for i in [1 .. m] do
    for t in [1 .. id] do
      x := transpose_multtable[repspos[i]][t];
      Add(right_inverses_by_rep[x][i], t);
      if not IsBound(right_canon_inverse_by_gen[x][i]) then
        right_canon_inverse_by_gen[x][i] := t;
      fi;
    od;
  od;

  # for each t in the right inverses of some a in max_L_intersects[i][j] by
  # reps[j], compute the left inverses of each s in S under t
  left_inverses := List([1 .. n], x -> ListWithIdenticalEntries(n + 1, fail));
  seen := List([1 .. id], ReturnFalse);
  for i in [1 .. m] do
    for j in [1 .. m] do
      if i = j then
        continue;
      fi;
      for a in max_L_intersects[i][j] do
        for t in right_inverses_by_rep[a][j] do
          # don't repeat the calculation if we've already done it for t!
          if not seen[t] then
            seen[t] := true;
            for u in [1 .. n] do
              s := transpose_multtable[u][t];
              if left_inverses[s][t] = fail then
                left_inverses[s][t] := [];
              fi;
              Add(left_inverses[s][t], u);
            od;
          fi;
        od;
      od;
    od;
  od;

  multsets := List(multtable, Set);

  T := [];
  for i in [1 .. m] do
    Ti := BlistList([1 .. n], []);
    for s in [1 .. n] do
      if Ti[s] then
        continue;
      fi;
      keep := true;
      for a in transpose_multsets[repspos[i]] do
        B := right_inverses_by_rep[a][i];
        sb := transpose_multtable[s][B[1]];
        if (transpose_multtable[s]{B} <>
            ListWithIdenticalEntries(Size(B), sb)) then
          keep := false;
          break;
        fi;
      od;
      if keep then
        UniteBlistList([1 .. n], Ti, multsets[s]);
        Ti[s] := true;
      fi;
    od;
    T[i] := ListBlist([1 .. n], Ti);
  od;

  r := rec();
  r.left_inverses := left_inverses;
  r.max_L_intersects := max_L_intersects;
  r.n := n;
  r.right_canon_inverse_by_gen := right_canon_inverse_by_gen;
  r.right_inverses_by_rep := right_inverses_by_rep;
  r.transpose_multtable := transpose_multtable;
  r.T := T;
  r.F := List([1 .. m], j -> List([1 .. n], a -> []));
  r.G := List([1 .. m], i -> List([1 .. m], j -> []));
  return r;
end;

SEMIGROUPS.LeftTranslationsBacktrackDataW := function(data, i, j, s)
  local left_canon_inverse_by_gen, multtable, right_inverses, W, r, x, a;

  if IsBound(data.W[i][j][s]) then
    return data.W[i][j][s];
  fi;

  left_canon_inverse_by_gen := data.left_canon_inverse_by_gen;
  multtable := data.multtable;
  right_inverses := data.right_inverses;
  W := [1 .. data.n];
  for a in data.max_R_intersects[i][j] do
    r := left_canon_inverse_by_gen[a][i];
    x := multtable[s][r];
    if right_inverses[x][left_canon_inverse_by_gen[a][j]] = fail then
      W := [];
      break;
    else
      W := Intersection(W,
           right_inverses[x][left_canon_inverse_by_gen[a][j]]);
    fi;
  od;
  data.W[i][j][s] := W;
  return W;
end;

SEMIGROUPS.RightTranslationsBacktrackDataG := function(data, i, j, s)
  local right_canon_inverse_by_gen, transpose_multtable, left_inverses, G, l, x,
  a;

  if IsBound(data.G[i][j][s]) then
    return data.G[i][j][s];
  fi;

  right_canon_inverse_by_gen := data.right_canon_inverse_by_gen;
  transpose_multtable := data.transpose_multtable;
  left_inverses := data.left_inverses;
  G := [1 .. data.n];
  for a in data.max_L_intersects[i][j] do
    l := right_canon_inverse_by_gen[a][i];
    x := transpose_multtable[s][l];
    if left_inverses[x][right_canon_inverse_by_gen[a][j]] = fail then
      G := [];
      break;
    else
      G := Intersection(G,
           left_inverses[x][right_canon_inverse_by_gen[a][j]]);
    fi;
  od;
  data.G[i][j][s] := G;
  return G;
end;

SEMIGROUPS.LeftTranslationsBacktrack := function(L, opt...)
  local S, reps, m, nr_only, nr, data, U, omega_stack, bt, lambda, out, i;

  S                 := UnderlyingSemigroup(L);
  reps              := UnderlyingRepresentatives(L);
  m                 := Size(reps);
  nr_only           := opt = ["nr_only"];
  nr                := 0;

  data := SEMIGROUPS.LeftTranslationsBacktrackData(S);
  U := data.U;

  # restrict via the U_{i}
  for i in [1 .. m] do
    omega_stack := [List(U, ShallowCopy)];
  od;

  bt := function(i)
    local consistent, W, s, j;

    for s in omega_stack[i][i] do
      lambda[i] := s;
      if i = m then
        if nr_only then
          nr := nr + 1;
        else
          Add(out, ShallowCopy(lambda));
        fi;
      else
        consistent := true;
        omega_stack[i + 1] := [];
        for j in [i + 1 .. m] do
          W := SEMIGROUPS.LeftTranslationsBacktrackDataW(data, i, j, s);
          omega_stack[i + 1][j] := Intersection(omega_stack[i][j], W);
          if IsEmpty(omega_stack[i + 1][j]) then
            consistent := false;
            break;
          fi;
        od;
        if consistent then
          bt(i + 1);
        fi;
      fi;
    od;
  end;

  lambda := [];
  out := [];
  bt(1);

  if nr_only then
    return nr;
  fi;

  Apply(out, x -> LeftTranslationNC(L, x));
  return out;
end;

SEMIGROUPS.RightTranslationsBacktrack := function(R, opt...)
  local S, reps, n, m, omega_stack, nr_only, nr, data, T, possiblegenvals, bt,
  rho, out, i;

  S           := UnderlyingSemigroup(R);
  reps        := UnderlyingRepresentatives(R);
  n           := Size(S);
  m           := Size(reps);
  omega_stack := List([1 .. m], i -> List([1 .. m], j -> []));
  nr_only     := opt = ["nr_only"];
  nr          := 0;

  data := SEMIGROUPS.RightTranslationsBacktrackData(S);
  T := data.T;

  possiblegenvals := List([1 .. m], i -> [1 .. n]);

  # restrict via the T_{i}
  for i in [1 .. m] do
    IntersectSet(possiblegenvals[i], T[i]);
  od;

  bt := function(i)
    local consistent, G, s, j;
    for s in omega_stack[i][i] do
      rho[i] := s;
      if i = m then
        if nr_only then
          nr := nr + 1;
        else
          Add(out, ShallowCopy(rho));
        fi;
      else
        consistent := true;
        omega_stack[i + 1] := [];
        for j in [i + 1 .. m] do
          G := SEMIGROUPS.RightTranslationsBacktrackDataG(data, i, j, s);
          omega_stack[i + 1][j] := Intersection(omega_stack[i][j], G);
          if IsEmpty(omega_stack[i + 1][j]) then
            consistent := false;
            break;
          fi;
        od;
        if consistent then
          bt(i + 1);
        fi;
      fi;
    od;
  end;

  omega_stack := [possiblegenvals];
  rho := [];
  out := [];
  bt(1);

  if nr_only then
    return nr;
  fi;

  Apply(out, x -> RightTranslationNC(RightTranslations(S), x));
  return out;
end;

SEMIGROUPS.BitranslationsBacktrack := function(H, opt...)
  local S, n, l_reps, r_reps, l_m, r_m, l_repspos, r_repspos, l_omega_stack,
  r_omega_stack, nr_only, nr, multtable, left_data, right_data,
  left_inverses_by_right_rep, right_inverses_by_left_rep, U, T, L, R, l_bt,
  r_bt, lambda, rho, out, i;

  S             := UnderlyingSemigroup(H);
  n             := Size(S);
  l_reps        := UnderlyingRepresentatives(LeftTranslations(S));
  r_reps        := UnderlyingRepresentatives(RightTranslations(S));
  l_m           := Size(l_reps);
  r_m           := Size(r_reps);
  l_repspos     := List(l_reps, x -> PositionCanonical(S, x));
  r_repspos     := List(r_reps, x -> PositionCanonical(S, x));
  l_omega_stack := List([1 .. l_m], i -> List([1 .. l_m], j -> []));
  r_omega_stack := List([1 .. r_m], i -> List([1 .. r_m], j -> []));
  nr_only       := opt = ["nr_only"];
  nr            := 0;

  multtable := MultiplicationTableWithCanonicalPositions(S);

  left_data                   := SEMIGROUPS.LeftTranslationsBacktrackData(S);
  right_data                  := SEMIGROUPS.RightTranslationsBacktrackData(S);
  left_inverses_by_right_rep  := SEMIGROUPS.LeftInversesRightReps(S);
  right_inverses_by_left_rep  := SEMIGROUPS.RightInversesLeftReps(S);

  U := left_data.U;
  T := right_data.T;

  l_omega_stack[1] := List([1 .. l_m], i -> [1 .. n]);
  r_omega_stack[1] := List([1 .. r_m], i -> [1 .. n]);

  # restrict via the T_{i} and U_{i}
  for i in [1 .. l_m] do
    l_omega_stack[1][i] := U[i];
  od;
  for i in [1 .. r_m] do
    r_omega_stack[1][i] := T[i];
  od;

  L := LeftTranslations(S);
  R := RightTranslations(S);

  l_bt := function(i)
    local depth, r_finished, consistent, W, x, s, j;

    if i <= r_m then
      depth := 2 * i - 1;
    else
      depth := r_m + i;
    fi;

    r_finished := i > r_m;

    for s in l_omega_stack[depth][i] do
      lambda[i] := s;

      if r_finished and i = l_m then
        if nr_only then
          nr := nr + 1;
        else
          Add(out, BitranslationNC(H,
                                   LeftTranslationNC(L, lambda),
                                   RightTranslationNC(R, rho)));
        fi;
        continue;
      fi;

      consistent                := true;
      l_omega_stack[depth + 1]  := [];
      r_omega_stack[depth + 1]  := [];

      # make sure to take care of linking condition
      # x_i * lambda(x_i) = (x_i)rho * x_i
      for j in [i .. Maximum(l_m, r_m)] do
        if (j > i and j <= l_m) then
          W := SEMIGROUPS.LeftTranslationsBacktrackDataW(left_data, i, j, s);
          l_omega_stack[depth + 1][j] := Intersection(l_omega_stack[depth][j],
                                                      W);
        fi;

        if j <= r_m then
          x := multtable[r_repspos[j]][s];
          r_omega_stack[depth + 1][j] :=
              Intersection(r_omega_stack[depth][j],
                           right_inverses_by_left_rep[x][i]);
        fi;

        if ((j > i and j <= l_m and IsEmpty(l_omega_stack[depth + 1][j])) or
            (j <= r_m and IsEmpty(r_omega_stack[depth + 1][j]))) then
          consistent := false;
          break;
        fi;
      od;

      if consistent then
        if r_finished then
          l_bt(i + 1);
        else
          # this i is intentional, we go LRLRLR...
          r_bt(i);
        fi;
      fi;
    od;
  end;

  r_bt := function(i)
    local depth, l_finished, consistent, G, x, s, j;

    if i <= l_m then
      depth := 2 * i;
    else
      depth := l_m + i;
    fi;

    l_finished := i >= l_m;

    for s in r_omega_stack[depth][i] do
      rho[i] := s;

      if l_finished and i = r_m then
        if nr_only then
          nr := nr + 1;
        else
          Add(out, BitranslationNC(H,
                                   LeftTranslationNC(L, lambda),
                                   RightTranslationNC(R, rho)));
        fi;
        continue;
      fi;

      consistent := true;
      l_omega_stack[depth + 1] := [];
      r_omega_stack[depth + 1] := [];

      for j in [i + 1 .. Maximum(r_m, l_m)] do
        if j <= r_m then
          G := SEMIGROUPS.RightTranslationsBacktrackDataG(right_data, i, j, s);
          r_omega_stack[depth + 1][j] := Intersection(r_omega_stack[depth][j],
                                                      G);
        fi;

        if j <= l_m then
          x := multtable[s][l_repspos[j]];
          l_omega_stack[depth + 1][j] :=
              Intersection(l_omega_stack[depth][j],
                           left_inverses_by_right_rep[x][i]);
        fi;

        if ((j <= l_m and IsEmpty(l_omega_stack[depth + 1][j])) or
            (j <= r_m and IsEmpty(r_omega_stack[depth + 1][j]))) then
          consistent := false;
          break;
        fi;
      od;

      if consistent then
        if l_finished then
          r_bt(i + 1);
        else
          l_bt(i + 1);
        fi;
      fi;
    od;
  end;

  lambda := [];
  rho := [];
  out := [];
  # Warning: it is assumed that the alternation starts with L; otherwise
  # the depth calculation in l_bt and r_bt must be altered, and some of the
  # logic changed
  l_bt(1);

  if nr_only then
    return nr;
  fi;

  return out;
end;

#############################################################################
# 2. Creation of translations semigroups, translational hull, and elements
#############################################################################

InstallMethod(LeftTranslations, "for a finite enumerable semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local fam, L, type;

  if SEMIGROUPS.IsNormalRMSOverGroup(S) then
    fam   := SEMIGROUPS.FamOfRMSLeftTranslationsByTriple();
    type  := fam!.type;
  else
    fam       := NewFamily("LeftTranslationsSemigroupElementsFamily",
                      IsLeftTranslation);
    type      := NewType(fam, IsLeftTranslation);
    fam!.type := type;
  fi;

  # create the semigroup of left translations
  L := Objectify(NewType(CollectionsFamily(fam), IsLeftTranslationsSemigroup
                         and IsWholeFamily and IsAttributeStoringRep), rec());

  # store the type of the elements in the semigroup
  SetTypeLeftTranslationsSemigroupElements(L, type);
  SetLeftTranslationsSemigroupOfFamily(fam, L);
  SetUnderlyingSemigroup(L, S);
  SetLeftTranslations(S, L);

  return L;
end);

InstallMethod(RightTranslations, "for a finite enumerable semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local fam, type, R;

  if SEMIGROUPS.IsNormalRMSOverGroup(S) then
    fam   := SEMIGROUPS.FamOfRMSRightTranslationsByTriple();
    type  := fam!.type;
  else
    fam       := NewFamily("RightTranslationsSemigroupElementsFamily",
                      IsRightTranslation);
    type      := NewType(fam, IsRightTranslation);
    fam!.type := type;
  fi;

  # create the semigroup of right translations
  R := Objectify(NewType(CollectionsFamily(fam), IsRightTranslationsSemigroup
    and IsWholeFamily and IsAttributeStoringRep), rec());

  # store the type of the elements in the semigroup
  SetTypeRightTranslationsSemigroupElements(R, type);
  SetRightTranslationsSemigroupOfFamily(fam, R);
  SetUnderlyingSemigroup(R, S);
  SetRightTranslations(S, R);

  return R;
end);

InstallMethod(TranslationalHull, "for a finite enumerable semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local fam, type, H;

  if SEMIGROUPS.IsNormalRMSOverGroup(S) then
    fam   := SEMIGROUPS.FamOfRMSBitranslationsByTriple();
    type  := fam!.type;
  else
    fam := NewFamily("BitranslationsFamily",
                      IsBitranslation);
    type      := NewType(fam, IsBitranslation);
    fam!.type := type;
  fi;

  # create the translational hull
  H := Objectify(NewType(CollectionsFamily(fam), IsBitranslationsSemigroup and
    IsWholeFamily and IsAttributeStoringRep), rec());

  # store the type of the elements in the semigroup
  SetTypeBitranslations(H, type);
  SetTranslationalHullOfFamily(fam, H);
  SetUnderlyingSemigroup(H, S);
  SetTranslationalHull(S, H);

  return H;
end);

# Create and calculate the semigroup of inner left translations
InstallMethod(InnerLeftTranslations, "for a semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local A, I, L, l, s;

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

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

InstallMethod(LeftTranslation,
"for a left translations semigroup and a general mapping",
[IsLeftTranslationsSemigroup, IsGeneralMapping],
function(L, map)
  local S, reps;

  S    := UnderlyingSemigroup(L);
  reps := UnderlyingRepresentatives(L);

  if S <> Source(map) or Source(map) <> Range(map) then
    ErrorNoReturn("the domain and range of the second argument must be ",
                  "the underlying semigroup of the first");
  elif ForAny(reps, s -> ForAny(S, t -> (s ^ map) * t <> (s * t) ^ map)) then
    ErrorNoReturn("the mapping given must define a left translation");
  fi;

  return LeftTranslationNC(L, map);
end);

InstallOtherMethod(LeftTranslation,
"for a left translations semigroup and a dense list",
[IsLeftTranslationsSemigroup, IsDenseList],
function(L, l)
  local S, reps, semi_list, full_lambda, g, lg, x, y, i, s;

  S    := UnderlyingSemigroup(L);
  reps := UnderlyingRepresentatives(L);

  if Length(l) <> Length(reps) then
    ErrorNoReturn("the second argument must map indices of representatives ",
                  "to indices of elements of the semigroup of the first ",
                  "argument");
  elif not ForAll(l, y -> IsPosInt(y) and y <= Size(S)) then
    ErrorNoReturn("the second argument must map indices of representatives ",
                  "to indices of elements of the semigroup of the first ",
                  "argument");
  fi;
  # TODO (later) store and use LeftTranslationsBacktrackData
  semi_list := AsListCanonical(S);
  full_lambda := [];
  for i in [1 .. Size(reps)] do
    g := reps[i];
    lg := l[i];
    for s in S do
      x := PositionCanonical(S, g * s);
      y := PositionCanonical(S, semi_list[lg] * s);
      if not IsBound(full_lambda[x]) then
        full_lambda[x] := y;
      fi;
      if full_lambda[x] <> y then
        ErrorNoReturn("the transformation given must define a left ",
                      "translation");
      fi;
    od;
  od;

  return LeftTranslationNC(L, l);
end);

# Careful - expects a particular form for normal RMS
InstallGlobalFunction(LeftTranslationNC,
function(L, l, opt...)
  local S, reps, map_as_list, i;

  S := UnderlyingSemigroup(L);
  if _IsLeftTranslationOfNormalRMSSemigroup(L) then
    if IsEmpty(opt) then
      return _LeftTranslationOfNormalRMSNC(L, l);
    else
      return _LeftTranslationOfNormalRMSNC(L, l, opt[1]);
    fi;
  fi;
  if IsDenseList(l) then
    return Objectify(TypeLeftTranslationsSemigroupElements(L),
                    [ShallowCopy(l)]);
  fi;
  # l is a mapping on UnderlyingSemigroup(S)
  reps := UnderlyingRepresentatives(L);
  map_as_list  := [];
  for i in [1 .. Length(reps)] do
    map_as_list[i] := PositionCanonical(S, reps[i] ^ l);
  od;

  return Objectify(TypeLeftTranslationsSemigroupElements(L), [map_as_list]);
end);

InstallMethod(RightTranslation,
"for a right translations semigroup and a general mapping",
[IsRightTranslationsSemigroup, IsGeneralMapping],
function(R, map)
  local S, reps;

  S    := UnderlyingSemigroup(R);
  reps := UnderlyingRepresentatives(R);

  if S <> Source(map) or Source(map) <> Range(map) then
    ErrorNoReturn("the domain and range of the second argument must be ",
                  "the underlying semigroup of the first");
  elif ForAny(reps, s -> ForAny(S, t -> s * (t ^ map) <> (s * t) ^ map)) then
    ErrorNoReturn("the mapping given must define a right translation");
  fi;

  return RightTranslationNC(R, map);
end);

InstallOtherMethod(RightTranslation,
"for a right translations semigroup and a dense list",
[IsRightTranslationsSemigroup, IsDenseList],
function(R, r)
  local S, reps, semi_list, full_rho, g, rg, x, y, i, s;

  S    := UnderlyingSemigroup(R);
  reps := UnderlyingRepresentatives(R);

  if Length(r) <> Length(reps) then
    ErrorNoReturn("the second argument must map indices of representatives ",
                  "to indices of elements of the semigroup of the first ",
                  "argument");
  elif not ForAll(r, y -> IsPosInt(y) and y <= Size(S)) then
    ErrorNoReturn("the second argument must map indices of representatives ",
                  "to indices of elements of the semigroup of the first ",
                  "argument");
  fi;

  # TODO (later) store and use some of RightTranslationsBacktrackData
  semi_list := AsListCanonical(S);
  full_rho := [];
  for i in [1 .. Size(reps)] do
    g := reps[i];
    rg := r[i];
    for s in S do
      x := PositionCanonical(S, s * g);
      y := PositionCanonical(S, s * semi_list[rg]);
      if not IsBound(full_rho[x]) then
        full_rho[x] := y;
      fi;
      if full_rho[x] <> y then
        ErrorNoReturn("the transformation given must define a right ",
                      "translation");
      fi;
    od;
  od;

  return RightTranslationNC(R, r);
end);

# Careful - expects a particular form for normal RMS
InstallGlobalFunction(RightTranslationNC,
function(R, r, opt...)
  local S, reps, map_as_list, i;

  S := UnderlyingSemigroup(R);
  if _IsRightTranslationOfNormalRMSSemigroup(R) then
    if IsEmpty(opt) then
      return _RightTranslationOfNormalRMSNC(R, r);
    else
      return _RightTranslationOfNormalRMSNC(R, r, opt[1]);
    fi;
  fi;
  if IsDenseList(r) then
    return Objectify(TypeRightTranslationsSemigroupElements(R),
                    [ShallowCopy(r)]);
  fi;
  # r is a mapping on UnderlyingSemigroup(S)
  reps := UnderlyingRepresentatives(R);
  map_as_list  := [];
  for i in [1 .. Length(reps)] do
    map_as_list[i] := PositionCanonical(S, reps[i] ^ r);
  od;

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

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

# Creates a bitranslation (l, r) from a left translation l and a right
# translation r, as an element of a translational hull H.
InstallMethod(Bitranslation,
[IsBitranslationsSemigroup, IsLeftTranslation, IsRightTranslation],
function(H, l, r)
  local S, L, R, l_reps, r_reps;

  S := UnderlyingSemigroup(H);
  L := LeftTranslationsSemigroupOfFamily(FamilyObj(l));
  R := RightTranslationsSemigroupOfFamily(FamilyObj(r));

  if UnderlyingSemigroup(L) <> S or UnderlyingSemigroup(R) <> S then
    ErrorNoReturn("each argument must have the same underlying semigroup");
  fi;

  l_reps := UnderlyingRepresentatives(L);
  r_reps := UnderlyingRepresentatives(R);

  if ForAny(l_reps, t -> ForAny(r_reps, s -> s * (t ^ l) <> (s ^ r) * t)) then
     ErrorNoReturn("the translations given must satisfy the linking ",
                   "condition");
  fi;

  return BitranslationNC(H, l, r);
end);

InstallGlobalFunction(BitranslationNC,
{H, l, r} -> Objectify(TypeBitranslations(H), [l, r]));

#############################################################################
# 3. Methods for rectangular bands
#############################################################################

# Every transformation on the relevant index set corresponds to a translation.
# The R classes of an I x J rectangular band correspond to (i, J) for i in I.
# Dually for L classes.
InstallMethod(Size,
"for the semigroup of left or right translations of a rectangular band",
[IsTranslationsSemigroup and IsWholeFamily], 2,
function(T)
  local S, n;
  S := UnderlyingSemigroup(T);
  if not IsRectangularBand(S) then
    TryNextMethod();
  elif IsLeftTranslationsSemigroup(T) then
    n := NrRClasses(S);
  else
    n := NrLClasses(S);
  fi;

  return n ^ n;
end);

# The translational hull of a rectangular band is the direct product of the
# left translations and right translations
InstallMethod(Size, "for the translational hull of a rectangular band",
[IsBitranslationsSemigroup and IsWholeFamily],
1,
function(H)
  local S, L, R;
  S := UnderlyingSemigroup(H);
  if not IsRectangularBand(S) then
    TryNextMethod();
  fi;
  L := LeftTranslations(S);
  R := RightTranslations(S);
  return Size(L) * Size(R);
end);

# Generators of the left/right translations semigroup on the I x J rectangular
# band correspond to the generators of the full transformation monoid on I or J.
InstallMethod(GeneratorsOfSemigroup,
"for the semigroup of left or right translations of a rectangular band",
[IsTranslationsSemigroup and IsWholeFamily],
2,
function(T)
  local S, n, iso, inv, rms, gens, t, f;

  S := UnderlyingSemigroup(T);
  if not IsRectangularBand(S) then
    TryNextMethod();
  fi;

  iso := IsomorphismReesMatrixSemigroup(S);
  inv := InverseGeneralMapping(iso);
  rms := Range(iso);
  if IsLeftTranslationsSemigroup(T) then
    n := Length(Rows(rms));
  else
    n := Length(Columns(rms));
  fi;

  gens := [];
  for t in GeneratorsOfMonoid(FullTransformationMonoid(n)) do
    if IsLeftTranslationsSemigroup(T) then
      f := function(x)
        return ReesMatrixSemigroupElement(rms, x[1] ^ t,
          (), x[3]);
      end;
      Add(gens, LeftTranslationNC(T, CompositionMapping(inv,
      MappingByFunction(rms, rms, f), iso)));
    else
      f := function(x)
        return ReesMatrixSemigroupElement(rms, x[1],
          (), x[3] ^ t);
      end;
      Add(gens, RightTranslationNC(T, CompositionMapping(inv,
        MappingByFunction(rms, rms, f), iso)));
    fi;
  od;
  return gens;
end);

# Generators of translational hull are the direct product of
# generators of left/right translations semigroup for rectangular bands
# since they are monoids
InstallMethod(GeneratorsOfSemigroup,
"for the translational hull of a rectangular band",
[IsBitranslationsSemigroup],
2,
function(H)
  local S, left_gens, right_gens, l, r, gens;

  S := UnderlyingSemigroup(H);
  if not IsRectangularBand(S) then
    TryNextMethod();
  fi;

  left_gens  := GeneratorsOfSemigroup(LeftTranslations(S));
  right_gens := GeneratorsOfSemigroup(RightTranslations(S));
  gens      := [];

  for l in left_gens do
    for r in right_gens do
      Add(gens, BitranslationNC(H, l, r));
    od;
  od;

  return gens;
end);

#############################################################################
# 4. Methods for monoids
#############################################################################

InstallMethod(GeneratorsOfSemigroup,
"for the left translations of a finite monoid",
[IsLeftTranslationsSemigroup and IsWholeFamily],
function(L)
  if not IsMonoid(UnderlyingSemigroup(L)) then
    TryNextMethod();
  fi;
  return GeneratorsOfSemigroup(InnerLeftTranslations(UnderlyingSemigroup(L)));
end);

InstallMethod(GeneratorsOfSemigroup,
"for the right translations of a finite monoid",
[IsRightTranslationsSemigroup and IsWholeFamily],
function(R)
  if not IsMonoid(UnderlyingSemigroup(R)) then
    TryNextMethod();
  fi;
  return GeneratorsOfSemigroup(InnerRightTranslations(UnderlyingSemigroup(R)));
end);

InstallMethod(GeneratorsOfSemigroup,
"for the translational hull of a finite monoid",
[IsBitranslationsSemigroup and IsWholeFamily],
function(H)
  if not IsMonoid(UnderlyingSemigroup(H)) then
    TryNextMethod();
  fi;
  return GeneratorsOfSemigroup(InnerTranslationalHull(UnderlyingSemigroup(H)));
end);

InstallMethod(Size,
"for a semigroup of left/right translations of a monoid",
[IsTranslationsSemigroup and IsWholeFamily],
1,
function(T)
  if not IsMonoid(UnderlyingSemigroup(T)) then
    TryNextMethod();
  fi;
  return Size(UnderlyingSemigroup(T));
end);

InstallMethod(Size, "for a translational hull of a monoid",
[IsBitranslationsSemigroup and IsWholeFamily],
1,
function(H)
  if not IsMonoid(UnderlyingSemigroup(H)) then
    TryNextMethod();
  fi;
  return Size(UnderlyingSemigroup(H));
end);

#############################################################################
# 5. Methods for monogenic semigroups
#############################################################################

InstallMethod(GeneratorsOfSemigroup,
"for the left translations of a finite monogenic semigroup",
[IsLeftTranslationsSemigroup and IsWholeFamily],
function(L)
  if not IsMonogenicSemigroup(UnderlyingSemigroup(L)) then
    TryNextMethod();
  fi;
  return Union([One(L)],
     GeneratorsOfSemigroup(InnerLeftTranslations(UnderlyingSemigroup(L))));
end);

InstallMethod(GeneratorsOfSemigroup,
"for the right translations of a finite monogenic semigroup",
[IsRightTranslationsSemigroup and IsWholeFamily],
function(R)
  if not IsMonogenicSemigroup(UnderlyingSemigroup(R)) then
    TryNextMethod();
  fi;
  return Union([One(R)],
     GeneratorsOfSemigroup(InnerRightTranslations(UnderlyingSemigroup(R))));
end);

InstallMethod(GeneratorsOfSemigroup,
"for the translational hull of a finite monogenic semigroup",
[IsBitranslationsSemigroup and IsWholeFamily],
function(H)
  if not IsMonogenicSemigroup(UnderlyingSemigroup(H)) then
    TryNextMethod();
  fi;
  return Union([One(H)],
     GeneratorsOfSemigroup(InnerTranslationalHull(UnderlyingSemigroup(H))));
end);

InstallMethod(Size,
"for a semigroup of left/right translations of a monogenic semigroup",
[IsTranslationsSemigroup and IsWholeFamily],
1,
function(T)
  if not IsMonogenicSemigroup(UnderlyingSemigroup(T)) then
    TryNextMethod();
  fi;
  return Size(UnderlyingSemigroup(T));
end);

InstallMethod(Size, "for a translational hull of a monogenic semigroup",
[IsBitranslationsSemigroup and IsWholeFamily],
1,
function(H)
  if not IsMonogenicSemigroup(UnderlyingSemigroup(H)) then
    TryNextMethod();
  fi;
  return Size(UnderlyingSemigroup(H));
end);

#############################################################################
# 6. Technical methods
#############################################################################

InstallMethod(UnderlyingRepresentatives,
"for a semigroup of left or right translations",
[IsTranslationsSemigroup],
function(T)
  local S, L, G;

  S := UnderlyingSemigroup(T);
  L := IsLeftTranslationsSemigroup(T);

  if SEMIGROUPS.IsNormalRMSOverGroup(S) then
    G := UnderlyingSemigroup(S);
    if L then
      return List(Rows(S), i -> RMSElement(S, i, One(G), 1));
    else
      return List(Columns(S), j -> RMSElement(S, 1, One(G), j));
    fi;
  fi;

  if IsLeftTranslationsSemigroup(T) then
    return List(MaximalRClasses(S), Representative);
  else
    return List(MaximalLClasses(S), Representative);
  fi;
end);

InstallMethod(RepresentativeMultipliers,
"for a semigroup of left translation",
[IsTranslationsSemigroup],
function(T)
  local S, reps, M, out, x, i, j;

  S    := UnderlyingSemigroup(T);
  reps := UnderlyingRepresentatives(T);

  if IsLeftTranslationsSemigroup(T) then
    M := MultiplicationTableWithCanonicalPositions(S);
  else
    M := TransposedMultiplicationTableWithCanonicalPositions(S);
  fi;

  out  := ListWithIdenticalEntries(Length(M), 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
        # store [i, j] instead of [x, j] for efficiency
        out[M[x][j]] := [i, j];
      fi;
    od;
    out[x] := [i, 0];
  od;
  return out;
end);

InstallMethod(AsList, "for a semigroup of left or right translations",
[IsTranslationsSemigroup and IsWholeFamily],
function(T)
  # Just use the AsList for semigroups if generators are known
  if SEMIGROUPS.HasEasyTranslationsGenerators(T) then
    TryNextMethod();
  elif IsLeftTranslationsSemigroup(T) then
    return SEMIGROUPS.LeftTranslationsBacktrack(T);
  else
    return SEMIGROUPS.RightTranslationsBacktrack(T);
  fi;
end);

InstallMethod(AsList, "for a translational hull",
[IsBitranslationsSemigroup and IsWholeFamily],
function(H)
  local S;

  S := UnderlyingSemigroup(H);
  if SEMIGROUPS.HasEasyBitranslationsGenerators(H) then
    TryNextMethod();
  elif IsReesZeroMatrixSemigroup(S) and IsZeroSimpleSemigroup(S) then
    return SEMIGROUPS.BitranslationsRZMS(H);
  elif SEMIGROUPS.IsNormalRMSOverGroup(S) then
    return SEMIGROUPS.BitranslationsNormalRMS(H);
  else
    return SEMIGROUPS.BitranslationsBacktrack(H);
  fi;
end);

InstallMethod(Size, "for a semigroups of left or right translations",
[IsTranslationsSemigroup and IsWholeFamily],
T -> Size(AsList(T)));

InstallMethod(Size, "for a translational hull",
[IsBitranslationsSemigroup and IsWholeFamily],
H -> Size(AsList(H)));

InstallMethod(NrLeftTranslations, "for a semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local L, out;

  L := LeftTranslations(S);
  if SEMIGROUPS.HasEasyTranslationsGenerators(L) then
    return Size(L);  # this is probably more efficient
  fi;

  out := SEMIGROUPS.LeftTranslationsBacktrack(L, "nr_only");
  SetSize(L, out);
  return out;
end);

InstallMethod(NrRightTranslations, "for a semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local R, out;

  R := RightTranslations(S);
  if SEMIGROUPS.HasEasyTranslationsGenerators(R) then
    return Size(R);  # this is probably more efficient
  fi;

  out := SEMIGROUPS.RightTranslationsBacktrack(R, "nr_only");
  SetSize(R, out);
  return out;
end);

# TODO (later): avoid reproducing the logic in AsList
InstallMethod(NrBitranslations, "for a semigroup",
[IsSemigroup and CanUseFroidurePin and IsFinite],
function(S)
  local H, out;

  H := TranslationalHull(S);
  if SEMIGROUPS.HasEasyBitranslationsGenerators(H) then
    return Size(H);  # this is probably more efficient
  elif IsReesZeroMatrixSemigroup(S) and IsZeroSimpleSemigroup(S) then
    out := SEMIGROUPS.BitranslationsRZMS(H, "nr_only");
  elif SEMIGROUPS.IsNormalRMSOverGroup(S) then
    out := SEMIGROUPS.BitranslationsNormalRMS(H, "nr_only");
  else
    out := SEMIGROUPS.BitranslationsBacktrack(H, "nr_only");
  fi;

  SetSize(H, out);
  return out;
end);

InstallMethod(Representative, "for a semigroup of left or right translations",
[IsTranslationsSemigroup and IsWholeFamily],
function(T)
  local S;
  S := UnderlyingSemigroup(T);
  if IsLeftTranslationsSemigroup(T) then
    return LeftTranslation(T, MappingByFunction(S, S, x -> x));
  else
    return RightTranslation(T, MappingByFunction(S, S, x -> x));
  fi;
end);

InstallMethod(Representative, "for a translational hull",
[IsBitranslationsSemigroup and IsWholeFamily],
function(H)
  local L, R, S;
  S := UnderlyingSemigroup(H);
  L := LeftTranslations(S);
  R := RightTranslations(S);
  return Bitranslation(H, Representative(L), Representative(R));
end);

InstallMethod(ViewObj, "for a semigroup of left or right translations",
[IsTranslationsSemigroup and IsWholeFamily],
function(T)
  Print("<the semigroup of ");
  if IsLeftTranslationsSemigroup(T) then Print("left ");
    else Print("right ");
  fi;
  Print("translations of ", ViewString(UnderlyingSemigroup(T)), ">");
end);

# TODO: not supposed to do this
InstallMethod(ViewObj, "for a semigroup of translations",
[IsTranslationsSemigroup], PrintObj);

InstallMethod(PrintObj, "for a semigroup of translations",
[IsTranslationsSemigroup],
function(T)
  if IsLeftTranslationsSemigroup(T) then
    Print("<left ");
  else
    Print("<right ");
  fi;
  Print("translations semigroup over ",
        ViewString(UnderlyingSemigroup(T)),
        ">");
end);

InstallMethod(ViewObj, "for a translation",
[IsSemigroupTranslation], PrintObj);

InstallMethod(PrintObj, "for a translation",
[IsSemigroupTranslation],
function(t)
  local L, S;
  L := IsLeftTranslation(t);
  if L then
    S := UnderlyingSemigroup(LeftTranslationsSemigroupOfFamily(FamilyObj(t)));
    Print("<left ");
  else
    S := UnderlyingSemigroup(RightTranslationsSemigroupOfFamily(FamilyObj(t)));
    Print("<right ");
  fi;

  Print("translation on ", ViewString(S), ">");
end);

InstallMethod(ViewObj, "for a translational hull",
[IsBitranslationsSemigroup], PrintObj);

InstallMethod(PrintObj, "for a translational hull",
[IsBitranslationsSemigroup and IsWholeFamily],
function(H)
  Print("<translational hull over ", ViewString(UnderlyingSemigroup(H)), ">");
end);

InstallMethod(PrintObj, "for a subsemigroup of a translational hull",
[IsBitranslationsSemigroup],
function(H)
  Print("<semigroup of bitranslations over ",
        ViewString(UnderlyingSemigroup(H)), ">");
end);

InstallMethod(ViewObj, "for a bitranslation",
[IsBitranslation], PrintObj);

InstallMethod(PrintObj, "for a bitranslation",
[IsBitranslation],
function(t)
  local H;
  H := TranslationalHullOfFamily(FamilyObj(t));
  Print("<bitranslation on ", ViewString(UnderlyingSemigroup(H)), ">");
end);

# Note the order of multiplication
InstallMethod(\*, "for left translations of a semigroup",
IsIdenticalObj,
[IsLeftTranslation, IsLeftTranslation],
function(x, y)
  local L, S, prod, i;
  L := LeftTranslationsSemigroupOfFamily(FamilyObj(x));
  S := UnderlyingSemigroup(L);
  prod := [];
  for i in [1 .. Size(UnderlyingRepresentatives(L))] do
    prod[i] := PositionCanonical(S, EnumeratorCanonical(S)[y![1][i]] ^ x);
  od;
  return Objectify(FamilyObj(x)!.type, [prod]);
end);

InstallMethod(\=, "for left translations of a semigroup",
IsIdenticalObj, [IsLeftTranslation, IsLeftTranslation],
{x, y} -> x![1] = y![1]);

InstallMethod(\<, "for left translations of a semigroup",
IsIdenticalObj, [IsLeftTranslation, IsLeftTranslation],
{x, y} -> x![1] < y![1]);

# Different order of multiplication
InstallMethod(\*, "for right translations of a semigroup",
IsIdenticalObj,
[IsRightTranslation, IsRightTranslation],
function(x, y)
  local R, S, prod, i;
  R := RightTranslationsSemigroupOfFamily(FamilyObj(x));
  S := UnderlyingSemigroup(R);
  prod := [];
  for i in [1 .. Size(UnderlyingRepresentatives(R))] do
    prod[i] := PositionCanonical(S, EnumeratorCanonical(S)[x![1][i]] ^ y);
  od;
  return Objectify(FamilyObj(x)!.type, [prod]);
end);

InstallMethod(\=, "for right translations of a semigroup",
IsIdenticalObj, [IsRightTranslation, IsRightTranslation],
{x, y} -> x![1] = y![1]);

InstallMethod(\<, "for right translations of a semigroup",
IsIdenticalObj, [IsRightTranslation, IsRightTranslation],
{x, y} -> x![1] < y![1]);

InstallMethod(\^, "for a semigroup element and a translation",
[IsAssociativeElement, IsSemigroupTranslation],
function(x, t)
  local T, S, M, 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;
  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]]];
  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));
    S := UnderlyingSemigroup(T);
  else
    T := RightTranslationsSemigroupOfFamily(FamilyObj(x));
    S := UnderlyingSemigroup(T);
  fi;
  enum := EnumeratorCanonical(S);
  return Set(List(SEMIGROUPS.ImagePositionsOfTranslation(x), i -> enum[i]));
end);

InstallMethod(\*, "for bitranslations",
IsIdenticalObj, [IsBitranslation, IsBitranslation],
{x, y} -> Objectify(FamilyObj(x)!.type, [x![1] * y![1], x![2] * y![2]]));

InstallMethod(\=, "for bitranslations",
IsIdenticalObj, [IsBitranslation, IsBitranslation],
{x, y} -> x![1] = y![1] and x![2] = y![2]);

InstallMethod(\<, "for bitranslations", IsIdenticalObj,
[IsBitranslation, IsBitranslation],
{x, y} -> x![1] < y![1] or (x![1] = y![1] and x![2] < y![2]));

InstallMethod(UnderlyingSemigroup,
"for a semigroup of left or right translations",
[IsTranslationsSemigroup],
function(T)
  if IsLeftTranslationsSemigroup(T) then
    return UnderlyingSemigroup(LeftTranslationsSemigroupOfFamily(
                                                                ElementsFamily(
                                                                FamilyObj(T))));
  else
    return UnderlyingSemigroup(RightTranslationsSemigroupOfFamily(
                                                                ElementsFamily(
                                                                FamilyObj(T))));
  fi;
end);

InstallMethod(UnderlyingSemigroup,
"for a subsemigroup of the translational hull",
[IsBitranslationsSemigroup],
function(H)
    return UnderlyingSemigroup(TranslationalHullOfFamily(ElementsFamily(
                                                        FamilyObj(H))));
end);

InstallMethod(ChooseHashFunction, "for a left or right translation and int",
[IsSemigroupTranslation, IsInt],
function(_, hashlen)
  return rec(func := SEMIGROUPS.HashFunctionForTranslations,
             data := hashlen);
end);

InstallMethod(ChooseHashFunction, "for a bitranslation and int",
[IsBitranslation, IsInt],
function(_, hashlen)
  return rec(func := SEMIGROUPS.HashFunctionForBitranslations,
             data := hashlen);
end);

InstallMethod(OneOp, "for a translational hull",
[IsBitranslation],
function(h)
  local H, L, R, S, l, r;
  H := TranslationalHullOfFamily(FamilyObj(h));
  S := UnderlyingSemigroup(H);
  L := LeftTranslations(S);
  R := RightTranslations(S);
  l := LeftTranslation(L, MappingByFunction(S, S, x -> x));
  r := RightTranslation(R, MappingByFunction(S, S, x -> x));
  return Bitranslation(H, l, r);
end);

InstallMethod(OneOp, "for a semigroup of translations",
[IsSemigroupTranslation],
function(t)
  local S, T;
  if IsLeftTranslation(t) then
    T := LeftTranslationsSemigroupOfFamily(FamilyObj(t));
    S := UnderlyingSemigroup(T);
    return LeftTranslation(T, MappingByFunction(S, S, x -> x));
  else
    T := RightTranslationsSemigroupOfFamily(FamilyObj(t));
    S := UnderlyingSemigroup(T);
    return RightTranslation(T, MappingByFunction(S, S, x -> x));
  fi;
end);

InstallGlobalFunction(LeftPartOfBitranslation,
function(h)
  if not IsBitranslation(h) then
     ErrorNoReturn("the argument must be a bitranslation");
  fi;
  return h![1];
end);

InstallGlobalFunction(RightPartOfBitranslation,
function(h)
  if not IsBitranslation(h) then
     ErrorNoReturn("the argument must be a bitranslation");
  fi;
  return h![2];
end);

InstallMethod(IsWholeFamily, "for a collection of translations",
[IsSemigroupTranslationCollection],
function(C)
  local L, S, T, t;

  t := Representative(C);
  L := IsLeftTranslation(t);

  if L then
    T := LeftTranslationsSemigroupOfFamily(FamilyObj(t));
  else
    T := RightTranslationsSemigroupOfFamily(FamilyObj(t));
  fi;

  S := UnderlyingSemigroup(T);

  if not HasSize(T) or
          IsRectangularBand(S) or
          IsSimpleSemigroup(S) or
          IsZeroSimpleSemigroup(S) or
          IsMonoidAsSemigroup(S) then
    TryNextMethod();
  fi;

  return Size(T) = Size(C);
end);

InstallMethod(IsWholeFamily, "for a collection of bitranslations",
[IsBitranslationCollection],
function(C)
  local b, H, S;
  b := Representative(C);
  H := TranslationalHullOfFamily(FamilyObj(b));
  S := UnderlyingSemigroup(H);

  if not HasSize(H) or
          IsRectangularBand(S) or
          IsMonoidAsSemigroup(S) then
    TryNextMethod();
  fi;

  return Size(H) = Size(C);
end);

[ Dauer der Verarbeitung: 0.52 Sekunden  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge