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


Quelle  semiffmat.gi   Sprache: unbekannt

 
#############################################################################
##
##  semigroups/semiffmat.gi
##  Copyright (C) 2015-2022                              James D. Mitchell
##                                                         Markus Pfeiffer
##
##  Licensing information can be found in the README file of this package.
##
#############################################################################
##

# Contents:
# 1. Isomorphisms for semigroups
# 2. Isomorphisms for monoids
# 3. Printing and viewing
# 4. Random
# 5. Methods for acting semigroup setup
# 6. Properties of matrix over finite field semigroups

#############################################################################
# 1. Isomorphisms for semigroups
#############################################################################

# fallback method: via a transformation semigroup

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup and a semigroup",
[IsMatrixOverFiniteFieldSemigroup, IsSemigroup],
SEMIGROUPS.DefaultIsomorphismSemigroup);

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup, a ring, and a semigroup",
[IsMatrixOverFiniteFieldSemigroup, IsRing, IsSemigroup],
function(filt, R, S)
  local iso1, inv1, iso2, inv2;

  if not (IsField(R) and IsFinite(R)) then
    ErrorNoReturn("the 2nd argument (a ring) must be a finite field");
  fi;

  iso1 := IsomorphismTransformationSemigroup(S);
  inv1 := InverseGeneralMapping(iso1);
  iso2 := IsomorphismSemigroup(filt, R, Range(iso1));
  inv2 := InverseGeneralMapping(iso2);

  return SemigroupIsomorphismByFunctionNC(S,
                                          Range(iso2),
                                          x -> (x ^ iso1) ^ iso2,
                                          x -> (x ^ inv2) ^ inv1);
end);

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup and a finite field matrix semigroup",
[IsMatrixOverFiniteFieldSemigroup, IsMatrixOverFiniteFieldSemigroup],
{filt, S} -> SemigroupIsomorphismByFunctionNC(S, S, IdFunc, IdFunc));

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup, ring, and matrix over ff semigroup",
[IsMatrixOverFiniteFieldSemigroup,
 IsRing,
 IsMatrixOverFiniteFieldSemigroup],
function(_, R, S)
  local D, map, inv, T;
  D := BaseDomain(Representative(S));
  if D = R then
    return SemigroupIsomorphismByFunctionNC(S, S, IdFunc, IdFunc);
  elif Size(D) <= Size(R) and IsIdenticalObj(FamilyObj(D), FamilyObj(R))
      and DegreeOverPrimeField(R) mod DegreeOverPrimeField(D) = 0 then
    map := x -> Matrix(R, x);
    inv := x -> Matrix(D, x);
    T   := Semigroup(List(GeneratorsOfSemigroup(S), map));
    return SemigroupIsomorphismByFunctionNC(S, T, map, inv);
  fi;
  TryNextMethod();  # take an isomorphism to a transformation semigroup
end);

# This is for converting semigroups of GAP library matrices over finite fields
# to IsMatrixOverFiniteFieldSemigroup
InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup and a semigroup of matrices over a ff",
[IsMatrixOverFiniteFieldSemigroup,
 IsSemigroup and HasGeneratorsOfSemigroup and IsFFECollCollColl],
function(_, S)
  local R, map, T;
  # The following line is required because of the weirdness in constructor
  # method selection, if the method for IsMatrixOverFiniteFieldSemigroup was
  # after this method, then the next 3 lines wouldn't be required, but at the
  # same time that'd be less robust.
  if IsMatrixOverFiniteFieldSemigroup(S) then
    TryNextMethod();
  fi;
  R := DefaultFieldOfMatrix(Representative(S));
  map := x -> Matrix(R, x);
  T := Semigroup(List(GeneratorsOfSemigroup(S), map));
  return SemigroupIsomorphismByFunctionNC(S, T, map, AsList);
end);

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup, a ring, and a ff mat. semigroup",
[IsMatrixOverFiniteFieldSemigroup,
 IsRing,
 IsSemigroup and HasGeneratorsOfSemigroup and IsFFECollCollColl],
function(_, R, S)
  local D, map, T;
  # The following line is required because of the weirdness in constructor
  # method selection, if the method for IsMatrixOverFiniteFieldSemigroup was
  # after this method, then the next 3 lines wouldn't be required, but at the
  # same time that'd be less robust.
  if IsMatrixOverFiniteFieldSemigroup(S) then
    TryNextMethod();
  fi;
  D := BaseDomain(Representative(S));
  if Size(D) <= Size(R) and IsIdenticalObj(FamilyObj(D), FamilyObj(R))
      and DegreeOverPrimeField(R) mod DegreeOverPrimeField(D) = 0 then
    map := x -> Matrix(R, x);
    T := Semigroup(List(GeneratorsOfSemigroup(S), map));
    return SemigroupIsomorphismByFunctionNC(S, T, map, AsList);
  fi;
  TryNextMethod();
end);

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup and transformation semigroup with gens",
[IsMatrixOverFiniteFieldSemigroup,
 IsTransformationSemigroup and HasGeneratorsOfSemigroup],
 {filt, S} -> IsomorphismSemigroup(IsMatrixOverFiniteFieldSemigroup, GF(2), S));

InstallMethod(IsomorphismSemigroup,
"for IsMatrixOverFiniteFieldSemigroup, a ring, and a transformation semigroup",
[IsMatrixOverFiniteFieldSemigroup,
 IsRing,
 IsTransformationSemigroup and HasGeneratorsOfSemigroup],
function(_, R, S)
  local n, basis, map, iso, inv, gens;

  if not (IsField(R) and IsFinite(R)) then
    ErrorNoReturn("the 2nd argument (a ring) must be a finite field");
  fi;

  n := DegreeOfTransformationSemigroup(S);
  # TODO(later) when GAP allows 0-dimensional matrices and Semigroups requires
  # that version of GAP, then the following if-statement can be removed.
  if n = 0 then
    n := 1;
  fi;
  basis := IdentityMatrix(R, n);
  map := x -> Unpack(basis){ImageListOfTransformation(x, n)};
  iso := x -> Matrix(R, map(x));
  inv := x -> Transformation([1 .. n], i -> PositionNonZero(x[i]));
  gens := List(GeneratorsOfSemigroup(S), iso);

  return SemigroupIsomorphismByFunctionNC(S, Semigroup(gens), iso, inv);
end);

#############################################################################
# 2. Isomorphisms for monoids
#############################################################################

InstallMethod(AsMonoid, "for a matrix over finite field semigroup",
[IsMatrixOverFiniteFieldSemigroup],
function(S)
  if MultiplicativeNeutralElement(S) = fail then
    return fail;  # so that we do the same as the GAP/ref manual says
  fi;
  return Range(IsomorphismMonoid(IsMatrixOverFiniteFieldMonoid, S));
end);

InstallMethod(IsomorphismMonoid,
"for IsMatrixOverFiniteFieldMonoid and a semigroup",
[IsMatrixOverFiniteFieldMonoid, IsSemigroup],
SEMIGROUPS.DefaultIsomorphismMonoid);

InstallMethod(IsomorphismMonoid,
"for IsMatrixOverFiniteFieldMonoid, a ring, and a semigroup",
[IsMatrixOverFiniteFieldMonoid, IsRing, IsSemigroup],
function(filt, R, S)
  local iso1, inv1, iso2, inv2;

  iso1 := IsomorphismTransformationMonoid(S);
  inv1 := InverseGeneralMapping(iso1);
  iso2 := IsomorphismMonoid(filt, R, Range(iso1));
  inv2 := InverseGeneralMapping(iso2);

  return SemigroupIsomorphismByFunctionNC(S,
                                          Range(iso2),
                                          x -> (x ^ iso1) ^ iso2,
                                          x -> (x ^ inv2) ^ inv1);
end);

InstallMethod(IsomorphismMonoid,
"for IsMatrixOverFiniteFieldMonoid and a monoid",
[IsMatrixOverFiniteFieldMonoid, IsMonoid],
{filt, S} -> IsomorphismSemigroup(IsMatrixOverFiniteFieldSemigroup, S));

InstallMethod(IsomorphismMonoid,
"for IsMatrixOverFiniteFieldMonoid, a ring, and a monoid",
[IsMatrixOverFiniteFieldMonoid, IsRing, IsMonoid],
{filt, R, S} -> IsomorphismSemigroup(IsMatrixOverFiniteFieldSemigroup, R, S));

InstallMethod(IsomorphismMonoid,
"for IsMatrixOverFiniteFieldMonoid and a matrix over finite field monoid",
[IsMatrixOverFiniteFieldMonoid, IsMatrixOverFiniteFieldMonoid],
{filt, S} -> SemigroupIsomorphismByFunctionNC(S, S, IdFunc, IdFunc));

InstallMethod(IsomorphismMonoid,
"for IsMatrixOverFiniteFieldMonoid, a ring, and a matrix over ff monoid",
[IsMatrixOverFiniteFieldMonoid, IsRing, IsMatrixOverFiniteFieldMonoid],
{filt, R, S} -> IsomorphismSemigroup(IsMatrixOverFiniteFieldSemigroup, R, S));

#############################################################################
# 3. Viewing and printing
#############################################################################

InstallMethod(SemigroupViewStringSuffix,
"for a matrix over finite field semigroup",
[IsMatrixOverFiniteFieldSemigroup],
function(S)
  local n;
  if UserPreference("semigroups", "ViewObj") <> "semigroups-pkg" then
    TryNextMethod();
  fi;
  n := ViewString(NrRows(Representative(S)));
  return Concatenation("\>\>", n, "x", n, "\< \>matrices\< \>over\< \>",
                       ViewString(BaseDomain(S)), "\<\< ");
end);

InstallMethod(ViewObj, "for a general linear monoid",
[IsGeneralLinearMonoid],
Maximum(RankFilter(IsMonoid and HasGeneratorsOfMonoid),
        RankFilter(IsMatrixOverFiniteFieldSemigroup
                   and HasGeneratorsOfSemigroup))
- RankFilter(IsGeneralLinearMonoid) + 1,
function(S)
  PrintFormatted("<general linear monoid {1}x{1} over {2}>",
                 NrRows(Representative(S)),
                 BaseDomain(S));
end);

InstallMethod(PrintString, "for general linear monoid",
[IsGeneralLinearMonoid],
7,  # to beat the method for monoids with generators
function(M)
  local rep, str;

  rep := Representative(M);
  str := Concatenation("GLM(",
                       String(NrRows(rep)),
                       ", ",
                       String(Characteristic(BaseDomain(M))));
  if Characteristic(BaseDomain(M)) <> 1 then
    Append(str, " ^ ");
    Append(str, String(Log(Size(BaseDomain(M)),
                           Characteristic(BaseDomain(M)))));
  fi;
  Append(str, ")");
  return str;
end);

InstallMethod(PrintObj, "for general linear monoid",
[IsGeneralLinearMonoid],
7,  # to beat the method for monoids with generators
function(M)
  Print(PrintString(M));
end);

#############################################################################
# 4. Random
#############################################################################

InstallMethod(SEMIGROUPS_ProcessRandomArgsCons,
[IsMatrixOverFiniteFieldSemigroup, IsList],
function(_, params)

  if Length(params) < 1 then  # nr gens
    params[1] := Random(1, 20);
  elif not IsPosInt(params[1]) then
    return "the 2nd argument (number of generators) is not a pos int";
  fi;
  if Length(params) < 2 then  # dimension
    params[2] := Random(1, 20);
  elif not IsPosInt(params[2]) then
    return "the 3rd argument (matrix dimension) is not a pos int";
  fi;
  if Length(params) < 3 then  # field
    params[3] := GF(Random(Primes), Random(1, 9));
  elif not IsField(params[3]) or not IsFinite(params[3]) then
    return "the 4th argument is not a finite field";
  fi;
  if Length(params) < 4 then  # ranks
    params[4] := [1 .. params[2]];
  elif not IsList(params[4])
      or not ForAll(params[4], x -> IsPosInt(x) and x <= params[2]) then
    return "the 5th argument (matrix ranks) is not a list of pos ints";
  fi;

  if Length(params) > 4 then
    return "there must be at most 5 arguments";
  fi;

  return params;
end);

InstallMethod(SEMIGROUPS_ProcessRandomArgsCons,
[IsMatrixOverFiniteFieldMonoid, IsList],
{filt, params} ->
SEMIGROUPS_ProcessRandomArgsCons(IsMatrixOverFiniteFieldSemigroup, params));

InstallMethod(RandomSemigroupCons,
"for IsMatrixOverFiniteFieldSemigroup and list",
[IsMatrixOverFiniteFieldSemigroup, IsList],
function(_, params)  # params = [nrgens, dim, field, ranks]
  return Semigroup(List([1 .. params[1]], i -> RandomMatrix(params[3],
                                                            params[2],
                                                            params[4])));
end);

InstallMethod(RandomMonoidCons,
"for IsMatrixOverFiniteFieldMonoid and list",
[IsMatrixOverFiniteFieldMonoid, IsList],
function(_, params)  # params = [nrgens, dim, field, ranks]
  return Monoid(List([1 .. params[1]], i -> RandomMatrix(params[3],
                                                         params[2],
                                                         params[4])));
end);

InstallMethod(RandomInverseSemigroupCons,
"for IsMatrixOverFiniteFieldSemigroup and list",
[IsMatrixOverFiniteFieldSemigroup, IsList],
function(filt, params)
  return AsSemigroup(filt,
                     params[3],
                     RandomInverseSemigroup(IsPartialPermSemigroup,
                                            params[1],
                                            params[2]));
end);

InstallMethod(RandomInverseMonoidCons,
"for IsMatrixOverFiniteFieldMonoid and list",
[IsMatrixOverFiniteFieldMonoid, IsList],
function(filt, params)
    return AsMonoid(filt,
                    params[3],
                    RandomInverseMonoid(IsPartialPermMonoid,
                                        params[1],
                                        params[2]));
end);

InstallMethod(BaseDomain, "for a matrix over finite field semigroup",
[IsMatrixOverFiniteFieldSemigroup], S -> BaseDomain(Representative(S)));

InstallMethod(IsGeneratorsOfInverseSemigroup,
"for an ffe coll coll coll ",
[IsFFECollCollColl],
coll -> IsGeneratorsOfSemigroup(coll) and ForAll(coll, x -> x ^ -1 <> fail));

#############################################################################
# 5. Methods for acting semigroups setup
#############################################################################

InstallGlobalFunction(MatrixOverFiniteFieldRowSpaceRightAction,
function(_, vsp, m)
  local nvsp, deg, i;

  Assert(1, IsRowBasisOverFiniteField(vsp));
  Assert(1, IsMatrixObjOverFiniteField(m));
  Assert(1, Rank(vsp) > 0);

  # This takes care of the token element
  if Rank(vsp) > NrRows(m) then
    return RowSpaceBasis(m);
  else
    nvsp := Unpack(vsp!.rows * m);
  fi;
  TriangulizeMat(nvsp);

  deg := Length(nvsp);
  for i in [deg, deg - 1 .. 1] do
    if IsZero(nvsp[i]) then
      Remove(nvsp, i);
    fi;
  od;

  return NewRowBasisOverFiniteField(IsPlistRowBasisOverFiniteFieldRep,
                                    BaseDomain(vsp),
                                    nvsp);
end);

InstallGlobalFunction(MatrixOverFiniteFieldLocalRightInverse,
function(S, V, mat)
  local n, k, W, se, zv, u, j, i;

  Assert(1, IsMatrixOverFiniteFieldSemigroup(S));
  Assert(1, IsRowBasisOverFiniteField(V));
  Assert(1, IsMatrixObjOverFiniteField(mat));
  Assert(1, NrRows(mat) > 0);
  Assert(1, Rank(V) > 0);

  n := NrRows(mat);
  k := Rank(V);

  W := Unpack(V!.rows * mat);

  for i in [1 .. k] do
    Append(W[i], V!.rows[i]);
  od;
  se := SemiEchelonMat(W);
  # If the matrix does not act injectively on V, then there is no right inverse
  # TODO(later) I think we can now simplify things below
  if Number(se.heads{[1 .. n]}, IsZero) > n - k then
    return fail;
  fi;

  for i in [1 .. Length(se.vectors)] do
    W[i] := ShallowCopy(se.vectors[i]);
  od;

  zv := [1 .. 2 * n] * Zero(BaseDomain(mat));
  for i in [1 .. n - Length(W)] do
    Add(W, ShallowCopy(zv));
  od;

  # add missing heads
  u := One(BaseDomain(mat));
  j := k + 1;
  for i in [1 .. n] do
    if se.heads[i] = 0 then
      W[j][i] := u;
      W[j][n + i] := u;
      j := j + 1;
    fi;
  od;
  TriangulizeMat(W);

  return Matrix(W{[1 .. n]}{[n + 1 .. 2 * n]}, mat);
end);

# Returns an invertible matrix.
# TODO(later): make pretty and efficient (in that order).  In particular the
# setup for the matrix should be much more efficient.
InstallGlobalFunction(MatrixOverFiniteFieldSchutzGrpElement,
function(_, x, y)
  local deg, n, eqs, idx, col, row, res;

  Assert(1, IsMatrixObjOverFiniteField(x));
  Assert(1, IsMatrixObjOverFiniteField(y));

  n := Rank(x);
  deg := NrRows(x);

  eqs := TransposedMatMutable(Concatenation(TransposedMat(x),
                                            TransposedMat(y)));
  TriangulizeMat(eqs);

  idx := [];
  col := 1;
  row := 1;

  while col <= deg do
    while IsZero(eqs[row, col]) and col <= deg do
      col := col + 1;
    od;
    if col <= deg then
      Add(idx, col);
      row := row + 1;
      col := col + 1;
    fi;
  od;
  res := Matrix(BaseDomain(x), eqs{[1 .. n]}{idx + deg});
  Assert(1, res ^ (-1) <> fail);
  return res;
end);

# StabilizerAction
InstallGlobalFunction(MatrixOverFiniteFieldStabilizerAction,
function(_, x, m)
  local n, k, rsp, zv, i;
  Assert(1, IsMatrixObjOverFiniteField(x));
  Assert(1, IsFFECollColl(m));
  Assert(1, not IsZero(x));
  Assert(1, not IsZero(m));

  n := NrRows(m);
  k := Rank(x);
  rsp := ShallowCopy(m * RowSpaceBasis(x)!.rows);

  zv := [1 .. n] * Zero(BaseDomain(x));
  for i in [1 .. n - k] do
    Add(rsp, ShallowCopy(zv));
  od;

  return Matrix(RowSpaceTransformationInv(x) * rsp, x);
end);

# This should be doable in a much more efficient way
InstallGlobalFunction(MatrixOverFiniteFieldLambdaConjugator,
function(_, x, y)
  local xse, h, p, yse, q;
  Assert(1, IsMatrixObjOverFiniteField(x));
  Assert(1, IsMatrixObjOverFiniteField(y));
  xse := SemiEchelonMat(Unpack(x));
  h := Filtered(xse.heads, x -> x <> 0);
  p := One(BaseDomain(x))
       * PermutationMat(SortingPerm(h), Length(h), BaseDomain(x));
  yse := SemiEchelonMat(Unpack(y));
  h := Filtered(yse.heads, x -> x <> 0);
  q := One(BaseDomain(y))
       * PermutationMat(SortingPerm(h), Length(h), BaseDomain(y));
  return p * q ^ (-1);
end);

# Is there a complete direct way of testing whether this idempotent exists
# (without constructing it)?  The method below is already pretty efficient.

InstallGlobalFunction(MatrixOverFiniteFieldIdempotentTester,
function(_, x, y)
  Assert(1, IsPlistRowBasisOverFiniteFieldRep(x));
  Assert(1, IsPlistRowBasisOverFiniteFieldRep(y));
  return MatrixOverFiniteFieldIdempotentCreator(_, x, y) <> fail;
end);

# Attempt to construct an idempotent m with RowSpace(m) = x
# ColumnSpace(m) = y

InstallGlobalFunction(MatrixOverFiniteFieldIdempotentCreator,
function(S, x, y)
  local m, inv;

  Assert(1, IsMatrixOverFiniteFieldSemigroup(S));
  Assert(1, IsRowBasisOverFiniteField(x));
  Assert(1, Rank(x) <> 0);
  Assert(1, IsRowBasisOverFiniteField(y));
  Assert(1, Rank(y) <> 0);
  Assert(1, Length(x!.rows[1]) = Length(y!.rows[1]));

  m := Matrix(BaseDomain(S), TransposedMat(y!.rows) * x!.rows);
  inv := MatrixOverFiniteFieldLocalRightInverse(S, x, m);
  if inv = fail then
    return fail;
  fi;
  return m * inv;
end);

InstallMethod(IsGeneratorsOfSemigroup, "for an ffe coll coll coll",
[IsFFECollCollColl],
function(coll)
  local rep;
  Assert(1, not IsEmpty(coll));
  rep := Representative(coll);
  if IsMatrixObjOverFiniteField(rep) then
    return ForAll(coll, x -> NrRows(x) = NrRows(coll[1])
                             and BaseDomain(x) = BaseDomain(coll[1])
                             and NrRows(x) = NrCols(x));
  fi;
  TryNextMethod();
end);

#############################################################################
# 6. Properties of matrix over finite field semigroups
#############################################################################

# FIXME(later) this method is not correct (although it works as documented)
# This should check whether <S> = GLM of the right dimensions/field

InstallMethod(IsFullMatrixMonoid, "for a semigroup",
[IsSemigroup], ReturnFalse);

[ zur Elbe Produktseite wechseln0.36Quellennavigators  Analyse erneut starten  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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