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


Quelle  pbr.gi   Sprache: unbekannt

 
############################################################################
##
##  elements/pbr.gi
##  Copyright (C) 2015-2022                              Attila Egri-Nagy
##
##  Licensing information can be found in the README file of this package.
##
#############################################################################
##

# This file contains an initial implementation of partitioned binary
# relations (PBRs) as defined in:
#
# Paul Martin and Volodymyr Mazorchuk, Partitioned binary relations,
# Mathematica Scandinavica, v113, n1, p. 30-52, https://arxiv.org/abs/1102.0862

# Internally a PBR is stored as the adjacency list of digraph with
# vertices [1 .. 2 * n] for some n. More precisely if <x> is a PBR, then:
#
#   * <x![1]> is equal to <n>
#
#   * <x![i + 1]> is the vertices adjacent to <i>
#
# The number <n> is the *degree* of <x>.

#############################################################################
# Family and type.
#
# One per degree to avoid lists with pbrs of different degrees
# belonging to IsAssociativeElementCollection.
#############################################################################

BindGlobal("TYPES_PBR", []);
BindGlobal("TYPE_PBR",
function(n)

  if not IsInt(n) or n < 0 then
    ErrorNoReturn("the argument is not a non-negative integer");
  fi;

  n := n + 1;  # since the degree can be 0

  if not IsBound(TYPES_PBR[n]) then
    TYPES_PBR[n] := NewType(NewFamily(Concatenation("PBRFamily",
                                                    String(n - 1)),
                                      IsPBR,
                                      CanEasilySortElements,
                                      CanEasilySortElements),
                            IsPBR and IsPositionalObjectRep);
  fi;

  return TYPES_PBR[n];
end);

#############################################################################
# Pickler
#############################################################################

InstallMethod(IO_Pickle, "for a PBR",
[IsFile, IsPBR],
function(file, x)
  if IO_Write(file, "PABR") = fail then
    return IO_Error;
  fi;
  return IO_Pickle(file, List([1 .. 2 * x![1] + 1], i -> x![i]));
end);

IO_Unpicklers.PABR := function(file)
  local x;
  x := IO_Unpickle(file);
  if x = IO_Error then
    return IO_Error;
  fi;
  return Objectify(TYPE_PBR(x![1]), x);
end;

#############################################################################
# TODO(later) the embeddings from the paper, AsPBR for a pbr (extend or
# restrict),
#############################################################################

InstallMethod(EmptyPBR, "for a pos int", [IsPosInt],
n -> PBRNC(List([1 .. n], y -> []), List([1 .. n], y -> [])));

InstallMethod(IdentityPBR, "for a pos int", [IsPosInt],
n -> PBRNC(List([1 .. n], y -> [-y]), List([1 .. n], y -> [y])));

InstallMethod(UniversalPBR, "for a pos in", [IsPosInt],
function(n)
  local x;
  x := Concatenation([-n .. -1], [1 .. n]);
  return PBRNC(List([1 .. n], y -> x), List([1 .. n], y -> x));
end);

# The following is temporary, with the current definition of
# IsGeneratorsOfInverseSemigroup for a pbr collection, the One of any element
# in the collection does not satisfy IsGeneratorsOfInverseSemigroup, and so it
# cannot be inverted.

InstallMethod(InverseMonoidByGenerators,
[IsPBRCollection],
function(_)
  ErrorNoReturn("not yet implemented");
end);

# See the comment above, this is not really correct.

InstallOtherMethod(InverseMutable, "for a PBR", [IsPBR],
function(x)
  # TODO(later) change IsBlockBijection(AsBipartition(x)) to
  # IsBlockBijectionPBR.
  if IsPartialPermPBR(x) or
      (IsBipartitionPBR(x) and IsBlockBijection(AsBipartition(x))) then
    return Star(x);
  fi;
  return fail;
end);

# See the comment above, this is not really correct.

InstallMethod(IsGeneratorsOfInverseSemigroup, "for a pbr collection",
[IsPBRCollection],
function(coll)
  return ForAll(coll, IsBipartitionPBR)
         and IsGeneratorsOfInverseSemigroup(List(coll, AsBipartition));
end);

InstallMethod(StarOp, "for a pbr", [IsPBR],
function(x)
  local ext;
  ext := ShallowCopy(ExtRepOfObj(x) * -1);
  Apply(ext, ShallowCopy);
  Apply(ext[1], ShallowCopy);
  Apply(ext[2], ShallowCopy);
  return PBR(ext[2], ext[1]);
end);

InstallMethod(DegreeOfPBRCollection, "for a PBR collection",
[IsPBRCollection],
function(coll)
  if IsPBRSemigroup(coll) then
    return DegreeOfPBRSemigroup(coll);
  fi;
  return DegreeOfPBR(coll[1]);
end);

InstallMethod(IsBipartitionPBR, "for a pbr",
[IsPBR],
x -> IsEquivalenceBooleanMat(AsBooleanMat(x)));

InstallMethod(IsTransformationPBR, "for a pbr",
[IsPBR],
function(x)
  local n, i;

  n := x![1];
  for i in [2 .. n + 1] do
    if Length(x![i]) <> 1 or x![i][1] <= n
        or not i - 1 in x![x![i][1] + 1] then
      return false;
    fi;
  od;
  for i in [n + 2 .. 2 * n + 1] do
    if not ForAll(x![i], j -> j <= n and x![j + 1][1] = i - 1) then
      return false;
    fi;
  od;

  return true;
end);

InstallMethod(IsBlockBijectionPBR, "for a pbr",
[IsPBR],
x -> IsBipartitionPBR(x) and IsBlockBijection(AsBipartition(x)));

InstallMethod(IsPartialPermPBR, "for a pbr",
[IsPBR],
x -> IsBipartitionPBR(x) and IsPartialPermBipartition(AsBipartition(x)));

InstallMethod(IsPermPBR, "for a pbr",
[IsPBR],
x -> IsBipartitionPBR(x) and IsPermBipartition(AsBipartition(x)));

InstallMethod(IsDualTransformationPBR, "for a pbr",
[IsPBR],
x -> IsBipartitionPBR(x) and IsDualTransBipartition(AsBipartition(x)));

InstallMethod(NumberPBR, "for a pbr",
[IsPBR],
x -> NumberBooleanMat(AsBooleanMat(x)));

InstallMethod(PBRNumber, "for pos int and pos int",
[IsPosInt, IsPosInt],
{nr, deg} -> AsPBR(BooleanMatNumber(nr, 2 * deg)));

InstallMethod(IsEmptyPBR, "for a partition binary relation",
[IsPBR],
function(x)
  local n, i;

  n := x![1];
  for i in [2 .. 2 * n + 1] do
    if Length(x![i]) > 0 then
      return false;
    fi;
  od;
  return true;
end);

InstallMethod(IsIdentityPBR, "for a partition binary relation",
[IsPBR],
function(x)
  local n, i;

  n := x![1];
  for i in [2 .. n + 1] do
    if Length(x![i]) <> 1 or x![i][1] <> i + n - 1 then
      return false;
    fi;
  od;
  for i in [n + 2 .. 2 * n + 1] do
    if Length(x![i]) <> 1 or x![i][1] <> i - n - 1 then
      return false;
    fi;
  od;
  return true;
end);

InstallMethod(IsUniversalPBR, "for a partition binary relation",
[IsPBR],
function(x)
  local n, i;

  n := x![1];
  for i in [2 .. 2 * n + 1] do
    if Length(x![i]) < 2 * n then
      return false;
    fi;
  od;
  return true;
end);

InstallMethod(AsPBR, "for a partial perm and pos int",
[IsPartialPerm, IsPosInt],
function(x, deg)
  local left, right, j, i;

  left  := List([1 .. deg], x -> []);
  right := List([1 .. deg], x -> []);

  for i in [1 .. deg] do
    j := i ^ x;
    if j <= deg and j <> 0 then
      Add(left[i], -j);
      Add(right[j], i);
    fi;
  od;

  return PBR(left, right);
end);

InstallMethod(AsPBR, "for a partial perm", [IsPartialPerm],
x -> AsPBR(x, Maximum(DegreeOfPartialPerm(x), CoDegreeOfPartialPerm(x))));

InstallMethod(AsPBR, "for a transformation and pos int",
[IsTransformation, IsPosInt],
function(x, deg)
  local left, right, i;

  left  := List([1 .. deg], x -> []);
  right := List([1 .. deg], x -> []);

  for i in [1 .. deg] do
    Add(left[i], -(i ^ x));
    Add(right[i ^ x], i);
  od;

  return PBR(left, right);
end);

InstallMethod(AsPBR, "for a transformation", [IsTransformation],
x -> AsPBR(x, DegreeOfTransformation(x)));

InstallMethod(AsPBR, "for a multiplicative element",
[IsMultiplicativeElement], x -> AsPBR(AsBipartition(x)));

InstallMethod(AsPBR, "for a multiplicative element and pos int",
[IsMultiplicativeElement, IsPosInt], {x, n} -> AsPBR(AsBipartition(x, n)));

# TODO(later) The following doesn't define a monoid embedding of P_n into
# PBR_n. What is a monoid embedding from P_n to PBR_n?

InstallMethod(AsPBR, "for a bipartition",
[IsBipartition], x -> AsPBR(x, DegreeOfBipartition(x)));

InstallMethod(AsPBR, "for a bipartition and pos int",
[IsBipartition, IsPosInt],
function(x, n)
  local deg, blocks, out, dom, block, i;

  deg    := DegreeOfBipartition(x);
  blocks := ExtRepOfObj(x);
  out    := [[], []];
  dom := Union([-n .. -1], [1 .. n]);

  for block in blocks do
    for i in block do
      if AbsInt(i) <= n then
        if i < 0 then
          out[2][-i] := Intersection(block, dom);
        else
          out[1][i] := Intersection(block, dom);
        fi;
      fi;
    od;
  od;
  for i in [deg + 1 .. n] do
    Add(out[1], []);
    Add(out[2], []);
  od;

  return PBRNC(out[1], out[2]);
end);

InstallMethod(AsPBR, "for a boolean matrix", [IsBooleanMat],
function(x)
  local dim, succ;

  dim := DimensionOfMatrixOverSemiring(x);
  if not IsEvenInt(dim) then
    ErrorNoReturn("the 1st argument (a boolean matrix)is not of ",
                  "even dimension");
  fi;
  succ := Successors(x);
  return PBRNC(succ{[1 .. dim / 2]}, succ{[dim / 2 + 1 .. dim]});
end);

InstallMethod(AsPBR, "for a boolean mat and pos int",
[IsBooleanMat, IsPosInt],
function(mat, n)
  local m, nbs, k, i, j;

  if not IsEvenInt(n) then
    ErrorNoReturn("the 2nd argument (a pos. int) is not even");
  fi;

  m := DimensionOfMatrixOverSemiring(mat);

  if not IsEvenInt(m) then
    ErrorNoReturn("the 1st argument (a boolean matrix) ",
                  "does not have even dimension");
  fi;

  nbs := [List([1 .. n / 2], x -> []),
          List([1 .. n / 2], x -> [])];

  if n <= m then
    for i in [1 .. n / 2] do
      for j in [1 .. n] do
        if mat[i][j] then
          Add(nbs[1][i], j);
        fi;
      od;
    od;
    for i in [n / 2 + 1 .. n] do
      for j in [1 .. n] do
        if mat[i][j] then
          Add(nbs[2][i - n / 2], j);
        fi;
      od;
    od;
  else
    k := (n - m) / 2;

    for i in [1 .. m / 2] do
      for j in [1 .. m / 2] do
        if mat[i][j] then
          Add(nbs[1][i], j);
        fi;
      od;
      for j in [m / 2 + 1 .. m] do
        if mat[i][j] then
          Add(nbs[1][i], j + k);
        fi;
      od;
    od;
    for i in [m / 2 + 1 .. m] do
      for j in [1 .. m / 2] do
        if mat[i][j] then
          Add(nbs[2][i - m / 2], j);
        fi;
      od;
      for j in [m / 2 + 1 .. m] do
        if mat[i][j] then
          Add(nbs[2][i - m / 2], j + k);
        fi;
      od;
    od;
  fi;

  return PBRNC(nbs[1], nbs[2]);
end);

# TODO(later) 2 arg version of this

InstallMethod(AsTransformation, "for a pbr", [IsPBR],
function(x)
  local out, n, i;

  if not IsTransformationPBR(x) then
    ErrorNoReturn("the argument (a pbr) does not define a transformation");
  fi;

  out := [];
  n := x![1];

  for i in [2 .. n + 1] do
    out[i - 1] := x![i][1] - n;
  od;

  return Transformation(out);
end);

# TODO(later) 2 arg version of this

InstallMethod(AsPartialPerm, "for a pbr", [IsPBR],
function(x)
  if not IsPartialPermPBR(x) then
    ErrorNoReturn("the argument (a pbr) does not define a partial perm");
  fi;
  return AsPartialPerm(AsBipartition(x));
end);

# TODO(later) 2 arg version of this

InstallMethod(AsPermutation, "for a pbr", [IsPBR],
function(x)
  if not IsPermPBR(x) then
    ErrorNoReturn("the argument (a pbr) does not define a permutation");
  fi;
  return AsPermutation(AsBipartition(x));
end);

InstallMethod(RandomPBR, "for a pos int", [IsPosInt],
function(n)
  local digraph;
  digraph := RandomDigraph(2 * n);
  return PBRNC(OutNeighbours(digraph){[1 .. n]},
               OutNeighbours(digraph){[n + 1 .. 2 * n]});
end);

InstallMethod(RandomPBR, "for a pos int", [IsPosInt, IsFloat],
function(n, p)
  local digraph;
  digraph := RandomDigraph(2 * n, p);
  return PBRNC(OutNeighbours(digraph){[1 .. n]},
               OutNeighbours(digraph){[n + 1 .. 2 * n]});
end);

InstallMethod(PBR, "for pair of dense list",
[IsDenseList, IsDenseList],
function(left, right)
  local deg, i;

  if Length(left) <> Length(right) then
    ErrorNoReturn("the arguments (dense lists) do not have equal length");
  fi;

  deg := Length(left);

  for i in [1 .. deg] do
    if not IsHomogeneousList(left[i]) then
      ErrorNoReturn("expected a homogeneous list in position ", i,
                    " of the 1st argument (a dense list)");
    elif not IsHomogeneousList(right[i]) then
      ErrorNoReturn("expected a homogeneous list in position ", i,
                    " of the 2nd argument (a dense list)");
    elif   not ForAll(left[i], j -> IsInt(j) and j <> 0
                                    and j <= deg and j >= -deg)
        or not ForAll(right[i], j -> IsInt(j) and j <> 0
                                     and j <= deg and j >= -deg) then
      # TODO(later) more informative
      ErrorNoReturn("the entries in the arguments are not integers ",
                    "in [", -deg, " .. -1] or [1 .. ", deg, "]");
    fi;
  od;
  return PBRNC(left, right);
end);

InstallGlobalFunction(PBRNC,
function(arg...)
  local left, right, n, i, j;

  arg   := StructuralCopy(arg);
  left  := arg[1];  # things adjacent to positives
  right := arg[2];  # things adjacent to negatives

  n := Length(left);

  for i in [1 .. n] do
    for j in [1 .. Length(left[i])] do
      if left[i][j] < 0 then
        left[i][j] := -left[i][j] + n;
      fi;
    od;
    left[i] := ShallowCopy(left[i]);
    Sort(left[i]);
    for j in [1 .. Length(right[i])] do
      if right[i][j] < 0 then
        right[i][j] := -right[i][j] + n;
      fi;
    od;
    right[i] := ShallowCopy(right[i]);
    Sort(right[i]);
  od;
  MakeImmutable(arg);
  arg := Concatenation([Length(arg[1])], Concatenation(arg));
  return Objectify(TYPE_PBR(arg[1]), arg);
end);

InstallMethod(DegreeOfPBR, "for a pbr",
[IsPBR], pbr -> pbr![1]);

InstallMethod(\*, "for pbrs", IsIdenticalObj,
[IsPBR, IsPBR],
function(x, y)
  local n, out, x_seen, y_seen, empty, x_dfs, y_dfs, tmp, i, j;

  n := x![1];

  out := Concatenation([n], List([1 .. 2 * n], x -> BlistList([1 .. 2 * n],
                                                              [])));

  x_seen := BlistList([1 .. 2 * n], []);
  y_seen := BlistList([1 .. 2 * n], []);
  empty  := BlistList([1 .. 2 * n], []);

  x_dfs := function(i, adj)  # starting in x
    local j;
    if x_seen[i] then
      return;
    fi;
    x_seen[i] := true;
    for j in x![i + 1] do
      if j <= n then
        adj[j] := true;
      else  # j > n
        y_dfs(j - n, adj);
      fi;
    od;
    return;
  end;

  y_dfs := function(i, adj)  # starting in y
    local j;
    if y_seen[i] then
      return;
    fi;
    y_seen[i] := true;
    for j in y![i + 1] do
      if j > n then
        adj[j] := true;
      else  # j <= n
        x_dfs(j + n, adj);
      fi;
    od;
    return;
  end;

  tmp := [];

  for i in [1 .. n] do  # find everything connected to vertex i
    for j in x![i + 1] do
      if j <= n then
        out[i + 1][j] := true;
      elif IsBound(tmp[j]) then
        UNITE_BLIST(out[i + 1], tmp[j]);
      else
        tmp[j] := BlistList([1 .. 2 * n], []);
        IntersectBlist(x_seen, empty);
        IntersectBlist(y_seen, empty);
        x_seen[i] := true;
        y_dfs(j - n, tmp[j]);
        UNITE_BLIST(out[i + 1], tmp[j]);
      fi;
      if SizeBlist(out[i + 1]) = 2 * n then
        break;
      fi;
    od;
  od;

  for i in [n + 1 .. 2 * n] do  # find everything connected to vertex i
    for j in y![i + 1] do
      if j > n then
        out[i + 1][j] := true;
      elif IsBound(tmp[j]) then
        UNITE_BLIST(out[i + 1], tmp[j]);
      else
        tmp[j] := BlistList([1 .. 2 * n], []);
        IntersectBlist(x_seen, empty);
        IntersectBlist(y_seen, empty);
        y_seen[i] := true;
        x_dfs(j + n, tmp[j]);
        UNITE_BLIST(out[i + 1], tmp[j]);
      fi;
      if SizeBlist(out[i + 1]) = 2 * n then
        break;
      fi;
    od;
  od;
  for i in [2 .. 2 * n + 1] do
    out[i] := ListBlist([1 .. 2 * n], out[i]);
  od;
  return Objectify(TYPE_PBR(n), out);
end);

InstallMethod(ExtRepOfObj, "for a pbr",
[IsPBR],
function(x)
  local n, out, i, j, k;

  n := x![1];
  out := [[], []];
  for i in [0, 1] do
    for j in [1 + n * i .. n + n * i] do
      Add(out[i + 1], []);
      for k in x![j + 1] do
        if k > n then
          AddSet(out[i + 1][j - n * i], -(k - n));
        else
          AddSet(out[i + 1][j - n * i], k);
        fi;
      od;
    od;
  od;

  return out;
end);

# These ViewObj and PrintObj methods are here because Print(ext[1]) produces
# nicer output than Print(ViewString(ext[1])). The ViewString and PrintString
# methods are required for use in things like Green's relations.

InstallMethod(ViewObj, "for a pbr", [IsPBR], PrintObj);

InstallMethod(PrintObj, "for a pbr", [IsPBR],
function(x)
  local ext;

  ext := ExtRepOfObj(x);
  Print("\>\>PBR(\>\>", ext[1], "\<\<,");

  if Length(String(ext[1])) > 72 or Length(String(ext[2])) > 72 then
    Print("\n");
  else
    Print(" ");
  fi;

  Print("\>\>", ext[2], "\<\<\<\<)");
end);

InstallMethod(ViewString, "for a pbr", [IsPBR], PrintString);

InstallMethod(PrintString, "for a pbr",
[IsPBR],
function(x)
  local ext, str;

  ext := ExtRepOfObj(x);

  str := Concatenation("\>\>PBR(\>\>", PrintString(ext[1]), "\<\<,");

  if Length(String(ext[1])) > 72 or Length(String(ext[2])) > 72 then
    Append(str, "\n");
  else
    Append(str, " ");
  fi;

  Append(str, "\>\>");
  Append(str, PrintString(ext[2]));
  Append(str, "\<\<\<\<)");

  # print empty lists with two spaces for consistency
  # see https://github.com/gap-system/gap/pull/5418
  return ReplacedString(str, "[ ]", "[  ]");
end);

InstallMethod(String, "for a pbr", [IsPBR],
function(x)
  local ext, str;
  ext := ExtRepOfObj(x);
  str := Concatenation("PBR(", String(ext[1]), ", ", String(ext[2]), ")");
  # print empty lists with two spaces for consistency
  # see https://github.com/gap-system/gap/pull/5418
  return ReplacedString(str, "[ ]", "[  ]");
end);

InstallMethod(\=, "for pbrs", IsIdenticalObj,
[IsPBR, IsPBR],
function(x, y)
  local n, i;

  n := x![1];
  for i in [1 .. 2 * n + 1] do
    if x![i] <> y![i] then
      return false;
    fi;
  od;
  return true;
end);

InstallMethod(\<, "for pbrs", IsIdenticalObj,
[IsPBR, IsPBR],
function(x, y)
  local n, i;

  n := x![1];
  for i in [1 .. 2 * n + 1] do
    if x![i] < y![i] then
      return true;
    elif x![i] > y![i] then
      return false;
    fi;
  od;
  return false;
end);

InstallMethod(OneMutable, "for a pbr",
[IsPBR],
function(x)
  local n, out, i;

  n := x![1];
  out := [n];
  for i in [1 .. n] do
    out[i + 1] := [i + n];
    out[i + n + 1] := [i];
  od;
  return Objectify(TYPE_PBR(n), out);
end);

[ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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