<#GAPDoc Label="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>.

<#/GAPDoc>
<#GAPDoc Label="TrivialGroup">
 This method is successful if and only if all generators of a group
 <A>G</A> are equal to the identity. Otherwise, it returns
 <K>NeverApplicable</K> indicating that it will never succeed. This method
 is only installed to handle the trivial case such that we do not have to
 take this case into account in the other methods.

<#/GAPDoc>
<#GAPDoc Label="KnownNilpotent">
 Hint to this method if you know G to be nilpotent or call it directly
 if you find out so. Note that it will return NeverApplicable if G is a
 p-group for some prime p. Make sure that the !.projective component is set
 correctly such that we can set the right Order method.

<#/GAPDoc>
<#GAPDoc Label="FewGensAbelian">
 If there are not too may generators (right now that means at most 200),
 check whether they commute; if yes, dispatch to
 <Ref Subsect="KnownNilpotent" Style="Text"/>,
 otherwise return <K>NeverApplicable</K>.

<#/GAPDoc>
<#GAPDoc Label="Giant">
 The method tries to determine whether the input group <A>G</A> is
 a giant (that is, <M>A_n</M> or <M>S_n</M> in its natural action on
 <M>n</M> points). The output is either a data structure <M>D</M> containing
 nice generators for <A>G</A> and a procedure to write an SLP for arbitrary
 elements of <A>G</A> from the nice generators; or <K>NeverApplicable</K> if
 <A>G</A> is not transitive; or <K>fail</K>, in the case that no
 evidence was found that <A>G</A> is a giant, or evidence was found, but
 the construction of <M>D</M> was unsuccessful.
 If the method constructs <M>D</M> then the calling node becomes a leaf.

<#/GAPDoc>
<#GAPDoc Label="LargeBasePrimitive">
 This method tries to determine whether the input group <A>G</A> is a
 fixed-point-free large-base primitive group that neither is a symmetric nor an alternating
 group in its natural action.
 This method is an implementation of <Cite Key="LNPS06"/>.
<P/>
 A primitive group <M>H</M> acting on <M>N</M> points is called <E>large</E> if
 there exist <M>n</M>, <M>k</M>, and <M>r</M> with
 <M>N = \{n \choose k\}^r</M>, and up to a permutational isomorphism <M>H</M>
 is a subgroup of the product action wreath product <M>S_n \wr S_r</M>,
 and an overgroup of <M>(A_n) ^ r</M> where <M>S_n</M> and <M>A_n</M> act on
 the <M>k</M>-subsets of <M>\{1, ..., n\}</M>.
 This algorithm recognises fixed-point-free large primitive groups with
 <M>r \cdot k > 1</M>
 and <M>2 \cdot r \cdot k^2 \le n</M>.
<P/>
 A large primitive group <M>H</M> of the above type which does have fixed
 points is handled as follows: if the group <M>H</M> does not know yet that
 it is primitive, then <Ref Func="ThrowAwayFixedPoints"/> returns
 <K>NotEnoughInformation</K>. After the first call to
 <C>LargeBasePrimitive</C>, the group <M>H</M> knows that it is primitive,
 but since it has fixed points <C>LargeBasePrimitive</C> returns
 <K>NeverApplicable</K>. Since <Ref Func="ThrowAwayFixedPoints"/> previously
 returned <K>NotEnoughInformation</K>, it will be called again. Then it will
 use the new information about <M>H</M> being primitive, and is guaranteed to
 prune away the fixed points and set up a reduction homomorphism.
 <C>LargeBasePrimitive</C> is then applicable to the image of that
 homomorphism.
<P/>
 If <A>G</A> is imprimitive then the output is
 <K>NeverApplicable</K>. If <A>G</A> is primitive then
 the output is either a homomorphism into the
 natural imprimitive action of <A>G</A> on <M>nr</M> points with
 <M>r</M> blocks of size <M>n</M>,  or <K>TemporaryFailure</K>, or
 <K>NeverApplicable</K> if no parameters <M>n</M>, <M>k</M>, and <M>r</M> as
 above exist.

<#/GAPDoc>
<#GAPDoc Label="SnAnUnknownDegree">
 This method tries to determine whether the input group given by <A>ri</A> is
 isomorphic to a symmetric group Sn or alternating group An with
 <M>11 \leq n</M>.
 It is an implementation of <Cite Key="JLNP13"/>.
<P/>
 If <A>Grp(ri)</A> is a permutation group, we assume that it is primitive and
 not a giant (a giant is Sn or An in natural action).
<P/>

<#/GAPDoc>
<#GAPDoc Label="FindElmOfEvenNormal">
 TODO

<#/GAPDoc>
<#GAPDoc Label="DoBaseChangeForBlocks">
 TODO

<#/GAPDoc>
<#GAPDoc Label="LowIndex">
 This method is designed for the handling of the Aschbacher class C2
 (stabiliser of a decomposition of the underlying vector space), but may
 succeed on other types of input as well. Given <A>G</A> <M> \le PGL(d,q)</M>,
 the output is either the permutation action of <A>G</A> on a short
 orbit of subspaces or <K>fail</K>. In the current setup, <Q>short orbit</Q>
 is defined to have length at most <M>4d</M>.

<#/GAPDoc>
<#GAPDoc Label="Blocks">
 TODO

<#/GAPDoc>
<#GAPDoc Label="BlocksModScalars">
 This method is only called when hinted from above. In this method it is
 understood that G should <E>neither</E>
 be recognised as a matrix group <E>nor</E> as a projective group.
 Rather, it treats all diagonal blocks modulo scalars which means that
 two matrices are considered to be equal, if they differ only by a scalar
 factor in <E>corresponding</E> diagonal blocks, and this scalar can
 be different for each diagonal block. This means that the kernel of
 the homomorphism mapping to a node which is recognised using this
 method will have only scalar matrices in all diagonal blocks.
<P/>
 This method does the balanced tree approach mapping to subsets of the
 diagonal blocks and finally using projective recognition to recognise
 single diagonal block groups.

<#/GAPDoc>
<#GAPDoc Label="BlocksBackToMats">
 TODO

<#/GAPDoc>
<#GAPDoc Label="BlockScalar">
 This method is only called by a hint. Alongside with the hint it gets
 a block decomposition respected by the matrix group <A>G</A> to be recognised
 and the promise that all diagonal blocks of all group elements
 will only be scalar matrices. This method recursively builds a balanced tree
 and does scalar recognition in each leaf.

<#/GAPDoc>
<#GAPDoc Label="C6">
 This method is designed for the handling of the Aschbacher class C6
 (normaliser of an extraspecial group). If the input <A>G</A><M>\le PGL(d,q)</M>
 does not satisfy <M>d=r^n</M> and <M>r|q-1</M> for some prime <M>r</M>
 and integer <M>n</M> then the method
 returns <K>NeverApplicable</K>. Otherwise, it returns either a homomorphism of
 <A>G</A> into <M>Sp(2n,r)</M>, or a homomorphism into the C2 permutation
 action of <A>G</A> on a decomposition of <M>GF(q)^d</M>, or <K>fail</K>.

<#/GAPDoc>
<#GAPDoc Label="KroneckerProduct">
 TODO

<#/GAPDoc>
<#GAPDoc Label="TensorDecomposable">
 TODO/FIXME: it is unclear if the following description actually belongs
 to this method, so be cautious!
<P/>
 This method currently tries to find one tensor factor by powering up
 commutators of random elements to elements of prime order. This seems
 to work quite well provided that the two tensor factors are not
 <Q>linked</Q> too much such that there exist enough elements that act
 with different orders on both tensor factors.
<P/>
 This method and its description needs some improvement.

<#/GAPDoc>
<#GAPDoc Label="KroneckerKernel">
 TODO

<#/GAPDoc>
<#GAPDoc Label="NaturalSL">
 TODO

<#/GAPDoc>
<#GAPDoc Label="BiggerScalarsOnly">
 TODO

<#/GAPDoc>
<#GAPDoc Label="NotAbsolutelyIrred">
 If an irreducible projective group <A>G</A> acts absolutely irreducibly
 then this method returns <K>NeverApplicable</K>. If <A>G</A> is not absolutely
 irreducible then a homomorphism into a smaller dimensional representation
 over an extension field is defined. A hint is handed down to the image that
 no test for absolute irreducibility has to be done any more. Another hint
 is handed down to the kernel indicating that the only possible kernel
 elements can be elements in the centraliser of <A>G</A> in <M>PGL(d,q)</M>
 that come from scalar matrices in the extension field.

<#/GAPDoc>
<#GAPDoc Label="StabilizerChainProj">
 This method computes a stabiliser chain and a base and strong generating
 set using projective actions. This is a last resort method since for
 bigger examples no short orbits can be found in the natural action.
 The strong generators are the nice generator in this case and expressing
 group elements in terms of the nice generators ist just sifting along
 the stabiliser chain.

<#/GAPDoc>
<#GAPDoc Label="Subfield">
 TODO

<#/GAPDoc>
<#GAPDoc Label="C3C5">
 TODO

<#/GAPDoc>
<#GAPDoc Label="D247">
 TODO

<#/GAPDoc>
<#GAPDoc Label="PrototypeForC2C4">
 TODO/FIXME: PrototypeForC2C4 is not used anywhere

<#/GAPDoc>
<#GAPDoc Label="ComputeSimpleSocle">
 This method randomly computes the non-abelian simple socle and
 stores it along with additional information if it is called for
 an almost simple group. Once the non-abelian simple socle is
 computed the function does not need to be called again for this
 node and therefore returns <K>NeverApplicable</K>.

<#/GAPDoc>
<#GAPDoc Label="ThreeLargeElOrders">
 In the case when the input group <A>G</A><M> \le PGL(d,p^e)</M> is
 suspected to be
 simple but not alternating, this method takes the three
 largest element orders from a sample of pseudorandom elements of
 <A>G</A>. From these element orders, it tries to determine whether <A>G</A>
 is of Lie type and the characteristic of <A>G</A> if it is of
 Lie type. In the case when <A>G</A> is of Lie type of characteristic
 different from <M>p</M>, the method also provides
 a short list of the possible isomorphism types of <A>G</A>.
<P/>
 This method assumes that its input is neither alternating nor sporadic and
 that <Ref Func="ComputeSimpleSocle"/> has already been called.
<P/>
 This recognition method is based on the paper <Cite Key="KS09"/>.

<#/GAPDoc>
<#GAPDoc Label="AltSymBBByDegree">
 This method is a black box constructive (?) recognition of alternating
 and symmetric groups.
<P/>
 This algorithm is probably based on the paper <Cite Key="BLGN+05"/>.

<#/GAPDoc>
<#GAPDoc Label="SporadicsByOrders">
 This method returns a list of sporadic simple groups that <A>G</A>
 possibly could be. Therefore it checks whether
 <A>G</A> has elements of orders that do not appear in sporadic
 groups and otherwise checks whether the most common ("killer") orders
 of the sporadic groups appear.
 Afterwards it creates hints that come out of a table for the sporadic
 simple groups.

<#/GAPDoc>
<#GAPDoc Label="NameSporadic">
 This method returns a list of sporadic simple groups that the group
 underlying <A>ri</A> could be. It does not recognise extensions of sporadic
 simple groups nor the Monster and the Baby Monster group. It is based on the
 Magma v2.24.10 function <C>RecognizeSporadic</C>.

<#/GAPDoc>
<#GAPDoc Label="LieTypeNonConstr">
 Recognise quasi-simple group of Lie type when characteristic is given.
 Based on <Cite Key="BKPS02"/> and <Cite Key="AB01"/>.

<#/GAPDoc>
<#GAPDoc Label="ClassicalNatural">
 TODO

<#/GAPDoc>
<#GAPDoc Label="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.

<#/GAPDoc>
<#GAPDoc Label="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.
<P/>
 If the input group moves a large point (currently, this means a point
 larger than 10), then this method returns <K>NeverApplicable</K>.

<#/GAPDoc>
<#GAPDoc Label="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>.

<#/GAPDoc>
<#GAPDoc Label="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.

<#/GAPDoc>
<#GAPDoc Label="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.

<#/GAPDoc>
<#GAPDoc Label="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>.
<P/>
 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.

<#/GAPDoc>
<#GAPDoc Label="StabilizerChainPerm">
 TODO

<#/GAPDoc>
<#GAPDoc Label="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/>
<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/>
<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"/>.

<#/GAPDoc>
<#GAPDoc Label="Scalar">
 TODO

<#/GAPDoc>
<#GAPDoc Label="DiagonalMatrices">
 This method is successful if and only if all generators of a matrix group
 <A>G</A> are diagonal matrices. Otherwise, it returns <K>NeverApplicable</K>.

<#/GAPDoc>
<#GAPDoc Label="BlockLowerTriangular">
 This method is only called when a hint was passed down from the method
 <Ref Subsect="ReducibleIso" Style="Text"/>. In that case, it knows that a
 base change to block lower triangular form has been performed. The method
 can then immediately find a homomorphism by mapping to the diagonal blocks.
 It sets up this homomorphism and gives hints to image and kernel. For the
 image, the method <Ref Subsect="BlockDiagonal" Style="Text"/> is used and
 for the kernel, the method <Ref Subsect="LowerLeftPGroup" Style="Text"/>
 is used.
<P/>
 Note that this method is implemented in a way such that it can also be
 used as a method for a projective group <A>G</A>. In that case the
 recognition node has the <C>!.projective</C> component bound
 to <K>true</K> and this information is passed down to image and kernel.

<#/GAPDoc>
<#GAPDoc Label="ReducibleIso">
 This method determines whether a matrix group <A>G</A> acts irreducibly.
 If yes, then it returns <K>NeverApplicable</K>. If <A>G</A> acts reducibly then
 a composition series of the underlying module is computed and a base
 change is performed to write <A>G</A> in a block lower triangular form.
 Also, the method passes a hint to the image group that it is in
 block lower triangular form, so the image immediately can make
 recursive calls for the actions on the diagonal blocks, and then to the
 lower <M>p</M>-part. For the image the method
 <Ref Subsect="BlockLowerTriangular" Style="Text"/> is used.
<P/>
 Note that this method is implemented in a way such that it can also be
 used as a method for a projective group <A>G</A>. In that case the
 recognition node has the <C>!.projective</C> component bound
 to <K>true</K> and this information is passed down to image and kernel.

<#/GAPDoc>
<#GAPDoc Label="BlockDiagonal">
 This method is only called when a hint was passed down from the method
 <Ref Subsect="BlockLowerTriangular" Style="Text"/>.
 In that case, it knows that the group is in block diagonal form.
 The method is used both in the matrix- and the projective case.
<P/>
 The method immediately delegates to projective methods handling
 all the diagonal blocks projectively. This is done by giving a hint
 to the image to use the method
 <Ref Subsect="BlocksModScalars" Style="Text"/>.
 The method for the kernel then has to deal with only scalar blocks,
 either projectively or with scalars, which is again done by giving a hint
 to either use <Ref Subsect="BlockScalar" Style="Text"/> or
 <Ref Subsect="BlockScalarProj" Style="Text"/> respectively.
<P/>
 Note that this method is implemented in a way such that it can also be
 used as a method for a projective group <A>G</A>. In that case the
 recognition node has the <C>!.projective</C> component bound
 to <K>true</K> and this information is passed down to image and kernel.

<#/GAPDoc>
<#GAPDoc Label="LowerLeftPGroup">
 This method is only called by a hint from <Ref Subsect="BlockLowerTriangular" Style="Text"/>
 as the kernel of the homomorphism mapping to the diagonal blocks.
 The method uses the fact that this kernel is a <M>p</M>-group where
 <M>p</M> is the characteristic of the underlying field. It exploits
 this fact and uses this special structure to find nice generators
 and a method to express group elements in terms of these.

<#/GAPDoc>
<#GAPDoc Label="BlockScalarProj">
 This method is only called by a hint. Alongside with the hint it gets
 a block decomposition respected by the matrix group <A>G</A> to be recognised
 and the promise that all diagonal blocks of all group elements
 will only be scalar matrices. This method simply norms the last diagonal
 block in all generators by multiplying with a scalar and then
 delegates to <C>BlockScalar</C> (see <Ref Subsect="BlockScalar"/>)
 and matrix group mode to do the recognition.

<#/GAPDoc>
<#GAPDoc Label="GoProjective">
 This method defines a homomorphism from a matrix group <A>G</A>
 into the projective group <A>G</A> modulo scalar matrices. In fact, since
 projective groups in &GAP; are represented as matrix groups, the
 homomorphism is the identity mapping and the only difference is that in
 the image the projective group methods can be applied.
 The bulk of the work in matrix recognition is done in the projective group
 setting.

<#/GAPDoc>
<#GAPDoc Label="KnownStabilizerChain">
 If a stabilizer chain is already known, then the kernel node is given
 knowledge about this known stabilizer chain, and the image node is told to
 use homomorphism methods from the database for permutation groups.
 If a stabilizer chain of a parent node is already known this is used for
 the computation of a stabilizer chain of this node. This stabilizer chain
 is then used in the same way as above.

<#/GAPDoc>
<#GAPDoc Label="ProjDeterminant">
 The method defines a homomorphism from a projective group <A>G</A><M> \le
 PGL(d,q)</M> to the cyclic group <M>GF(q)^*/D</M>, where <M>D</M> is the set
 of <M>d</M>th powers in <M>GF(q)^*</M>. The image of a group
 element <M>g \in <A>G</A></M> is the determinant of a matrix representative of
 <M>g</M>, modulo <M>D</M>.

<#/GAPDoc>
<#GAPDoc Label="FindHomMethodsGeneric.TrivialGroup">
<Listing Type="Code"><![CDATA[
BindRecogMethod(FindHomMethodsGeneric, "TrivialGroup",
"go through generators and compare to the identity",
function(ri, G)
  local gens;
  # get the generators of the group
  gens := GeneratorsOfGroup(G);
<P/>
  # check whether all generators are trivial
  # ri!.isone is explained below
  if not ForAll(gens, ri!.isone) then
    # NeverApplicable because it makes
    # no sense to call this method again
    return NeverApplicable;
  fi;
<P/>
  # The group is trivial! Provide required information:
<P/>
  # size of the group
  SetSize(ri, 1);
<P/>
  # explained below
  Setslpforelement(ri, SLPforElementFuncsGeneric.TrivialGroup);
<P/>
  # SLP from given generators to nice generators
  Setslptonice(ri, StraightLineProgramNC([[[1,0]]],
                   Length(gens)));
<P/>
  # We have reached a leaf node.
  SetFilterObj(ri, IsLeaf);
  return Success;
end);
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="SLPforElementFuncsGeneric.TrivialGroup">
<Listing Type="Code"><![CDATA[
SLPforElementFuncsGeneric.TrivialGroup := function(ri,g)
    if not ri!.isone(g) then
        return fail;
    fi;
    return StraightLineProgramNC( [ [1,0] ], 1 );
end;
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="AddMethod_Perm_FindHomMethodsGeneric.TrivialGroup">
<Listing Type="Code"><![CDATA[
AddMethod(FindHomDbPerm, FindHomMethodsGeneric.TrivialGroup, 300);
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="AddMethod_Matrix_FindHomMethodsGeneric.TrivialGroup">
<Listing Type="Code"><![CDATA[
AddMethod(FindHomDbMatrix, FindHomMethodsGeneric.TrivialGroup, 3100);
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="AddMethod_Projective_FindHomMethodsGeneric.TrivialGroup">
<Listing Type="Code"><![CDATA[
AddMethod(FindHomDbProjective, FindHomMethodsGeneric.TrivialGroup, 3000);
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="FindHomMethodsPerm.NonTransitive">
<Listing Type="Code"><![CDATA[
BindRecogMethod(FindHomMethodsPerm, "NonTransitive",
"try to find non-transitivity and restrict to orbit",
rec(validatesOrAlwaysValidInput := true),
function(ri, G)
    local hom,la,o;
<P/>
    # test whether we can do something:
    if IsTransitive(G) then
        return NeverApplicable;
    fi;
<P/>
    # 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);
<P/>
    # TODO: explanation
    Setimmediateverification(ri, true);
<P/>
    # indicate success
    return Success;
end);
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="AddMethod_Perm_FindHomMethodsPerm.NonTransitive">
<Listing Type="Code"><![CDATA[
AddMethod(FindHomDbPerm, FindHomMethodsPerm.NonTransitive, 90);
]]></Listing>

<#/GAPDoc>
<#GAPDoc Label="SLCR.FindHom">
 Given two integers d and g and a group G which must be isomorphic to SL(d,q),
 this function recognises G constructively and stores the result in ri.
<P/>
 TODO: find a better name.

<#/GAPDoc>
