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


SSL stbcrand.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Ákos Seress.
##
##  Copyright of GAP belongs to its developers, whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-2.0-or-later
##
##  This  file contains  the  functions for  a random Schreier-Sims algorithm
##  with verification.
##

#############################################################################
##
#F  StabChainRandomPermGroup( <gens>, <id>, <opts> )  .  random Schreier-Sims
##
##  The  method  consists of  2  phases:  a  heuristic construction  and
##  either a deterministic or two random checking phases.
##  In the random checking  phases,  we  take random  elements of
##  created set, multiply by  random subproduct of  generators, and sift down
##  by dividing with the  appropriate coset representatives. The stabchain is
##  correct when  all  siftees are  ().    In the first  checking  phase, all
##  computations are carried out with words  in strong generators and siftees
##  are checked by plugging in random points in words; in the second checking
##  phase, permutations are multiplied.
##
##  During the construction, we create new records for stabilizers:
##  S.aux = set of strong generators for S, temporarily created during the
##          construction. On the other hand, S.generators contains a strong
##          generating set for S which would have been created by the
##          deterministic method
##  S.treegen = elements of S.aux used in S.transversal
##  S.treegeninv = inverses of S.treegen; also used in S.transversal,
##                 and they are also elements of S.aux
##  S.treedepth = depth of Schreier tree of S
##  S.diam = sum of treedepths in stabilizer chain of S
##
##  After the  stabilizer chain  is  ready,  the  extra records are  deleted.
##  Transversals are rebuilt using the generators in the .generators records.
##
InstallGlobalFunction( StabChainRandomPermGroup, function( gens, id, options)
    local S,        # stabilizer chain
          degree,   # degree of S
          givenbase,# list of points from which first base points should come
          correct,  # boolean; true if a correct base is given
          size,     # size of <G> as constructed
          order,    # size of G if given in input
          limit,    # upper bound on Size(G) given in input
          orbits,   # list of orbits of G
          orbits2,  # list of orbits of G
          k,        # number of pairs of generators checked
          param,    # list of parameters guiding number of repetitions
                    # in random constructions
          where,    # list indicating which orbit contains points in domain
          basesize, # list; i^th entry = number of base points in orbits[i]
          i,j,
          ready,    # boolean; true if stabilizer chain ready
          warning,  # used at warning if given and computed size differ
          new,      # list of permutations to be added to stab. chain
          result,   # output of checking phase; nontrivial if stabilizer
                    # chain is incorrect
          base,     # ordering of domain from which base points are taken
          missing,  # if a correct base was provided by input, missing
                    # contains those points of it which are not in
                    # constructed base
          T;        # a stabilizer chain containing the usual records

    S:= rec( generators := ShallowCopy( gens ), identity := id );
    if options.random = 1000 then
       #case of deterministic computation with known size
       k := 1;
    else
       k:=First([1..14],x->(3/5)^x<1-options.random/1000);
    fi;

    degree := LargestMovedPoint( S.generators );

    if IsBound( options.knownBase) and
      Length(options.knownBase)<4+LogInt(degree,10)  then
        param:=[k,4,0,0,0,0];
    else
        param:=[QuoInt(k,2),4,QuoInt(k+1,2),4,50,5];
        options:=ShallowCopy(options);
        Unbind(options.knownBase);
    fi;
    if options.random <= 200 then
       param[2] := 2;
       param[4] := 2;
    fi;

    #param[1] = number of pairs of random subproducts from generators in
    #           first checking phase
    #param[2] = (number of random elements from created set)/S.diam
    #           in first checking phase
    #param[3] = number of pairs of random subproducts from generators in
    #           second checking phase
    #param[4] = (number of random elements from created set)/S.diam
    #           in second checking phase
    #param[5] = maximum size of orbits in  which we evaluate words on all
    #           points of orbit
    #param[6] = minimum number of random points from orbit to plug in to check
    #           whether given word is identity on orbit


    # prepare input of construction
    if IsBound(options.base)  then
        givenbase := options.base;
    else
        givenbase := [];
    fi;

    if IsBound(options.size) then
        order := options.size;
        warning := 0;
        limit := 0;
    else
        order := 0;
        if IsBound(options.limit) then
            limit := options.limit;
        else
            limit := 0;
        fi;
    fi;

    if IsBound( options.knownBase )  then
        correct := true;
    else
        correct := false;
    fi;

    if correct then
        # if correct  base was given as input, no need for orbit information
        base:=Concatenation(givenbase,Difference(options.knownBase,givenbase));
        missing := Set(options.knownBase);
        basesize := [];
        where := [];
        orbits := [];
    else
        # create ordering of domain used in choosing base points and
        # compute orbit information
        base:=Concatenation(givenbase,Difference([1..degree],givenbase));
        missing:=[];
        orbits2:=OrbitsPerms(S.generators,[1..degree]);
        #throw away one-element orbits
        orbits:=[];
        j:=0;
        for i in [1..Length(orbits2)] do
            if Length(orbits2[i]) >1 then
               j:=j+1; orbits[j]:= orbits2[i];
            fi;
        od;
        basesize:=[];
        where:=[];
        for i in [1..Length(orbits)] do
            basesize[i]:=0;
            for j in [1..Length(orbits[i])] do
                where[orbits[i][j]]:=i;
            od;
        od;
        # temporary solution to speed up of handling of lots of small orbits
        # until compiler
        if Length(orbits) > degree/40 then
           param[1] := 0;
           param[3] := k;
        fi;
    fi;

    ready:=false;
    new:=S.generators;

    while not ready do
        SCRMakeStabStrong
           (S,new,param,orbits,where,basesize,base,correct,missing,true);
        # last parameter of input is true if function called for original G
        # in recursive calls on stabilizers, it is false
        # reason: on top level,
        #         we do not want to add anything to generating set

        # start checking
        size := 1;  T := S;
        while Length( T.generators ) <> 0  do
            size := size * Length( T.orbit );
            T := T.stabilizer;
        od;
        if size = order  or  size = limit  then
            ready := true;
        elif size < order then
            # we have an incorrect stabilizer chain
            # repeat checking until a new element is discovered
            result := id;
            if options.random = 1000 then
                if correct then
                   result := SCRStrongGenTest(S,[1,10/S.diam,0,0,0,0],orbits,
                                      basesize,base,correct,missing);
                else
                   result := SCRStrongGenTest2(S,[0,0,1,10/S.diam,0,0]);
                fi;
                if result = id then
                   T := SCRRestoredRecord(S);
                   result := VerifySGS(T,missing,correct);
                fi;
                if result = id then
                   Print("Warning, computed and given size differ","\n");
                   ready := true;
                   S := T;
                else
                   if not IsPerm(result) then
                      repeat
                         result := SCRStrongGenTest2(S,[0,0,1,10/S.diam,0,0]);
                      until result <> id;
                   fi;
                   new := [result];
                fi;
            else
               warning := 0;
               if correct then
                 # if correct base was provided, it is enough to check
                 # images of base points to check whether a word is trivial
                 # no need for second checking phase
                 while result = id do
                    warning := warning + 1;
                    if warning > 5 then
                       Print("Warning, computed and given size differ","\n");
                    fi;
                    result := SCRStrongGenTest(S,param,orbits,
                                      basesize,base,correct,missing);
                 od;
               else
                 while result = id do
                    warning := warning + 1;
                    if warning > 5 then
                       Print("Warning, computed and given size differ","\n");
                    fi;
                    result:=SCRStrongGenTest(S,param,orbits,
                                    basesize,base,correct,missing);
                    if result = id then
                        # Print("entering SGT2","\n");
                        result:=SCRStrongGenTest2(S,param);
                    fi;
                 od;
               fi;  # correct or not
               new:=[result];
            fi;   # end of random checking or not, when size is known
        else
            #no information or only upper bound about Size(S)
            if options.random = 1000 then
              if correct then
                   result := SCRStrongGenTest(S,[1,10/S.diam,0,0,0,0],orbits,
                                      basesize,base,correct,missing);
               else
                   result := SCRStrongGenTest2(S,[0,0,1,10/S.diam,0,0]);
               fi;
               if result = id then
                  T := SCRRestoredRecord(S);
                  result := VerifySGS(T,missing,correct);
               fi;
               if result = id then
                  S := T;
                  ready := true;
               else
                  if not IsPerm(result) then
                     repeat
                        result := SCRStrongGenTest2(S,[0,0,1,10/S.diam,0,0]);
                     until result <> id;
                  fi;
                  new := [result];
               fi;
            else
               # Print("entering SGT", "\n");
               result:=SCRStrongGenTest(S,param,orbits,basesize,
                                  base,correct,missing);
               if result <> id then
                  new:=[result];
               elif correct then
                  # no need for second checking phase
                  ready:=true;
               else
                   # Print("entering SGT2","\n");
                   result:=SCRStrongGenTest2(S,param);
                   if result = id then
                      ready:=true;
                   else
                      new:=[result];
                   fi;
               fi;
            fi;   # random checking or not, when size is not known
        fi;   # size known
    od;

    #restore usual record elements
    if not IsBound(S.labels) then
       S := SCRRestoredRecord(S);
    fi;
    return S;
end );


#############################################################################
##
#F  SCRMakeStabStrong( ... )  . . . . . . . . . . . . . . . . . . . . . local
##
##  heuristic stabilizer  chain  construction, with one random  subproduct on
##  each  level,  and one or two  (defined  by mlimit) random cosets  to make
##  Schreier generators
##
InstallGlobalFunction( SCRMakeStabStrong,
    function ( S, new, param, orbits, where, basesize, base,
                                correct, missing, top )
    local   x,m,j,l,      # loop variables
            ran1,         # random permutation
            string,       # random 0-1 string
            w,            # random subproduct of generators
            len,          # number of generators of S
            mlimit,       # number of random elements to be tested
            coset,        # word representing coset of S
            residue,      # first component: remainder of Schreier generator
                          # after factorization; second component > 0
                          # if factorization unsuccessful
            jlimit,       # number of random points to plug into residue[1]
            ran,          # index of random point in an orbit of S
            g,            # permutation to be added to S.stabilizer
            gen,          # permutations used in S.transversal
            inv,          # their inverses
            firstmove;    # first point of base moved by an element of new

    if new <> [] then
        firstmove := First( base, x->ForAny( new, gen->x^gen<>x ) );
        # if necessary add a new stabilizer to the stabchain
        if not IsBound(S.stabilizer) then
            S.orbit                    := [firstmove];
            S.transversal              := [];
            S.transversal[S.orbit[1]]  := S.identity;
            S.generators               := [];
            S.treegen                  := [];
            S.treegeninv               := [];
            S.stabilizer               := rec();
            S.stabilizer.identity      := S.identity;
            S.stabilizer.aux           := [];
            S.stabilizer.generators    := [];
            S.stabilizer.diam          := 0;
            if not correct then
                basesize[where[S.orbit[1]]]
                    := basesize[where[S.orbit[1]]] + 1;
            fi;
            missing := Difference( missing, [ firstmove ] );
        else
            if Position(base,firstmove) < Position(base,S.orbit[1]) then
                S.stabilizer               := ShallowCopy(S);
                S.orbit                    := [firstmove];
                S.transversal              := [];
                S.transversal[S.orbit[1]]  := S.identity;
                S.generators := ShallowCopy(S.stabilizer.generators);
                S.treegen                  := [];
                S.treegeninv               := [];
                if not correct then
                    basesize[where[S.orbit[1]]]
                      := basesize[where[S.orbit[1]]] + 1;
                fi;
                missing := Difference( missing, [ firstmove ] );
            fi;
        fi;

        # on top level, we want to keep the original generators
        if not top or Length(S.generators) = 0  then
          for j in new do
            StretchImportantSLPElement(j);
          od;
          Append(S.generators,new);
        fi;
        #construct orbit of basepoint
        SCRSchTree(S,new);

        #check whether new elements are really new in the system
        while new <> [] do
            g := SCRSift( S, Remove(new) );
            if g <> S.identity then
                SCRMakeStabStrong(S.stabilizer,[g],param,orbits,
                                  where,basesize,base,correct,missing,false);
                S.diam:=S.treedepth+S.stabilizer.diam;
                S.aux:=Concatenation(S.treegen,
                                     S.treegeninv,S.stabilizer.aux);
            fi;
        od;
    fi;

    #check random Schreier generators
    gen := Concatenation(S.treegen,S.treegeninv,[S.identity]);
    inv := Concatenation(S.treegeninv,S.treegen,[S.identity]);
    len := Length(S.aux);
    #in case of more than one generator for S, form a random subproduct
    #otherwise, use the generator
    if len > 1 then
        ran1 := SCRRandomPerm(len);
        string := SCRRandomString(len);
        w := S.identity;
        for x in [1..len] do
            w := w*(S.aux[x^ran1]^string[x]);
        od;
    else
        w:=S.aux[1];
    fi;

    # take random coset(s)
    mlimit:=1;
    m:=0;
    while m < mlimit do
        m := m+1;
        ran := Random(1, Length(S.orbit));
        coset := CosetRepAsWord(S.orbit[1],S.orbit[ran],S.transversal);
        coset := InverseAsWord(coset,gen,inv);
        if w <> S.identity then
            # form Schreier generator and factorize
            Add(coset,w);
            residue := SiftAsWord(S,coset);
            # check whether factorization is successful
            if residue[2] > 0  then
                # factorization is unsuccessful; use remainder for
                # construction in stabilizer
                g := Product(residue[1]);
                SCRMakeStabStrong(S.stabilizer,[g],param,orbits,where,
                                  basesize,base,correct,missing,false);
                S.diam := S.treedepth+S.stabilizer.diam;
                S.aux := Concatenation(S.treegen,S.treegeninv,
                                       S.stabilizer.aux);
                # get out of current loop
                m := 0;
            elif correct then
                # enough to check images of points in given base
                l := 0;
                while l < Length(missing) do
                    l := l+1;
                    if ImageInWord(missing[l],residue[1]) <> missing[l] then
                        # factorization is unsuccessful;
                        # use remainder for construction in stabilizer
                        g := Product(residue[1]);
                        SCRMakeStabStrong(S.stabilizer,[g],param,
                                          orbits,where,basesize,
                                          base,correct,missing,false);
                        S.diam := S.treedepth+S.stabilizer.diam;
                        S.aux := Concatenation(S.treegen,
                                               S.treegeninv,S.stabilizer.aux);
                        # get out of current loop
                        m := 0;
                        l := Length(missing);
                    fi;
                od;
            else
                l:=0;
                while l < Length(orbits) do
                    l:=l+1;
                    if Length(orbits[l]) > param[5] then
                        # in large orbits, plug in random points
                        j:=0;
                        jlimit:=Maximum(param[6],basesize[l]);
                        while j < jlimit do
                            j:=j+1;
                            ran:=Random(1, Length(orbits[l]));
                            if ImageInWord(orbits[l][ran],residue[1])
                              <> orbits[l][ran]
                            then
                                # factorization is unsuccessful;
                                # use remainder for construction in stabilizer
                                g := Product(residue[1]);
                                SCRMakeStabStrong(S.stabilizer,[g],param,
                                                  orbits,where,basesize,
                                                  base,correct,missing,false);
                                S.diam := S.treedepth+S.stabilizer.diam;
                                S.aux := Concatenation(S.treegen,S.treegeninv,
                                                       S.stabilizer.aux);
                                # get out of current loop
                                m := 0;
                                j := jlimit;
                                l := Length(orbits);
                            fi;
                        od; #j loop
                    else
                        # in small orbits, check images of all points
                        j := 0;
                        while j < Length(orbits[l]) do
                            j := j+1;
                            if ImageInWord(orbits[l][j],residue[1])
                              <> orbits[l][j]
                            then
                                # factorization is unsuccessful;
                                # use remainder for construction in stabilizer
                                g := Product(residue[1]);
                                SCRMakeStabStrong(S.stabilizer,[g],param,
                                                  orbits,where,basesize,
                                                  base,correct,missing,false);
                                S.diam := S.treedepth+S.stabilizer.diam;
                                S.aux := Concatenation(S.treegen,S.treegeninv,
                                                       S.stabilizer.aux);
                                # get out of current loop
                                m := 0;
                                j := Length(orbits[l]);
                                l := Length(orbits);
                            fi;
                        od; #j loop
                    fi;
                od; #l loop
            fi;
        fi;
    od; #m loop

end );


#############################################################################
##
#F  SCRStrongGenTest( ... ) . . . . . . . . . . . . . . . . . . . . . . local
##
##  tests whether product of a random element of S and a random subproduct of
##  the strong generators  of S is in S.   Computations are  carried out with
##  words in generators   representing  group  elements; random   points  are
##  plugged in to test whether a word represents  the identity.  If SGS for S
##  not complete, returns a permutation not in S.
##
InstallGlobalFunction( SCRStrongGenTest,
    function ( S, param, orbits, basesize,
                               base, correct, missing)
    local   x,i,k,m,j,l,  # loop variables
            ran1,ran2,    # random permutations
            string,       # random 0-1 string
            w,            # list containing random subproducts of generators
            len,          # number of generators of S
            len2,         # length of short random subproduct
            mlimit,       # number of random elements to be tested
            ranword,      # random element of S as a word in generators
            residue,      # first component: remainder of ranword
                          # after factorization; second component > 0
                          # if factorization unsuccessful
            jlimit,       # number of random points to plug into residue[1]
            ran,          # index of random point in an orbit of S
            g;            # product of residue[1]

    k := 0;
    while k < param[1] do
        k := k+1;
        len := Length(S.aux);
        #in case of large S.aux, form random subproducts
        #otherwise, try all of them
        if len > 2*param[3] then
            ran1 := SCRRandomPerm(len);
            ran2 := SCRRandomPerm(len);
            len2 := Random(1, QuoInt(len,2));
            string := SCRRandomString(len+len2);

            # we form two random subproducts:
            # w[1] in a random ordering of all generators
            # w[2] in a random ordering of a random subset of them
            w:=[];
            w[1] := S.identity;
            for x in [1 .. len] do
                w[1] := w[1]*(S.aux[x^ran1]^string[x]);
            od;
            w[2] := S.identity;
            for x in [1 .. len2] do
                w[2] := w[2]*(S.aux[x^ran2]^string[x+len]);
            od;

        else
            # take next two generators of S (unless only one is left)
            w := [];
            w[1] := S.aux[2*k-1];
            if len > 2*k-1 then
                w[2] := S.aux[2*k];
            else
                w[2] := S.identity;
            fi;
        fi;

        # take random elements of S as words
        m := 0;
        mlimit := param[2]*S.diam;
        while m < mlimit do
            m:=m+1;
            ranword := RandomElmAsWord(S);
            i := 0;
            while i < 2 do
                i := i+1;
                if w[i] <> S.identity then
                    Append(ranword,[w[i]]);
                    residue := SiftAsWord(S,ranword);
                    if residue[2]>0 then
                        # factorization is unsuccessful;
                        # remainder is witness that SGS for S is not complete
                        g := Product(residue[1]);
                        # Print("k=",k," i=",i," m=",m," mlimit=",mlimit,"\n");
                        return g;
                    elif correct then
                        # enough to check whether base points are fixed
                        l:=0;
                        while l < Length(missing) do
                            l:=l+1;
                            if ImageInWord(missing[l],residue[1])
                              <> missing[l]
                            then
                                # remainder is not in S
                                g := Product(residue[1]);
                                return g;
                            fi;
                        od;
                    else
                        # plug in points from each orbit to check whether
                        # action on orbit is trivial
                        l:=0;
                        while l < Length(orbits) do
                            l:=l+1;
                            if Length(orbits[l]) > param[5] then
                                # on large orbits, plug in random points
                                j := 0;
                                jlimit := Maximum(param[6],basesize[l]);
                                while j < jlimit do
                                    j := j+1;
                                    ran := Random(1, Length(orbits[l]));
                                    if ImageInWord(orbits[l][ran],residue[1])
                                      <> orbits[l][ran]
                                    then
                                        #remainder is not in S
                                        g := Product(residue[1]);
                                        return g;
                                    fi;
                                od; #j loop
                            else
                                # on small orbits, plug in all points
                                j := 0;
                                while j < Length(orbits[l]) do
                                    j := j+1;
                                    if ImageInWord( orbits[l][j],residue[1] )
                                      <> orbits[l][j]
                                    then
                                        # remainder is not in S
                                        g:=Product(residue[1]);
                                        return g;
                                    fi;
                                od; #j loop
                            fi;
                        od; #l loop
                    fi;
                fi;
            od; #i loop
        od; #m loop
        if len <= 2*k then
            #finished making Schr. generators with all in S.aux
            k := param[1];
        fi;
    od; #k loop

    return S.identity;
end );


#############################################################################
##
#F  SCRSift( <S>, <g> ) . . . . . . . . . . . . . . . . . . . . . . . . local
##
##  tries to factor g as product of cosetreps in S; returns remainder
##
InstallGlobalFunction( SCRSift, function(S,g)
     local result;

     if not IsInternalRep( g ) then
       return SiftedPermutation(S, g);
     fi;

     result :=  SCR_SIFT_HELPER(S, g, Maximum(LargestMovedPoint(g),LargestMovedPoint(S!.generators)));

#     Assert(2,result = SiftedPermutation(S, g));
     return result;
end);



#############################################################################
##
#F  SCRStrongGenTest2( <S>, <param> ) . . . . . . . . . . . . . . . . . local
##
##  tests whether product of a random element of S and a random subproduct of
##  the  strong generators of S is  in S.  Computations  are carried out with
##  complete permutations.
##
InstallGlobalFunction( SCRStrongGenTest2, function ( S, param )
    local   x,i,k,m,      # loop variables
            ran1,ran2,    # random permutations
            string,       # random 0-1 string
            w,            # list containing random subproducts of generators
            len,          # number of generators of S
            len2,         # length of short random subproduct
            mlimit,       # number of random elements to be tested
            ranelement,   # random element of S
            T,  p,
            residue;      # remainder of ranelement after factorization

    k := 0;
    while k < param[3] do
        k := k+1;
        len := Length(S.aux);
        #in case of large S.aux, form random subproducts
        #otherwise, try all of them
        if len > 2*param[3] then
            ran1 := SCRRandomPerm(len);
            ran2 := SCRRandomPerm(len);
            len2 := Random(1, QuoInt(len,2));
            string := SCRRandomString(len+len2);

            # we form two random subproducts:
            # w[1] in a random ordering of all generators
            # w[2] in a random ordering of a random subset of them
            w:=[];
            w[1] := S.identity;
            for x in [1 .. len] do
                w[1] := w[1]*(S.aux[x^ran1]^string[x]);
            od;
            w[2] := S.identity;
            for x in [1 .. len2] do
                w[2] := w[2]*(S.aux[x^ran2]^string[x+len]);
            od;

        else
            # take next two generators of S (unless only one is left)
            w := [];
            w[1] := S.aux[2*k-1];
            if len > 2*k-1 then
                w[2] := S.aux[2*k];
            else
                w[2] := S.identity;
            fi;
        fi;

        # take random elements of S
        m := 0;
        mlimit := param[4]*S.diam;
        while m < mlimit do
            m:=m+1;
            ranelement := S.identity;
            T := S;
            while Length( T.generators ) <> 0  do
                p := Random( T.orbit );
                while p <> T.orbit[ 1 ]  do
                    ranelement := LeftQuotient( T.transversal[ p ],
                                          ranelement );
                    p := p ^ T.transversal[ p ];
                od;
                T := T.stabilizer;
            od;
            i := 0;
            while i < 2 do
                i := i+1;
                if w[i] <> S.identity then
                    # test whether product of ranelement and w[i] in S
                    ranelement := ranelement*w[i];
                    residue := SCRSift(S,ranelement);
                    if residue <> S.identity then
                        return residue;
                    fi;
                fi;
            od; #i loop
        od; #m loop
        if len <= 2*k then
            #finished checking all in S.aux
            k := param[3];
        fi;
    od; #k loop

    return S.identity;
end );


#############################################################################
##
#F  SCRNotice( <orb>, <transversal>, <genlist> )  . . . . . . . . . . . local
##
##  checks whether   orbit  is closed  for  the   action of  permutations  in
##  genlist. If not, returns orbit point and generator witnessing.
##
InstallGlobalFunction( SCRNotice,
    function ( orb, transversal, genlist )
    local flag, #first component of output; true if orb is closed for
                #action of genlist
          i,    #second component of output, index of point in orb moving out
          j ;   #third component, index of permutation in genlist moving orb[i]

    i := 0;
    flag := true;
    while i < Length(orb) and flag  do
        i := i+1;
        j := 0;
        while j < Length(genlist) and flag do
            j := j+1;
            if not IsBound(transversal[orb[i]^genlist[j]])  then
                flag := false;
            fi;
        od;
    od;

    return [flag,i,j];
end );


#############################################################################
##
#F  SCRExtend( <list> ) . . . . . . . . . . . . . . . . . . . . . . . . local
##
##  given a partial Schreier tree of depth d,
##  SCRExtends the partial Schreier tree to depth d+1
##  input, output coded in list of length 5
##
InstallGlobalFunction( SCRExtend, function ( list )
    local orb,          #partial orbit
          transversal,  #partial transversal
          treegen,      #list of generators
          treegeninv,   #inverses of elements of treegen
                        #both treegen, treegeninv are used in transversal
          i, j,         #loop variables
          previous,     #index, showing end of level d-1 in orb
          len;          #length of orb at entering routine

    orb:=list[1];
    transversal:=list[2];
    treegen:=list[3];
    treegeninv:=list[4];
    previous:=list[5];
    len:=Length(orb);

    # for each point on level d, check whether one of the generators or
    # inverses moves it out of orb. If yes, add image to orb
    for i in [previous+1..len] do
        for j in [1..Length(treegen)] do
            if not IsBound(transversal[orb[i]^treegen[j]]) then
                transversal[orb[i]^treegen[j]] := treegeninv[j];
                Add(orb, orb[i]^treegen[j]);
            fi;
            if not IsBound(transversal[orb[i]^treegeninv[j]]) then
                transversal[orb[i]^treegeninv[j]] := treegen[j];
                Add(orb, orb[i]^treegeninv[j]);
            fi;
        od;
    od;

    # return Schreier tree of depth one larger
    return [orb,transversal,treegen,treegeninv,len];

end );


#############################################################################
##
#F  SCRSchTree( <S>, <new> )  . . . . . . . . . . . . . . . . . . . . . local
##
##  creates Schreier tree for the group generated by S.generators \cup new
##
InstallGlobalFunction( SCRSchTree, function ( S, new )
    local l,        #output of notice
          flag,     #first component of output
          i,        #second component of output
          j,        #third component of output
          word,     #list of permutations coding a coset representative
          g,        #the coset representative coded by word
          witness,  #a permutation moving a point out of S.orbit
          list;     #list coding input and output of 'extend'

    l := SCRNotice(S.orbit,S.transversal,new);
    flag := l[1];
    if flag then
        #do nothing; the orbit did not change
        return;
    else
        i := l[2];
        j := l[3];
        witness := new[j];
    fi;

    while not flag do
        word := CosetRepAsWord(S.orbit[1],S.orbit[i],S.transversal);
        g := Product(word);
        #add a new generator to treegen which moves S.orbit[1] out of S.orbit
        Add(S.treegen, g^(-1)*witness);
        Add(S.treegeninv, witness^(-1)*g);

        #recompute Schreier tree to new depth
        S.orbit := [S.orbit[1]];
        S.transversal := [];
        S.transversal[S.orbit[1]] := S.identity;
        S.treedepth := 0;
        list := [S.orbit,S.transversal,S.treegen,S.treegeninv,0];
        flag := false;

        #with k generators, we build only a tree of depth 2k
        while not flag and S.treedepth < 2*Length(S.treegen) do
            list := SCRExtend(list);
            S.orbit := list[1];
            S.transversal := list[2];
            if Length(S.orbit) = list[5] then
                #the tree did not extend; orbit is closed for treegen
                flag := true;
            else
                S.treedepth := S.treedepth + 1;
            fi;
        od;
        #increased S.orbit may not be closed for all generators of S
        l := SCRNotice(S.orbit,S.transversal,S.generators);
        flag := l[1];
        if not flag then
            i := l[2];
            j := l[3];
            witness := S.generators[j];
        fi;
    od;

    #update record components aux, diam
    S.aux := Concatenation(S.treegen,S.treegeninv,S.stabilizer.aux);
    S.diam := S.treedepth+S.stabilizer.diam;

end );


#############################################################################
##
#F  SCRRandomPerm( <d> )  . . . . . . . . . . . . . . . . . . . . . . . local
##
##  constructs random permutation in Sym(d)
##  without creating group record of Sym(d)
##
InstallGlobalFunction( SCRRandomPerm, function ( d )
    local   rnd,        # random permutation, result
            tmp,        # temporary variable for swapping
            i,  k;      # loop variables

    # use Floyd\'s algorithm
    rnd := [ 1 .. d ];
    for i  in [ 1 .. d-1 ]  do
        k := Random( 1, d+1-i );
        tmp := rnd[d+1-i];
        rnd[d+1-i] := rnd[k];
        rnd[k] := tmp;
    od;

    # return the permutation
    return PermList( rnd );
end );


#############################################################################
##
#F  SCRRandomString( <n> )  . . . . . . . . . . . . . . . . . . . . . . local
##
##  constructs random 0-1 string of length n
##  same steps as Random, but uses created random number for 28 bits
##
InstallGlobalFunction( SCRRandomString, function ( n )
    local i, j,     # loop variables
          k,        # number of 28 long substrings
          rnd,      # the random number which would be created by Random
          string,   # the random string constructed
          range;    # Upper value of range used for getting ints

    range := 2^28-1;

    string:=[];
    k:=QuoInt(n-1,28);
    for i in [0..k-1] do
        rnd := Random(0,range);
        # use each bit of rnd
        for j in [1 .. 28] do
            string[28*i+j] := rnd mod 2;
            rnd := QuoInt(rnd,2);
        od;
    od;

    # construct last <= 28 bits  of string
    rnd := Random(0, range);
    for j in [28*k+1 .. n] do
        string[j] := rnd mod 2;
        rnd := QuoInt(rnd,2);
    od;

    return string;
end );

#############################################################################
##
#F  SCRRandomSubproduct( <list>, <id> ) .  random subproduct of perms in list
##
InstallGlobalFunction( SCRRandomSubproduct, function( list, id )
    local string,  # 0-1 string containing the exponents of elements of list
          random,  # the random subproduct
          i;       # loop variable

    string := SCRRandomString(Length(list));
    random := id;
    for i in [1 .. Length(list)] do
        if string[i] = 1 then
            random := random*list[i];
        fi;
    od;

    return random;
end );

#############################################################################
##
#F  SCRExtendRecord( <G> )  . . . . . . . . . . . . . . . . . . . . . . local
##
##  defines record elements used at random stabilizer chain construction
##
InstallGlobalFunction( SCRExtendRecord, function(G)
    local list,       # list of stabilizer subgroups
          len,        # length of list
          i;          # loop variable

    list := ListStabChain(G);
    len := Length(list);
    list[len].diam := 0;
    list[len].aux := [];
    for i in [1 .. len - 1] do
        # list[len - i].real := list[len - i].generators;

        if Length(list[len - i].orbit) = 1 then
            # in this case, SCRSchTree will not do anything;
            # we have to define records treedepth, aux, and diameter
            list[len - i].treedepth := 0;
            list[len - i].aux := list[len - i + 1].aux;
            list[len - i].diam := list[len - i + 1].diam;
        fi;

        list[len - i].orbit := [ list[len - i].orbit[1] ];
        list[len - i].transversal := [];
        list[len - i].transversal[list[len - i].orbit[1]]
            := list[len - i].identity;
        list[len - i].treegen := [];
        list[len - i].treegeninv := [];
        SCRSchTree( list[len - i], list[len - i].generators );

    od;

end );


#############################################################################
##
#F  SCRRestoredRecord( <G> )  . . . . . . . . . . . . . . . . . . . . . local
##
##  restores usual group records after random stabilizer chain construction
##
InstallGlobalFunction( SCRRestoredRecord, function( G )
    local   sgs,  T,  S,  l,  pnt,o,ind;

    S := G;
    sgs := [ S.identity ];
    while IsBound( S.stabilizer )  do
        UniteSet( sgs, S.treegen );
        UniteSet( sgs, S.treegeninv );
        S := S.stabilizer;
    od;
    T := EmptyStabChain( sgs, G.identity );
    sgs := [ 2 .. Length( sgs ) ];
    S := T;
    while IsBound( G.stabilizer )  do
        InsertTrivialStabilizer( S, G.orbit[ 1 ] );
        S.genlabels   := sgs;
        S.generators  := G.generators;
        S.orbit       := G.orbit;
        S.transversal := G.transversal;
        o:=ShallowCopy(S.orbit);
        # check identity of transversal elements first: Most are
        # identical and thus element comparisons are relatively
        # infrequent
        while Length(o)>0 do

          ind:=S.transversal[o[1]];
          ind:=Filtered([1..Length(o)],
                  i->IsIdenticalObj(S.transversal[o[i]],ind));
          for l in sgs do
            if S.transversal[o[1]]=S.labels[l] then
              for pnt in o{ind} do # all these transv. elements are same
                S.translabels[ pnt ] := l;
              od;
            fi;
          od;
          o:=o{Difference([1..Length(o)],ind)}; # the rest
        od;

            #was:
            # (The element comparisons could be expensive)
            #for pnt  in S.orbit  do
            #    if S.transversal[ pnt ] = lab  then
            #        S.translabels[ pnt ] := l;
            #    fi;
            #od;

        sgs := Filtered( sgs, l ->
                       S.orbit[ 1 ] ^ S.labels[ l ] = S.orbit[ 1 ] );
        S := S.stabilizer;
        G := G.stabilizer;
    od;
    return T;
end );

#############################################################################
##
#F  VerifyStabilizer( <S>, <z>, <missing>, <correct> )  . . . .  verification
##
InstallGlobalFunction( VerifyStabilizer, function(S,z,missing,correct)
 #z is an involution, moving first base point
 # correct is boolean telling whether a base is known
 # if yes, missing contains the base points which do not occur in the base of S
 local pt1,            # the first base point
       zinv,           # inverse of z
       pt2,            # pt1^zinv
       flag,           # Boolean; true if z exchanges pt1 and pt2
       stab,           # the stabilizer of pt1 in S
       chain,          # stab after base change, to bring pt2 first
       stabpt2,        # stabilizer of pt2 in chain
       result,         # output, witness perm if something is wrong
       g,              # generator of stabpt2
       where1,         # stores which orbit of stab pts of S.orbit belong to
       orbit1count,    # index running through orbits of stab
       leaders,        # list of orbit representatives of stab
       i, j, l,        # loop variables
       residue,        # result of sifting as word
       where2,         # boolean list to mark orbits of stabpt2 as processed
       k,              # point of an orbit of stab
       gen,            # a generator of stab
       transversal,    # transversal of stab, on all of its orbits
       orb,            # an orbit of stabpt2
       img,            # image of a point at computation of orb
       pnt,            # a point from orb
       w1, w2, w3, w4, # words/permutations coding coset representatives
       w1inv,          # inverse of w1
       schgen;         # Schreier generator

    pt1 := S.orbit[1];
    zinv := z^(-1);
    pt2 := pt1^zinv;
    result := S.identity;
    stab := S.stabilizer;
    if pt2^zinv = pt1 then
       flag := true;
       result := SCRSift(stab, z^2);
    else
       flag := false;
    fi;

    # store which orbit of stab the pts of S.orbit belong to
    # in each orbit, compute transversals from a representative
    where1 := []; # orbits of stab
    leaders := [pt2];
    orbit1count := 1;
    transversal := [];
    transversal[pt2] := S.identity;
    where1[pt2] := 1;
    orb := [pt2];
    j := 1;
    while j <= Length( orb )  do
    for gen  in stab.generators  do
       k := orb[j] / gen;
       if not IsBound( transversal[k] )  then
             transversal[k] := gen;
             Add( orb, k );
             where1[k] := orbit1count;
          fi;
       od;
       j := j + 1;
    od;
    for i in S.orbit do
        if not IsBound(where1[i]) then
           orbit1count := orbit1count + 1;
           Add(leaders, i);
           orb := [i];
           where1[i] := orbit1count;
           transversal[i] := S.identity;
           j := 1;
           while j <= Length( orb )  do
             for gen  in stab.generators  do
                 k := orb[j] / gen;
                 if not IsBound( transversal[k] )  then
                    transversal[k] := gen;
                    Add( orb, k );
                    where1[k] := orbit1count;
                 fi;
             od;
             j := j + 1;
           od;
        fi;
    od;

   # check that conjugates of point stabilizers of stab are subgroups of stab
   chain:=StructuralCopy(stab);
   for j in [1..Length(leaders)] do
       if result = S.identity then
           i := leaders[Length(leaders)+1-j];
           ChangeStabChain( chain, [i], false );
           if i = pt2 then
              w1 := z;
              w1inv := zinv;
           else
              w1 := CosetRepAsWord(pt1, i, S.transversal);
              w1 := Product(w1);
              w1inv := w1^(-1);
           fi;
           for g in chain.stabilizer.generators do
               if result = S.identity then
                  if correct then
                     residue := SiftAsWord(stab, [w1inv,g,w1]);
                     if residue[2] <> 0 then
                        result := Product(residue[1]);
                     else
                        l := 0;
                        while ( l < Length(missing) ) and ( result = S.identity ) do
                           l:=l+1;
                              if ImageInWord(missing[l],residue[1])
                                  <> missing[l]  then
                                  # remainder is not in S
                                  result := Product(residue[1]);
                              fi;
                        od;
                     fi;
                  else
                     result := SCRSift(stab, w1inv*g*w1);
                  fi;
               fi;
           od;
       fi;
   od;

 if result = S.identity then
    stabpt2 := chain.stabilizer;
    # process orbits of stabpt2
    where2:= BlistList( [1..Length(where1)],[] ) ;
    for i in S.orbit do
        if result = S.identity and (not where2[i]) then
           orb := [i];
           where2[i] := true;
           for pnt  in orb  do
               for gen  in stabpt2.generators  do
                   img := pnt^gen;
                   if not where2[img]  then
                      Add( orb, img );
                      where2[img] := true;
                   fi;
               od;
           od;

           # if we hit a new orbit of stabpt2
           # and if z exchanges pt1 and pt2 then
           # mark the orbit
           if flag and not where2[i^z] then
              orb := [i^z];
              where2[i^z] := true;
              for pnt  in orb  do
                 for gen  in stabpt2.generators  do
                    img := pnt^gen;
                    if not where2[img]  then
                       Add( orb, img );
                       where2[img] := true;
                    fi;
                 od;
              od;
           fi;

           # compute Schreier generator either as a word or perm
           # if i is not a fixed point of z,
           # we have to compute a Schreier generator
           w1 := CosetRepAsWord(pt1, leaders[where1[i]], S.transversal);
           w2 := CosetRepAsWord(leaders[where1[i]], i, transversal);
           w3 := CosetRepAsWord(leaders[where1[i^z]], i^z, transversal);
           if where1[i] <> where1[i^z] then
               w4 := CosetRepAsWord(pt1,leaders[where1[i^z]], S.transversal);
           else
               w4 := w1;
           fi;
           schgen := (Product(w1))^(-1)*(Product(w2))^(-1);
           if correct then
               schgen := Concatenation([schgen,z],w3,w4);
           else
               schgen := schgen*z*Product(w3)*Product(w4);
           fi;

           # sift Schreier generator either as a word or perm
           if correct then
              residue := SiftAsWord(stab, schgen);
              if residue[2] <> 0 then
                 result := Product(residue[1]);
              else
                  l := 0;
                  while ( l < Length(missing) ) and ( result = S.identity ) do
                     l:=l+1;
                     if ImageInWord(missing[l],residue[1])
                               <> missing[l]  then
                          # remainder is not in S
                          result := Product(residue[1]);
                     fi;
                  od;
               fi;
           else
              result := SCRSift(stab, schgen);
           fi;
        fi;  # result = S.identity and not where2[i]
     od;
 fi;

 return result;

end );

#############################################################################
##
#F  VerifySGS( <S>, <missing>, <correct> )  . . . . . . . . . .  verification
##
InstallGlobalFunction( VerifySGS, function(S,missing,correct)
 # correct is boolean telling whether a base is known
 # if yes, missing contains the base points which do not occur in the base of S
 local n,         # degree of S
       list,      # list of subgroups in stabchain
       result,    # result of the test
       len,       # length of list
       i,l,       # loop variables
       residue,   # result of sifting as word
       temp,      # subgroup of S we currently work with
       temp2,     # temp, with possible extension on blocks
       gen,       # the generator whose addition we verify
       longer,    # generator list of temp, after gen is added
       gencount,  # counts the generators to be verified
       set,       # set of orbit of temp
       orbit,     # orbit of temp after adding gen
       blks,      # images of block when gen is added
       extension, # list of length 2; first coord. is temp2, extended by
                  # the action on blks, second coord. is newgen
       newgen,    # the extension of gen
       leader,    # first point in orbit of temp2
       block,     # block containing leader
       point,     # another point from block
       pos;       # position of set in blks

 n := LargestMovedPoint(S.generators);
 list := ListStabChain(S);
 len := Length(list);
 result := S.identity;

 # verify the subgroup chain from bottom up
 i := 1;
 while i < len  and  result = S.identity  do
     temp := ShallowCopy(list[len - i + 1]);
     InsertTrivialStabilizer(temp, list[len -i].orbit[1]);
     gencount := 0;

     # add one generator a time
     while (gencount < Length(list[len - i].generators)) and (result= S.identity ) do
         gencount := gencount + 1;
         gen := list[len - i].generators[gencount];
         set := Set( temp.orbit );

         # if adding gen did not change the fundamental orbit, just sift gen
         if set = OnSets(set,gen) then
            if correct then
               residue := SiftAsWord(temp, [gen]);
               if residue[2] <> 0 then
                  result := Product(residue[1]);
               else
                  l := 0;
                  while ( l < Length(missing) ) and ( result = S.identity ) do
                     l:=l+1;
                     if ImageInWord(missing[l],residue[1])
                               <> missing[l]  then
                          # remainder is not in S
                          result := Product(residue[1]);
                     fi;
                  od;
               fi;
            else
               result := SCRSift(temp, gen);
            fi;
         # if the fundamental orbit increased, compute block system
         # obtained when adding gen
         else
            if Length(set) =1 then
                temp2 := temp;
                newgen := gen;
            # otherwise, compute the action on blocks
            else
                longer := Concatenation(temp.generators, [gen]);
                orbit := OrbitPerms( longer, temp.orbit[ 1 ] );
                blks := Blocks( GroupByGenerators( longer ), orbit, set );
                if Length(blks) * Length(set) <> Length(orbit) then
                    result := "false0";
                else
                    pos := Position( blks, set );
                    extension := ExtensionOnBlocks( temp, n, blks, [gen] );
                    temp2 := extension[1];
                    newgen := extension[2][1];
                    InsertTrivialStabilizer(temp2, n + pos);
                fi;
            fi;

            # first generator in first group can be verified easily
            if i=1 and Length(set) =1 then
                result := newgen^(CycleLengthOp(newgen,temp2.orbit[1]));
                AddGeneratorsExtendSchreierTree(temp2, [newgen]);
            elif result = S.identity then
                AddGeneratorsExtendSchreierTree( temp2, [ newgen ] );
                blks := Blocks( GroupByGenerators(temp2.generators),
                                temp2.orbit);
                if Length(blks) > 1 then
                   leader := temp2.orbit[1];
                   block := First(blks, x -> leader in x);
                   point := First(block, x -> x <> leader);
                   newgen := Product(CosetRepAsWord(leader ,point,
                                       temp2.transversal));
                   temp2 := temp2.stabilizer;
                   InsertTrivialStabilizer(temp2, leader);
                   AddGeneratorsExtendSchreierTree(temp2, [newgen]);
                   result := VerifyStabilizer(temp2,newgen,missing,correct);
                   if leader > n then
                      AddGeneratorsExtendSchreierTree(temp,[RestrictedPermNC
                          (newgen, [1..n])]);
                   else
                      temp := temp2;
                   fi;
                   gencount := gencount - 1;
                else
                   result := VerifyStabilizer(temp2,newgen,missing,correct);
                   if temp2.orbit[1] > n then
                      AddGeneratorsExtendSchreierTree(temp,[gen]);
                   fi;
                fi;
                if result <> S.identity and temp2.orbit[1] > n then
                     result := RestrictedPermNC(result, [1..n]);
                fi;

            fi;
        fi;
    od;
    i := i + 1;
 od;

 return result;

end );

#############################################################################
##
#F  ExtensionOnBlocks( <S>, <n>, <blks>, <elms> ) . . . . . . . . . extension
##
InstallGlobalFunction( ExtensionOnBlocks, function( S, n, blks, elms )
    local   where,  j,  k,  hom,  T,  newelms;

      # list which block the elements of the orbit belong to
      where := [];
      for j in [1..Length(blks)] do
          for k in blks[j] do
              where[k] := j;
          od;
      od;

      hom := function( g )
          local  perm,  j;

          perm := [1..n];
          for j in [1..Length(blks)] do
              perm[n+j] := n+where[blks[j][1]^g];
          od;
          perm := PermList(perm);
          return g * perm;
      end;

      T := EmptyStabChain( [  ], S.identity );
      ConjugateStabChain( S, T, hom, S.identity );

      # construct extensions of permutations in elms
      newelms := List( elms, hom );

      return [ T, newelms ];
end );

#############################################################################
##
#F  ClosureRandomPermGroup( <G>, <genlist>, <options> ) make closure randomly
##
InstallGlobalFunction( ClosureRandomPermGroup,
    function( G, genlist, options )
    local  k,          # number of pairs of subproducts of generators in
                       # testing result
           givenbase,  # ordering from which initial base points should
                       # be chosen
           gens,       # generators in genlist that are not in <G>
           g,          # element of gens
           degree,     # degree of closure
           orbits,     # list of orbits of closure
           orbits2,    # list of orbits of closure
           i,j,        # loop variables
           param,       # list of parameters guiding number of repetitions
                        # in random constructions
           where,       # list indicating which orbit contains points in domain
           basesize,    # list; i^th entry = number of base points in orbits[i]
           ready,       # boolean; true if stabilizer chain ready
           new,         # list of permutations to be added to stab. chain
           result,      # output of checking phase; nontrivial if stabilizer
                        # chain is incorrect
           base,        # ordering of domain from which base points are taken
           missing,     # if a correct base was provided by input, missing
                       # contains those points of it which are not in
                       # constructed base
           cnt,        # iteration counter
           correct;     # boolean; true if a correct base is given

# warning:  options.base should be compatible with BaseOfGroup(G)

    gens := Filtered( genlist, gen -> not(IsOne(SCRSift(G,gen))) );
    if Length(gens) > 0  then

        G.identity := One(gens[1]) ;
        if options.random = 1000 then
            #case of deterministic computation with known size
            k := 1;
        else
            k:=First([1..14],x->(3/5)^x<1-options.random/1000);
        fi;
        if IsBound(options.knownBase) then
            param := [k,4,0,0,0,0];
        else
            param := [QuoInt(k,2),4,QuoInt(k+1,2),4,50,5];
        fi;
        if options.random <= 200 then
            param[2] := 2;
            param[4] := 2;
        fi;

#param[1] = number of pairs of random subproducts from generators in
#           first checking phase
#param[2] = (number of random elements from created set)/S.diam
#           in first checking phase
#param[3] = number of pairs of random subproducts from generators in
#           second checking phase
#param[4] = (number of random elements from created set)/S.diam
#           in second checking phase
#param[5] = maximum size of orbits in  which we evaluate words on all
#           points of orbit
#param[6] = minimum number of random points from orbit to plug in to check
#           whether given word is identity on orbit

        degree := LargestMovedPoint( Union( G.generators, gens ) );

        # prepare input of construction
        if IsBound(options.base) then
            givenbase := options.base;
        else
            givenbase := [];
        fi;

        if IsBound(options.knownBase) then
            correct := true;
        else
            correct := false;
        fi;

        if correct then
            # if correct  base was given as input,
            # no need for orbit information
            base := Set( givenbase );
            for i in BaseStabChain(G) do
                if not i in base then
                    Add( givenbase, i );
                fi;
            od;
            base := Concatenation(givenbase,Difference(options.knownBase,
                                                       givenbase));
            missing := Difference(options.knownBase,BaseStabChain(G));
            basesize := [];
            where := [];
            orbits := [];
        else
            # create ordering of domain used in choosing base points and
            # compute orbit information
            base := Set( givenbase );
            for i in BaseStabChain(G) do
                if not i in base then
                    Add( givenbase, i );
                fi;
            od;
            base := Concatenation(givenbase,Difference([1..degree],givenbase));
            missing := [];
            orbits2 := OrbitsPerms( Union( G.generators, gens ), [1..degree] );
            #throw away one-element orbits
            orbits:=[];
            j:=0;
            for i in [1..Length(orbits2)] do
                if Length(orbits2[i]) >1 then
                    j:=j+1; orbits[j]:= orbits2[i];
                fi;
            od;
            basesize:=[];
            where:=[];
            for i in [1..Length(orbits)] do
                basesize[i]:=0;
                for j in [1..Length(orbits[i])] do
                    where[orbits[i][j]]:=i;
                od;
            od;
            # temporary solution to speed up of handling
            # of lots of small orbits until compiler
            if Length(orbits) > degree/40 then
                param[1] := 0;
                param[3] := k;
            fi;
        fi;

        if not IsBound(G.aux) then
            SCRExtendRecord(G);
        fi;
        new := gens;

        #the first call of SCRMakeStabStrong has top:=false
        #in order to add gens to the generating set of G;
        #further calls have top:=true, in order not to add
        #output of SCRStrongGenTest to generating set.
        #remark: adding gens to the generating set of G before
        #calling SCRMakeStabStrong gives a nasty error if first base
        #point changes
        for g in gens do
            if not(IsOne(SCRSift(G,g))) then
                SCRMakeStabStrong (G,[g],param,orbits,
                        where,basesize,base,correct,missing,false);
            fi;
        od;

        cnt:=0;
        ready := false;
        while not ready do
          if    IsBound(options.limit)
            and SizeStabChain(G)=options.limit
          then
              ready := true;
          else
              # we do a little random testing, to ensure heuristically a
              # correct result
              if correct then
                  result := SCRStrongGenTest(G,[1,10/G.diam,0,0,0,0],orbits,
                                      basesize,base,correct,missing);
              else
                  result := SCRStrongGenTest2(G,[0,0,1,10/G.diam,0,0]);
              fi;
              if not(IsPerm(result) and IsOne(result)) then
                  new := [result];
                  ready := false;
              elif options.random = 1000 then
                  G.restored := SCRRestoredRecord(G);
                  result := VerifySGS( G.restored, missing, correct );
                  cnt:=cnt+1;
                  if cnt>99 then
                    # in rare cases this loop iterates for a very long time.
                    # In this case, rather create a new chain, than try to
                    # fix the problematic one
                    #Error("infinite loop?");
                    return StabChainRandomPermGroup(G.generators,G.identity,
                            options);
                  fi;
              elif options.random > 0 then
                  result := SCRStrongGenTest
                          (G,param,orbits,basesize,base,correct,missing);
              fi;
              if not(IsPerm(result) and IsOne(result)) then
                  if not IsPerm(result) then
                     repeat
                         result := SCRStrongGenTest2(G,[0,0,1,10/G.diam,0,0]);
                     until not(IsPerm(result) and IsOne(result));
                  fi;
                  new := [result];
                  ready := false;
              elif correct or options.random = 0 or options.random = 1000 then
                  ready := true;
              else
                  result := SCRStrongGenTest2(G,param);
                  if IsPerm(result) and IsOne(result) then
                      ready := true;
                  else
                      new := [result];
                      ready := false;
                  fi;
              fi;
              if not ready then
                Unbind(G.restored);
                SCRMakeStabStrong (G,new,param,orbits,
                        where,basesize,base,correct,missing,true);
                #Print("D ",SizeStabChain(G),"\n");
              fi;
          fi;
        od;

        if not IsBound(options.temp) or options.temp = false then
             if IsBound( G.restored ) then
                G := G.restored;
             else
                G := SCRRestoredRecord(G);
             fi;
        else
             G.basesize := basesize;
             G.correct := correct;
             G.orbits := orbits;
             G.missing := missing;
             G.base := base;
        fi;

    fi; # if Length(gens) > 0


    # return the closure
    return G;

end );

#############################################################################



[ Verzeichnis aufwärts0.56unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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