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


Quelle  perm.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of recog, a package for the GAP computer algebra system
##  which provides a collection of methods for the constructive recognition
##  of groups.
##
##  This files's authors include Max Neunhöffer, Ákos Seress.
##
##  Copyright of recog belongs to its developers whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-3.0-or-later
##
##
##  A collection of find homomorphism methods for permutation groups.
##
#############################################################################

#! @BeginChunk MovesOnlySmallPoints
#! If a permutation group moves only small points
#! (currently, this means that its largest moved point is at most 10),
#! then this method computes a stabilizer chain for the group via
#! <Ref Subsect="StabChain" Style="Text"/>.
#! This is because the most convenient way of solving constructive membership
#! in such a group is via a stabilizer chain.
#! In this case, the calling node becomes a leaf node of the composition tree.
#!
#! If the input group moves a large point (currently, this means a point
#! larger than 10), then this method returns <K>NeverApplicable</K>.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "MovesOnlySmallPoints",
"calculate a stabilizer chain if only small points are moved",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
  if LargestMovedPoint(G) <= 10 then
      return FindHomMethodsPerm.StabChain(ri, G);
  fi;
  return NeverApplicable;
end);

#! @BeginChunk NonTransitive
#! If a permutation group <A>G</A> acts nontransitively then this method
#! computes a homomorphism to the action of <A>G</A> on the orbit of the
#! largest moved point. If <A>G</A> is transitive then the method returns
#! <K>NeverApplicable</K>.
#! @EndChunk
#! @BeginCode FindHomMethodsPerm.NonTransitive
BindRecogMethod(FindHomMethodsPerm, "NonTransitive",
"try to find non-transitivity and restrict to orbit",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
    local hom,la,o;

    # test whether we can do something:
    if IsTransitive(G) then
        return NeverApplicable;
    fi;

    # compute orbit of the largest moved point
    la := LargestMovedPoint(G);
    o := Orb(G,la,OnPoints);
    Enumerate(o);
    # compute homomorphism into Sym(o), i.e, restrict
    # the permutation action of G to the orbit o
    hom := OrbActionHomomorphism(G,o);
    # TODO: explanation
    Setvalidatehomominput(ri, {ri,p} -> ForAll(o, x -> (x^p in o)));
    # store the homomorphism into the recognition node
    SetHomom(ri,hom);

    # TODO: explanation
    Setimmediateverification(ri, true);

    # indicate success
    return Success;
end);
#! @EndCode

#! @BeginChunk Imprimitive
#! If the input group is not known to be transitive then this method
#! returns <K>NotEnoughInformation</K>. If the input group is known to be transitive
#! and primitive then the method returns <K>NeverApplicable</K>; otherwise, the method
#! tries to compute a nontrivial block system. If successful then a
#! homomorphism to the action on the blocks is defined; otherwise,
#! the method returns <K>NeverApplicable</K>.
#! 
#! If the method is successful then it also gives a hint for the children of
#! the node by determining whether the kernel of the action on the
#! block system is solvable. If the answer is yes then the default value 20
#! for the number of random generators in the kernel construction is increased
#! by the number of blocks.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "Imprimitive",
"for a imprimitive permutation group, restricts to block system",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
    local blocks,hom,pcgs,subgens;

    # Only look for primitivity once we know transitivity:
    # This ensures the right trying order even if the ranking is wrong.
    if not HasIsTransitive(G) then
        return NotEnoughInformation;
    fi;

    # We test for known non-primitivity:
    if HasIsPrimitive(G) and IsPrimitive(G) then
        return NeverApplicable;
    fi;

    RECOG.SetPseudoRandomStamp(G,"Imprimitive");

    # Now try to work:
    blocks := MaximalBlocks(G,MovedPoints(G));
    if Length(blocks) = 1 then
        SetIsPrimitive(G,true);
        return NeverApplicable;
    fi;

    # Find the homomorphism:
    hom := ActionHomomorphism(G,blocks,OnSets);
    Setvalidatehomominput(ri, {ri,p} -> OnSetsSets(blocks, p) = blocks);
    SetHomom(ri,hom);

    # Now we want to help recognising the kernel, we first check, whether
    # the restriction to one block is solvable, which would mean, that
    # the kernel is solvable and that a hint is in order:
    Setimmediateverification(ri,true);
    InitialDataForKernelRecogNode(ri).blocks := blocks;
    AddMethod(InitialDataForKernelRecogNode(ri).hints, FindHomMethodsPerm.PcgsForBlocks, 400);
    AddMethod(InitialDataForKernelRecogNode(ri).hints, FindHomMethodsPerm.BalTreeForBlocks, 200);
    findgensNmeth(ri).args[1] := Length(blocks)+3;
    findgensNmeth(ri).args[2] := 5;
    return Success;
end);

#! @BeginChunk PcgsForBlocks
#! This method is called after a hint is set in
#! <C>FindHomMethodsPerm.</C><Ref Subsect="Imprimitive" Style="Text"/>.
#! Therefore, the group <A>G</A> preserves a non-trivial block system.
#! This method checks whether or not the restriction of <A>G</A> on one block
#! is solvable.
#! If so, then <C>FindHomMethodsPerm.</C><Ref Subsect="Pcgs" Style="Text"/> is
#! called, and otherwise <K>NeverApplicable</K> is returned.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "PcgsForBlocks",
"TODO",
function(ri, G)
  local blocks,pcgs,subgens;
  blocks := ri!.blocks;   # we know them from above!
  subgens := List(GeneratorsOfGroup(G),g->RestrictedPerm(g,blocks[1]));
  pcgs := Pcgs(Group(subgens));
  if pcgs <> fail then
      # We now know that the kernel is solvable, go directly to
      # the Pcgs method:
      return FindHomMethodsPerm.Pcgs(ri,G);
  fi;
  # We have failed, let others do the work...
  return NeverApplicable;
end);

#! @BeginChunk BalTreeForBlocks
#! This method creates a balanced composition tree for the kernel of an
#! imprimitive group. This is guaranteed as the method is just called
#! from <C>FindHomMethodsPerm.</C><Ref Subsect="Imprimitive" Style="Text"/>
#! and itself. The homomorphism for the split in the composition tree used is
#! induced by the action of <A>G</A> on
#! half of its blocks.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "BalTreeForBlocks",
"TODO",
function(ri, G)
  local blocks,cut,hom,lowerhalf,nrblocks,o,upperhalf,l,n,seto;

  blocks := ri!.blocks;

  # We do exactly the same as in the non-transitive case, however,
  # we restrict to about half the blocks and pass our knowledge on:
  nrblocks := Length(blocks);
  if nrblocks = 1 then
      # this might happen during the descent into the tree
      return NeverApplicable;
  fi;
  cut := QuoInt(nrblocks,2);  # this is now at least 1
  lowerhalf := blocks{[1..cut]};
  upperhalf := blocks{[cut+1..nrblocks]};
  o := Concatenation(upperhalf);
  # The order of 'o' in the homom must align with InitialDataForImageRecogNode(ri).blocks below
  hom := ActionHomomorphism(G,o);

  # Make a set so checking validatehomominput is faster
  seto := Immutable(Set(o));
  Setvalidatehomominput(ri, {ri,p} -> ForAll(o, x -> x^p in seto));
  SetHomom(ri,hom);
  Setimmediateverification(ri,true);
  findgensNmeth(ri).args[1] := 3+cut;
  findgensNmeth(ri).args[2] := 5;
  if nrblocks - cut > 1 then
      l := Length(upperhalf[1]);
      n := Length(upperhalf);
      InitialDataForImageRecogNode(ri).blocks := List([1..n],i->[(i-1)*l+1..i*l]);
      AddMethod(InitialDataForImageRecogNode(ri).hints, FindHomMethodsPerm.BalTreeForBlocks, 200);
  fi;
  if cut > 1 then
      InitialDataForKernelRecogNode(ri).blocks := lowerhalf;
      AddMethod(InitialDataForKernelRecogNode(ri).hints, FindHomMethodsPerm.BalTreeForBlocks, 200);
  fi;
  return Success;
end);

# Now to the small base groups using stabilizer chains:

# The GAP manual suggests that the labels at each level of a stabiliser chain
# are identical GAP objects, but it does not promise this.
# This function tests whether the stabiliser chain has this property, and
# gives an error if not.
DoSafetyCheckStabChain := function(S)
  while IsBound(S.stabilizer) do
      if not IsIdenticalObj(S.labels, S.stabilizer.labels) then
          ErrorNoReturn("Alert! labels not identical on different levels!");
      fi;
      S := S.stabilizer;
  od;
end;

#! @BeginChunk StabChain
#! This is the randomized &GAP; library function for computing a stabiliser
#! chain. The method selection process ensures that this function is called
#! only with small-base inputs, where the method works efficiently.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "StabChain",
"for a permutation group using a stabilizer chain",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
     local Gmem,S,si;

     # We know transitivity and primitivity, because there are higher ranked
     # methods checking for them!

     # Calculate a stabilizer chain:
     Gmem := GroupWithMemory(G);
     if HasStabChainMutable(G) or HasStabChainImmutable(G) or HasSize(G) then
         si := Size(G);
         S := StabChainOp(Gmem,rec(random := 900,size := si));
     else
         S := StabChainOp(Gmem,rec(random := 900));
     fi;
     DoSafetyCheckStabChain(S);
     Setslptonice(ri,SLPOfElms(S.labels));
     StripStabChain(S);
     SetNiceGens(ri,S.labels);
     MakeImmutable(S);
     ri!.stabilizerchain := S;
     Setslpforelement(ri,SLPforElementFuncsPerm.StabChain);
     SetFilterObj(ri,IsLeaf);
     SetSize(G,SizeStabChain(S));
     SetSize(ri,SizeStabChain(S));
     ri!.Gnomem := G;
     return Success;
end);

SLPforElementFuncsPerm.StabilizerChainPerm := function(ri,x)
  local r;
  r := SiftGroupElementSLP(ri!.stabilizerchain,x);
  return r.slp;
end;

#! @BeginChunk StabilizerChainPerm
#! TODO
#! @EndChunk
# TODO: merge FindHomMethodsPerm.StabilizerChainPerm and  FindHomMethodsProjective.StabilizerChainProj ?
BindRecogMethod(FindHomMethodsPerm, "StabilizerChainPerm",
Concatenation(
    "for a permutation group using a stabilizer chain via the ",
    "<URL Text=\"genss package\">",
    "https://gap-packages.github.io/genss/",
    "</URL>"),
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
  local Gm,S;
  Gm := Group(ri!.gensHmem);
  Gm!.pseudorandomfunc := [rec(
     func := function(ri) return RandomElm(ri,"StabilizerChainPerm",true).el; end,
     args := [ri])];
  S := StabilizerChain(Gm);
  SetSize(ri,Size(S));
  SetSize(Grp(ri),Size(S));
  ri!.stabilizerchain := S;
  Setslptonice(ri,SLPOfElms(StrongGenerators(S)));
  ForgetMemory(S);
  Setslpforelement(ri,SLPforElementFuncsPerm.StabilizerChainPerm);
  SetFilterObj(ri,IsLeaf);
  return Success;
end);

# creates recursively a word for <g> using the Schreier tree labels
# from the stabilizer chain <S>
WordinLabels := function(word,S,g)
  local i,point,start;
  if not (IsBound(S.orbit) and IsBound(S.orbit[1])) then
      return fail;
  fi;
  start := S.orbit[1];
  point := start^g;
  while point <> start do
      if not IsBound(S.translabels[point]) then
          return fail;
      fi;
      i := S.translabels[point];
      g := g * S.labels[i];
      point := point^S.labels[i];
      Add(word,i);
  od;
  # now g is in the first stabilizer
  if g <> S.identity then
      if not IsBound(S.stabilizer) then
          return fail;
      fi;
      return WordinLabels(word,S.stabilizer,g);
  fi;
  return word;
end;

# creates a straight line program for an element <g> using the
# Schreier tree labels from the stabilizer chain <S>
SLPinLabels := function(S,g)
  local i,j,l,line,word;
  word := WordinLabels([],S,g);
  if word = fail then
      return fail;
  fi;
  line := [];
  i := 1;
  while i <= Length(word) do
      # Find repeated labels:
      j := i+1;
      while j < Length(word) and word[j] = word[i] do
          j := j + 1;
      od;
      Add(line,word[i]);
      Add(line,j-i);
      i := j;
  od;
  l := Length(S!.labels);
  if Length(word) = 0 then
      return StraightLineProgramNC([[1, 0]], l);
  fi;
  return StraightLineProgramNC([line, [l + 1, -1]], l);
end;


SLPforElementFuncsPerm.StabChain :=
  function( ri, g )
    # we know that ri!.stabilizerchain is an immutable StabChain and
    # ri!.stronggensslp is bound to a slp that expresses the strong generators
    # in that StabChain in terms of the GeneratorsOfGroup(Grp(ri)).
    return SLPinLabels(ri!.stabilizerchain,g);
  end;

StoredPointsPerm := function(p)
  # Determines, as a permutation of how many points p is stored.
  local s;
  s := SIZE_OBJ(p) - GAPInfo.BytesPerVariable;
  if IsPerm4Rep(p) then
      return s/4;   # permutation stored with 4 bytes per point
  elif IsPerm2Rep(p) then
      return s/2;   # permutation stored with 2 bytes per point
  fi;
  ErrorNoReturn("StoredPointsPerm: input is not an internal permutation");
end;

#! @BeginChunk ThrowAwayFixedPoints
#! This method defines a homomorphism of a permutation group
#! <A>G</A> to the action on the moved points of <A>G</A> if
#! <A>G</A> has any fixed points, and is either known to be primitive or the
#! ratio of fixed points to moved points exceeds a certain threshold. If <A>G</A>
#! has fixed points but is not primitive, then it returns
#! <K>NotEnoughInformation</K> so that it may be called again at a later time.
#! In all other cases, it returns <K>NeverApplicable</K>.
#! <P/>
#!
#! In the current setup, the
#! homomorphism is defined if the number <M>n</M> of moved
#! points is at most <M>1/3</M> of the largest moved point of <A>G</A>,
#! or <M>n</M> is at most half of the number of points on which
#! <A>G</A> is stored internally by &GAP;.
#! <P/>
#!
#! The fact that this method returns <K>NotEnoughInformation</K> if <A>G</A>
#! has fixed points but does not know whether it is primitive, is important for
#! the efficient handling of large-base primitive groups by
#! <Ref Func="LargeBasePrimitive"/>.
#! @EndChunk
#
#  A technical explanation of why we use a threshold for the ratio of fixed
#  points to moved points, this is technical so it does not go into the manual:
#  The reason we do not just always discard fixed points is that it also incurs
#  a cost, so we only try to do it when it seems worthwhile to do so.
#
#  Suppose the group G is not known to be primitive. Then we still
#  apply this method if one of the following two criterion is met:
#  - the largest moved point of G is three or more times larger than the number
#    n of actually moved points
#  - there is a generator of G whose internal storage reserves space for a
#    number of moved points which is two or more times larger than n. Note that
#    even for a simple transposition (1,2), for technical reasons it can happen
#    that GAP internally stores it with the same size as a permutation moving a
#    million points; this is wasteful, and the second criterion tries to deal
#    with this.

BindRecogMethod(FindHomMethodsPerm, "ThrowAwayFixedPoints",
"try to find a huge amount of (possible internal) fixed points",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
      # Check, whether we can throw away fixed points
      local gens,nrStoredPoints,n,largest,isApplicable,o,hom;

      gens := GeneratorsOfGroup(G);
      nrStoredPoints := Maximum(List(gens,StoredPointsPerm));
      n := NrMovedPoints(G);
      largest := LargestMovedPoint(G);
      # If isApplicable is true, we definitely are applicable.
      isApplicable := 3*n <= largest or 2*n <= nrStoredPoints
        or (HasIsPrimitive(G) and IsPrimitive(G) and n < largest);
      # If isApplicable is false, we might become applicable if G figures out
      # that it is primitive.
      if not isApplicable then
          if not HasIsPrimitive(G) and n < largest then
              return NotEnoughInformation;
          else
              return NeverApplicable;
          fi;
      fi;
      o := MovedPoints(G);
      hom := ActionHomomorphism(G,o);
      SetHomom(ri,hom);
      Setvalidatehomominput(ri, {ri,p} -> IsSubset(o, MovedPoints(p)));

      # Initialize the rest of the record:
      findgensNmeth(ri).method := FindKernelDoNothing;

      return Success;
end);

#! @BeginChunk Pcgs
#! This is the &GAP; library function to compute a stabiliser chain for a
#! solvable permutation group. If the method is successful then the calling
#! node becomes a leaf node in the recursive scheme. If the input group is
#! not solvable then the method returns <K>NeverApplicable</K>.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "Pcgs",
"use a Pcgs to calculate a stabilizer chain",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
    local GM,S,pcgs;
    GM := Group(ri!.gensHmem);
    GM!.pseudorandomfunc := [rec(
       func := function(ri) return RandomElm(ri,"PCGS",true).el; end,
       args := [ri])];
    pcgs := Pcgs(GM);
    if pcgs = fail then
        return NeverApplicable;
    fi;
    S := StabChainMutable(GM);
    DoSafetyCheckStabChain(S);
    Setslptonice(ri,SLPOfElms(S.labels));
    StripStabChain(S);
    SetNiceGens(ri,S.labels);
    MakeImmutable(S);
    ri!.stabilizerchain := S;
    Setslpforelement(ri,SLPforElementFuncsPerm.StabChain);
    SetFilterObj(ri,IsLeaf);
    SetSize(G,SizeStabChain(S));
    SetSize(ri,SizeStabChain(S));
    ri!.Gnomem := G;
    return Success;
end);


# The following commands install the above methods into the database:
#! @BeginCode AddMethod_Perm_FindHomMethodsGeneric.TrivialGroup
AddMethod(FindHomDbPerm, FindHomMethodsGeneric.TrivialGroup, 300);
#! @EndCode

AddMethod(FindHomDbPerm, FindHomMethodsPerm.ThrowAwayFixedPoints, 100);

AddMethod(FindHomDbPerm, FindHomMethodsGeneric.FewGensAbelian, 99);

AddMethod(FindHomDbPerm, FindHomMethodsPerm.Pcgs, 97);

AddMethod(FindHomDbPerm, FindHomMethodsPerm.MovesOnlySmallPoints, 95);

#! @BeginCode AddMethod_Perm_FindHomMethodsPerm.NonTransitive
AddMethod(FindHomDbPerm, FindHomMethodsPerm.NonTransitive, 90);
#! @EndCode

AddMethod(FindHomDbPerm, FindHomMethodsPerm.Giant, 80);

AddMethod(FindHomDbPerm, FindHomMethodsPerm.Imprimitive, 70);

AddMethod(FindHomDbPerm, FindHomMethodsPerm.LargeBasePrimitive, 60);

AddMethod(FindHomDbPerm, FindHomMethodsPerm.StabilizerChainPerm, 55);

AddMethod(FindHomDbPerm, FindHomMethodsPerm.StabChain, 50);


# Note that the last one will always succeed!

[ Dauer der Verarbeitung: 0.26 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