Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/images/gap/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 27.7.2024 mit Größe 19 kB image not shown  

Quelle  smallestImage.gi   Sprache: unbekannt

 
#############################################################################
##
#W  files.gi                   images Package                  Chris Jefferson
##
##  Installation file for SmallestImage.
##
#Y  Copyright (C) 2014      University of St. Andrews, North Haugh,
#Y                          St. Andrews, Fife KY16 9SS, Scotland
##

# In practice there is one interesting function here --
# smallest image for sets, which is defined in nsi.g. Everything
# else is transformed into a problem on sets, and then solved.

# Copied from Ferret (where it is called _FerretHelperFuncs)
_ImageHelperFuncs := MakeImmutable(rec(

  # Simple helper to support optional arguments
  optArg := function(Val, default)
    if Length(Val) = 0 then
      return default;
    fi;
    if Length(Val) = 1 then
      return Val[1];
    fi;
    ErrorNoReturn("Only one optional argument!");
  end,

# Copies 'useroptions' over values of 'options' with the same name.
fillUserValues := function(options, useroptions)
  local name, ret;
  ret := rec();
  
  useroptions := ShallowCopy(useroptions);

  for name in RecNames(options) do
    if IsBound(useroptions.(name)) then
      ret.(name) := useroptions.(name);
      Unbind(useroptions.(name));
    else
      ret.(name) := options.(name);
    fi;
  od;

  if useroptions <> rec() then
    Error("Unknown options: ", useroptions);
  fi;

  return ret;
 end));

# Creates the group on a 2D matrix of x*x points
# Which is generated by swapping
# columns i&j and rows i&j simultaneously.
_rowColGen := function( inGroup, x )
  local i,j,l,p, generators, temp;
  
  if IsTrivial(inGroup) then
     return inGroup;
  fi;
  
  generators := [];
  for p in GeneratorsOfGroup(inGroup) do
    l := [];
    for i in [1..x] do
      for j in [1..x] do
        l[i+ (j-1)*x] := i^p + (j^p - 1)*x;
      od;
    od;

    Add(generators, PermList(l));
  od;

  return Group(generators,());
end;

_minOrbBuilder := function(select)
    local fixedPoints, Func;
    fixedPoints := function ( pts, gens )
        return Filtered( pts, x -> ForAll( gens, y -> (x^y=x) ) );
    end;

    Func := function( G )
        local vals,fp, order, branch;
        if LargestMovedPoint(G) = 0 then
            return ();
        fi;
        vals := Set([1..LargestMovedPoint(G)]);
        order := [];
        while vals <> [] do
            branch := select(G, vals);
            G := Stabilizer(G, branch);
            SubtractSet(vals, [branch]);
            Add(order, branch);
        od;
        return PermList(order)^-1;
    end;

    return Func;
end;



InstallMethod(MinOrbitPerm, [IsPermGroup],
    _minOrbBuilder(
        function(G, vals)
            local orbs, o, smallOrbSize, first;
            orbs := Orbits(G, vals);
            orbs := List(orbs, Set);
            orbs := Set(orbs);
            smallOrbSize := Minimum(List(orbs, Size));
            first := First(orbs, x -> Size(x) = smallOrbSize);
            return first[1];
        end
));

InstallMethod(MaxOrbitPerm, [IsPermGroup],
    _minOrbBuilder(
        function(G, vals)
            local orbs, o, largeOrbSize, first;
            orbs := Orbits(G, vals);
            orbs := List(orbs, Set);
            orbs := Set(orbs);
            largeOrbSize := Maximum(List(orbs, Size));
            first := First(orbs, x -> Size(x) = largeOrbSize);
            return first[1];
        end
));
  
# Install the two most common cases of rowColGen
# as an attribute
InstallMethod(rowcolsquareGroup, [IsPermGroup],
function( inGroup )
  return _rowColGen(inGroup, LargestMovedPoint(inGroup));
end);

# Install the two most common cases of rowColGen
# as an attribute
InstallMethod(rowcolsquareGroup2, [IsPermGroup],
function( inGroup )
  return _rowColGen(inGroup, LargestMovedPoint(inGroup) + 1);
end);


_booleaniseList := function(l, matrixMax)
  local set, i;
  set := [];
  for i in [1..Length(l)] do
      Add(set, (i-1)*matrixMax + l[i]);
  od;
  return set;
end;

_unbooleaniseList := function(s, matrixMax)
  local lresult, img, dom, i;
  lresult := [];
  # Turn back into a partial function
  # we only feed in those values which we generated.
  for i in [1..Length(s)] do
    img := (s[i] - 1) mod matrixMax + 1;
    dom := (s[i] - img)/matrixMax + 1;
    lresult[dom] := img;
  od;

  return lresult;
end;

_CanonicalSetImage := function(G, S, stab, settings)
    local L, earlyskip;
    
    if settings.result = GetBool then
        earlyskip := true;
    else
        earlyskip := false;
    fi;
    
    L := _NewSmallestImage(G, S, stab, x -> x, [earlyskip, S], settings.disableStabilizerCheck, settings.order );
    
    if settings.getStab then
        settings.original.stab := L[2];
    fi;

    if L[1] = false then
        return false;
    fi;
    
    if settings.result = GetImage then
        return L[1];
    fi;
    
    if settings.result = GetBool then
        if L[1] = MinImage.Smaller or L[1] = MinImage.Larger then
            return false;
        else
            return Set(L[1]) = Set(S);
        fi;
    fi;
    
    if settings.result = GetPerm then
        return RepresentativeAction(G, S, L[1], OnTuples);
    fi;
    
    Error("Invalid value of result");
end;


InstallGlobalFunction("IsMinimalImageLessThan", 
    function(G, A, B, extra...)
        local ret;
        B := Set(B);
        if Length(extra) <> 1 or extra[1] <> OnSets then
            ErrorNoReturn("IsMinimalImageLessThan only supports 'OnSets' are present");
        fi;
        if Length(A) <> Length(B) then
            ErrorNoReturn("IsMinimalImageLessThan only supports equal sized sets are present");
        fi;
        ret := _NewSmallestImage(G, A, Stabilizer(G, A, OnSets), x -> x, [true, Set(B)], false, CanonicalConfig_Minimum);
        if ret[1] = MinImage.Smaller or ret[1] = MinImage.Larger then
            return ret[1];
        fi;
        ret[1] := Set(ret[1]);
        if ret[1] < B then
            return MinImage.Smaller;
        elif ret[1] > B then
            return MinImage.Larger;
        else
            return MinImage.Equal;
        fi;
end);

_CanonicalSetSetImage := function(G, S, stab, stepval, settings)
    local L;
    
    L := _NewSmallestImage_SetSet(G, S, stab, x -> x, stepval );
    
    if settings.result = GetImage then
        return L[1];
    fi;
    
    if settings.result = GetBool then
        return Set(L[1]) = Set(S);
    fi;
    
    if settings.result = GetPerm then
        return RepresentativeAction(G, S, L[1], OnTuples);
    fi;
    
    Error("Invalid value of result");
end;

_CanonicalTupleSetImage := function(G, origS, settings)
    local i, stab, curperm, curset, L, perm, S, Slen;
    curperm := ();
    if settings.order <> CanonicalConfig_Minimum then
        S := Filtered(origS, x -> Length(x) > 0);
        Slen := List(S, Length);
        SortParallel(Slen, S);
    else
        S := origS;
    fi;
    
    for i in [1..Length(S)] do
        curset := OnSets(S[i], curperm);
        stab := Stabilizer(G, curset, OnSets);
        L := _NewSmallestImage(G, curset, stab, x->x, [false], settings.disableStabilizerCheck, settings.order );
        perm := RepresentativeAction(G, curset, L[1], OnTuples);
        curperm := curperm * perm;
        G := stab^perm;
    od;

    if settings.result = GetImage then
        return OnTuplesSets(origS, curperm);
    fi;

    if settings.result = GetBool then
        return OnTuplesSets(origS, curperm) = origS;
    fi;

    if settings.result = GetPerm then
        return curperm;
    fi;
end;






_MinimalImage_partialFunction := function(l, G, mMax, settings)
  local lresult, set, i, image, imageset, rowcolGroup,
        stab, img, dom, perm;
  
  # Turn partial function into a subset of a 2D matrix,
  # which contains (i,j) if i^trans = j.
  set := _booleaniseList(l, mMax);

  # Cache only the most common group
  if mMax = LargestMovedPoint(G) then
    rowcolGroup := rowcolsquareGroup(G);
  elif mMax = LargestMovedPoint(G) + 1 then
    rowcolGroup := rowcolsquareGroup2(G);
  else
    rowcolGroup := _rowColGen(G, mMax);
  fi;
  
  if settings.stabilizer <> fail then
     stab := _rowColGen(settings.stabilizer, mMax);
  else
      # Find minimal image of set
      stab := Stabilizer(rowcolGroup, set, OnSets);
  fi;
  
  image := _CanonicalSetImage(rowcolGroup, set, stab, settings);
  
  if settings.result = GetBool then
      return image;
  elif settings.result = GetImage then
      return _unbooleaniseList(image, mMax);
  elif settings.result = GetPerm then
      # This horrible equation picks out the row permutation from our matrix
      perm := List([1..mMax], 
                   x -> ((((mMax+1)*x-mMax)^image)+mMax)/(mMax+1));
      return PermList(perm);
  fi;
  
end;

# This function just encapsulates what we have to return in the case
# of a trivial input case (usually, group is the identity)
_trivialReturn := function(object, result)
    if result = GetBool then
        return true;
    elif result = GetPerm then
        return ();
    elif result = GetImage then
        return object;
    else
        Error("Bad 'result' argument");
    fi;
end;

        
    
# Returns the minimum image of a transformation
InstallMethod(CanonicalImageOp, [IsPermGroup, IsTransformation, IsFunction, IsObject],
function(inGroup, trans, action, settings)
  local l, lresult, set, stab, imageperm, imageset, retset,
        transformMax, matrixMax, rowcolGroup, dom, img, i;

  if action <> OnPoints then
    Error("Can only act on transformations with OnPoints");
  fi;
  
  # Return in trivial cases
  if Maximum(LargestMovedPoint(trans),LargestImageOfMovedPoint(trans)) = 0 or
     LargestMovedPoint(inGroup) = 0 then
      return _trivialReturn(trans, settings.result);
  fi;

  # First find the largest integer of interest
  transformMax := Maximum(LargestImageOfMovedPoint(trans),
                          LargestMovedPoint(trans));

  # TODO: This could be reduced but not all the way down to
  # LargestMovedPoint(inGroup) in general.
  matrixMax := Maximum(transformMax, LargestMovedPoint(inGroup));

  # Turn transformation into function and pass to general case
  l := ListTransformation(trans, matrixMax);
  lresult := _MinimalImage_partialFunction(l, inGroup, matrixMax, settings);
  
  #Print(":",settings.,":",GetImage,":",settings.image = GetImage,"\n");
  
  if settings.result = GetImage then
      return Transformation(lresult);
  else
      return lresult;
  fi;
  
end);

# Returns the minimum image of a transformation
InstallMethod(CanonicalImageOp, [IsPermGroup, IsPerm, IsFunction, IsObject],
function(inGroup, trans, action, settings)
  local l, lresult, set, stab, imageperm, imageset, retset,
        transformMax, matrixMax, rowcolGroup, dom, img, i;

  if action <> OnPoints then
    Error("Can only act on permutations with OnPoints");
  fi;
  
  # Return in trivial cases
  if LargestMovedPoint(trans) = 0 or LargestMovedPoint(inGroup) = 0 then
      return _trivialReturn(trans, settings.result);
  fi;

  # First find the largest integer of interest
  transformMax := LargestMovedPoint(trans);

  # TODO: This could be reduced but not all the way down to
  # LargestMovedPoint(inGroup) in general.
  matrixMax := Maximum(transformMax, LargestMovedPoint(inGroup));

  # Turn transformation into function and pass to general case
  l := ListPerm(trans, matrixMax);
  lresult := _MinimalImage_partialFunction(l, inGroup, matrixMax, settings);
  
  if settings.result = GetImage then
      return PermList(lresult);
  else
      return lresult;
  fi;
  
end);

InstallMethod(CanonicalImageOp, [IsPermGroup, IsPosInt, IsFunction, IsObject],
        function(inGroup, i, action, settings)
    local min;
    
    min := Minimum(Orbit(inGroup, i, action));
    
    if settings.result = GetImage then
        return min;
    elif settings.result = GetBool then
        return min = i;
    else #GetPerm
        return RepresentativeAction(inGroup, i, min, action);
    fi;
end);

InstallMethod(CanonicalImageOp, [IsPermGroup, IsPartialPerm, IsFunction, IsObject],
function(inGroup, pp, action, settings)
  local dom, max, matrixMax, minTrans, l, lresult, i;

  if action <> OnPoints then
    Error("Can only act on partial perms with OnPoints");
  fi;
  
  # First find the largest integer of interest
  max := Maximum(DegreeOfPartialPerm(pp),
                 CodegreeOfPartialPerm(pp));

  # Return in trivial cases
  if max = 0 then
      return _trivialReturn(pp, settings.result);
  fi;

  matrixMax := Maximum(max, LargestMovedPoint(inGroup)) + 1;
  
  minTrans := CanonicalImage(inGroup, AsTransformation(pp, matrixMax), settings);
  
  if settings.result = GetPerm or settings.result = GetBool then
      return minTrans;
  fi;
  
  # TODO: Ask how to avoid having to do this to get a PartialPermBack
  # the mod is there as a quick(ish) way to turn 'matrixMax' into '0'.
  return PartialPerm(List(ListTransformation(minTrans, matrixMax), x -> x mod matrixMax));
end);


_cajGroupCopy := function(G, max, copies)
  local result, gen, i, j, p;

  result := [];
  for gen in GeneratorsOfGroup(G) do
    p := [];
    for i in [0..copies-1] do
      for j in [1..max] do
        p[j+i*max] := j^gen + i*max;
      od;
    od;
    Add(result, PermList(p));
  od;

  return GroupByGenerators(result, ());
end;

# WreathProduct doesn't quite give us the control we need
# (we can't set how big a copy of G to max for example)
_cajWreath := function(G, max, copies)
  local result, gen, i, j, p;

  result := List(GeneratorsOfGroup(_cajGroupCopy(G, max, copies)));

  Add(result, PermList(Flat([ [max+1..max*2], [1..max]])));
  Add(result, PermList(Flat([ [max+1..max*copies], [1..max]])));

  return GroupByGenerators(result, ());
end;



# This handles some trivial cases (OnSets, OnTuples)
# and some non-trival ones too!
InstallMethod(CanonicalImageOp, [IsPermGroup, IsList, IsFunction, IsObject],
function(inGroup, inList, op, settings)
  local stab, bigGroup, maxIn, setImage, imageperm, currentperm, i, outset, inner, outer, fList;
  
  # Bail out in global trivial case:
  if LargestMovedPoint(inGroup) = 0 then
    return _trivialReturn(inList, settings.result);
  fi;

  if op = OnSets then
      if settings.stabilizer <> fail then
          stab := settings.stabilizer;
      else
          stab := Stabilizer(inGroup, inList, OnSets);
      fi;
      
      imageperm := _CanonicalSetImage(inGroup, inList, stab, settings);
      if settings.result = GetImage then
         return Set(imageperm);
      else
         return imageperm;
      fi;
      
  fi;
  
  if op = OnTuples then
      fList := [];
      currentperm := ();
      for i in [1..Length(inList)] do
          imageperm := MinimalImagePerm(inGroup, inList[i]^currentperm, OnPoints);
          currentperm := currentperm*imageperm;
          fList[i] := inList[i]^currentperm;
          inGroup := Stabilizer(inGroup, fList[i]);
      od;
      if settings.result = GetImage then
          return fList;
      elif settings.result = GetBool then
          return fList = inList;
      else # GetPerm
          return currentperm;
      fi;
  fi;

  if op = OnTuplesSets then
    return _CanonicalTupleSetImage(inGroup, inList, settings);
  fi;
  
  if op = OnSetsSets then
    # Our code is not happy with empty lists, so let's get them filtered out first
    # (we will add them back at the end)
    fList := Filtered(inList, x -> Length(x) > 0);

    # Bail out in trivial situation
    if Length(fList) = 0 then
      return _trivialReturn(inList, settings.result);
    fi;

    maxIn := Maximum(Maximum(List(fList, x -> Maximum(x))),
                     LargestMovedPoint(inGroup));

    # TODO: Cache this
    bigGroup := _cajWreath(inGroup, maxIn, Size(fList));

    setImage := Flat(List([1..Length(fList)],
                        x -> List(fList[x], y -> y + (x-1)*maxIn)));
    if settings.stabilizer <> fail then
        if IsTrivial(settings.stabilizer) then
            stab := Group(());
        else
            Error("Only the trivial group is accepted for SetSet stabilizer in CanonicalImage");
        fi;
    else
        stab := Stabilizer(bigGroup, setImage, OnSets);
    fi;
    
    imageperm := _CanonicalSetSetImage(bigGroup, setImage, stab, maxIn, settings);
    
    if settings.result = GetBool then
        return imageperm;
    fi;
    
    if settings.result = GetPerm then
        # This perm is a wreath product perm, we want to project it down onto the first set
        return PermList(List([1..maxIn], x -> (x^imageperm - 1) mod maxIn + 1));
    fi;
    
    outset := List([1..Length(fList)], x -> []);

    for i in imageperm do
      inner := (i - 1) mod maxIn + 1;
      outer := (i - inner)/maxIn + 1;
      Add(outset[outer], inner);
    od;

    # Put those filtered lists back in
    for i in [1..Length(inList) - Length(fList)] do
      Add(outset, []);
    od;

    return Set(outset, x -> Set(x));
  fi;

  Error("Do not understand:", op);

end);

InstallGlobalFunction(_CanonicalImageParse, function ( arglist, resultarg, imagearg )
  local G,        # Group
        obj,      # object
        action,   # action
        settings, # settings
        index;    # index
      
  if Length(arglist) < 2 or Length(arglist) > 4 then
    Error("MinimalImage(G, obj [, action] [,config])");
  fi;

  G := arglist[1];
  
  if not(IsGroup(G)) then
    Error("First argument must be a group");
  fi;
  
  obj := arglist[2];
  
  index := 3;
  
  if Length(arglist) >= index and IsFunction(arglist[index]) then
    action := arglist[3];
    index := index + 1;
  else
    action := OnPoints;
  fi;
   
  settings := rec(result := resultarg, stabilizer := fail, order := imagearg, getStab := false,
                  disableStabilizerCheck := false);
  
  if Length(arglist) >= index and IsRecord(arglist[index]) then
    settings := _ImageHelperFuncs.fillUserValues(settings, arglist[index]);
    settings.original := arglist[index];
    index := index + 1;
  fi;
  
  if index <= Length(arglist) then
    Error("Failed to understand argument ",index, ", which was ", arglist[index]);
  fi;
  
  return CanonicalImageOp(G, obj, action, settings);
end);

InstallGlobalFunction(MinimalImage, function(arg)
  return _CanonicalImageParse(arg, GetImage, CanonicalConfig_Minimum);
end);

InstallGlobalFunction(IsMinimalImage, function(arg)
  return _CanonicalImageParse(arg, GetBool, CanonicalConfig_Minimum);
end);

InstallGlobalFunction(MinimalImagePerm, function(arg)
  return _CanonicalImageParse(arg, GetPerm, CanonicalConfig_Minimum);
end);

InstallGlobalFunction(CanonicalImage, function(arg)
  return _CanonicalImageParse(arg, GetImage, CanonicalConfig_Fast);
end);

InstallGlobalFunction(IsCanonicalImage, function(arg)
  return _CanonicalImageParse(arg, GetBool, CanonicalConfig_Fast);
end);

InstallGlobalFunction(CanonicalImagePerm, function(arg)
  return _CanonicalImageParse(arg, GetPerm, CanonicalConfig_Fast);
end);



InstallMethod(MinimalImageOrderedPair, [IsPermGroup, IsObject],
  function(G,O) return MinimalImageOrderedPair(G,O,OnPoints);
end);



InstallMethod(MinimalImageUnorderedPair, [IsPermGroup, IsObject],
  function(G,O) return MinimalImageUnorderedPair(G,O,OnPoints);
end);

InstallMethod(MinimalImageUnorderedPair, [IsPermGroup, IsList, IsFunction],
  function(G, O, F)
    local fperm, sperm, first, second, act1, act2;
    
    fperm := MinimalImagePerm(G, O[1], F);
    sperm := MinimalImagePerm(G, O[2], F);
    
    act1 := F(O[1], fperm);
    act2 := F(O[2], sperm);
    
    if act1 < act2 then
        second := MinimalImage(Stabilizer(G, F(O[1], fperm)), F(O[2], fperm), F);
        return [F(O[1], fperm), second];
    fi;
    
    if act1 > act2 then
        first := MinimalImage(Stabilizer(G, F(O[2], sperm)), F(O[1], sperm), F);
        return [F(O[2], sperm), first];
    fi;
    
     second := MinimalImage(Stabilizer(G, F(O[1], fperm)), F(O[2], fperm), F);
     first := MinimalImage(Stabilizer(G, F(O[2], sperm)), F(O[1], sperm), F);
     
     if first < second then
         return [act1, first];
     else
         return [act1, second];
     fi;
 end);
 

## CanonicalImage(Group, Obj, rec(action:=OnSets, 
##                                image:="Minimal",
##                                result := GetBool/GetBool/GetImage));

[ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet)  ]