Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/guarana/tst/completeOldCode/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 11.1.2022 mit Größe 42 kB image not shown  

Quelle  bch.g   Sprache: unbekannt

 
Spracherkennung für: .g vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

#############################################################################
#
#                                                                 7.10.2005
# Code for the computation of coefficients of the BCH-series
# in k variables. That is, we compute an expression for z in

# exp(y_1)* exp(y_2) *...* exp(y_k) = exp( z ) 

# First we compute z as a polynomial in the x_i. For this purpose,
# we use the paper of Reinsch "A simple expression for the terms in the
# Baker-Campbell-Hausdorff series"
#
# These terms have now to be converted in expression containing only
# Lie brackets. It is not clear to me, how you can do this for k variables,
# but this is also not really needed. 
# What is is more important for us is the case
#
# Long Commutator in exp( y_1 ),exp(y_2)  = exp( z )
#
# For this we replace the y_i by y_1,-y_1,y_2,-y_2.
#
# The resulting polynomial in y_1,y_2 can be transformed into an 
# expression using Lie brackets in y_1, y_2 with the trick of Vaughan-Lee
#
# The aim of all this, is the computation of structure constants and
# an efficient log and exp. We use
#
# [logx,logy]= log( [x,y] ) + higher commutators in x,y           (*)
#
# Maybe it is possible to compute a series for this, i.e. we would
# get [logx,logy] = Q-linear combination of logs of group commutators.
# Approach: Compute this expression for a group of fixed nilpotency 
# class. Then we can probably show that a group of nilpotency class
# c+1 contains the old series plus some new terms. 
# We can compute this by replacing in (*) the higher commutators in x,y
# chi(x,y)_L by chi(x,y)_G + higher commutators in x,y, which we 
# compute with the extended BCH-series.
#  
# Maybe we can also find a formula for log applied to 
# g_1^e_1 * ... * g_k^e_k where k varies between 1 and 10. 
# What we need for this is exactly the Lie bracket expression for 
# z in exp(z) = exp(y_1) * ... exp( y_n )
#
# TODO: 
# - BCH series for any commutator in x,y
#   (also possible with Reinsch by using F,F^-1,G,G^-1)
# - BCH in k variable can be used for efficient log.
#   Can we deal with elements of the factors of the upper central
#   series simultaneously ? 
#   If you have a group of class 7 with 60 generators, it would 
#   be an overkill to use the BCH formula in 60 Variables!
# - Should we use basic commutators for all series ?

#############################################################################
#
# IN: v ..... upper or lower trinagular matrix with 0s on the diagonal
#
# OUT: exp(x)
#
BCH_Exponential := function( A, v )
    local n,exp, vPow, fac, i;
    n := Length( v[1] );
    exp := One( A )* IdentityMat(n) + v;
    vPow := v;
    fac := 1;
    for i in [2..n-1] do
        vPow := vPow*v;
        fac := fac*i;
        exp := exp + (fac^-1)*vPow;
    od;
    return exp;
end;

#############################################################################
#
# IN: x ..... upper or lower trinagular matrix with ones on the diagonal
#
# OUT: log(x)
#
BCH_Logarithm := function( x )
    local n,mat,matPow,log,i;
    n := Length( x[1] );
    mat := x - x^0;
    matPow := mat;
    log := mat;
    for i in [2..n-1] do
        matPow := matPow*mat;
        log := log + (-1)^(i-1)*(i)^-1*matPow;
    od;
    return log;
end;

#############################################################################
#
# matrix F as in paper of Reinsch 
#
BCH_Compute_F := function( n )
    local F,i,j;
    F := IdentityMat( n+1 );
    for i in [1..n+1] do
        for j in [i+1..n+1] do
            F[i][j] := 1/Factorial( j-i );
        od;
    od;
    return F;
end;

# compute F^pow where pow = +- 1
BCH_Compute_F_Power := function( n, pow )
    local mat,i,F_pow;
    mat := 0*IdentityMat( n+1 );
    for i in [1..n] do
        mat[i][i+1] := 1;
    od;
    F_pow := BCH_Exponential( Rationals, pow*mat ); 
    return F_pow;
end;

BCH_Compute_G := function( n, PolRing )
    local G,i,j,prod,I;
    I := IndeterminatesOfPolynomialRing( PolRing );
    G := IdentityMat( n+1 );
    for i in [1..n+1] do
        for j in [i+1..n+1] do
            prod := Product( I{[i..j-1]} );
            G[i][j] := 1/Factorial( j-i )* prod;
        od;
    od;
    return G;
end;

# compute G^pow where pow = +- 1
BCH_Compute_G_Power := function( n, PolRing, pow )
    local mat,i,G_pow,I;
    mat := 0*IdentityMat( n+1 );
    I := IndeterminatesOfPolynomialRing( PolRing );
    for i in [1..n] do
        mat[i][i+1] := I[i];
    od;
    G_pow := BCH_Exponential( Rationals, pow*mat ); 
    return G_pow;
end;



BCH_Compute_H := function( n, PolRing )
    local H,i,j,prod,I;
    I := IndeterminatesOfPolynomialRing( PolRing );
    H := IdentityMat( n+1 );
    for i in [1..n+1] do
        for j in [i+1..n+1] do
            prod := Product( I{[(i+n)..(j+n-1)]} );
            H[i][j] := 1/Factorial( j-i )* prod;
        od;
    od;
    return H;
end;

#############################################################################
#
# IN: mat ............ unipotent matrix
#     pow ............ rational number

# OUT: mat^pow
BCH_RationalPowerOfUnipotentMat := function( mat, pow )
    local log;
    log := BCH_Logarithm( mat );
    return BCH_Exponential( Rationals, pow*log ); 
end;


#############################################################################
#
# Extension of the code of Reinsch. We do computations with k variables
#
# IN:
# n ...........  n-th term of the extended BCH series should be computed
# k ...........  k variables, i.e. exp(y_1)*...*exp(y_k)= exp(z)
# A ...........  Free associative algebra with one containing the y_i
#
# For simplification of the programming we replace the matrix F, which 
# originally does not contain varialbles with one similar to G, 
# i.e. we get a list of k matrices called H, whose i-th matrix
# contains only y_i
#
#A := FreeAssociativeAlgebraWithOne( Rationals, k, "x" );
#
BCH_Compute_HMatrices := function( n, k, A )
    local gens,i,j,mat,H;
    gens := GeneratorsOfAlgebraWithOne( A );
    H := [];
    for i in [1..k] do
        mat := Zero( A ) * IdentityMat( n+1 );
        for j in [1..n] do
            mat[j][j+1] := gens[i];
        od; 
        H[i] := BCH_Exponential( A, mat );
    od;
    return H;
end;


# typical input string = "1/180*x_1*x_2*x_5"
BCH_SigmaExpression2XY := function( n, string, A )
    local ll,k,gens,monomial,start,ll2,i,rat;

    ll := SplitString( string, "*" );
    k := Length( ll );

    #check if start with rational number
    rat := 1;
    start := 1;
    if ll[1][1] <> 'x' then;
        rat := Rat( ll[1] );
        start := 2;
    fi;

    ll2 := List( [start..k], x-> Int( ll[x]{[3]}) );

    # compute monomial
    gens := GeneratorsOfAlgebra( A ); 
    monomial := gens[1];
    for i in [1..n] do
        if i in ll2 then
            monomial := monomial*gens[3];
        else
            monomial := monomial*gens[2];
        fi;
    od;
    return rat*monomial;
end;

#############################################################################
#
# Operator T corresponding to Reinsch
# IN
# string ..........  polynomial in sigmaexpressions 
#                    typical input string = "1/180*x_1*x_2*x_5"
# OUT
# result of operator T.

# Example:
# gap> BCH_SigmaExpression2List( 7, "1/180*x_1*x_2*x_5" );
# [ 1/180, [ 2, 2, 1, 1, 2, 1, 1 ] ]
#
BCH_SigmaExpression2List := function( n, string )
    local ll,k,start,ll2,i,rat,result;

    ll := SplitString( string, "*" );
    k := Length( ll );

    #check if start with rational number or minus sign
    rat := 1;
    start := 1;
    if ll[1][1] <> 'x' then
        if ll[1][1] = '-' and ll[1][2] = 'x' then
            rat := -1;
            ll[1] := ll[1]{[2..Length(ll[1])]};
        else
            rat := Rat( ll[1] );
            start := 2;
        fi;
    fi;

    # extract indices
    ll2 := List( [start..k], 
            x-> Int( ll[x]{[3..Length(ll[x])]}) );

    # compute monomial
    result := [];
    for i in [1..n] do
        if i in ll2 then
            # the 1 stands for y
            Add( result, 2);
        else
            Add( result, 1);
        fi;
    od;
    return [rat,result];
    #return    [result, rat ];
end;

#############################################################################
#
# IN:
# string .............. represents a MONOMIAL of a Free Algebra with One
#                       for example "(4/5)*y.2*y.1"
# OUT
# A list describing this element, in the  example [ 4/5, [ 2, 1 ] ]
#
BCH_Monomial2List := function( string )
    local ll,b,a,rat,inds,index,i,power,j,ss;
    # get rid of new lines commands
    ll := ReplacedString( string, "\n", "" );
    ll := SplitString( ll, "*" );
    b := Length( ll );

    # get coefficient
    a := Length( ll[1] );
    rat := Rat( ll[1]{[2..a-1]} );

    # get list which describes monomial
    inds := [];
    for i in [2..b] do
        # deal with powers
        power := 1;
        ss := SplitString( ll[i], "^" );
        if Length( ss ) > 1 then
            power := Int( ss[2] );
        fi;
        a := Length( ss[1] );
        index := Int( ss[1]{[3..a]} );
        for j in [1..power] do
            Add( inds, index );
        od;
    od;
    return [ rat, inds ];
end;


#############################################################################
#
# A := FreeAlgebraWithOne( Rationals, 2 );
# typical input string = "-1/720*x_1*x_2+1/180*x_3*x_5";
# Conversion corresponding to Reinsch
# Output lies in A
#
BCH_SumOfSigmaExpresions2XY := function( n, string, A )
    local ll1,ll2,ll3,k, gens,pol,i;
    ll1 :=  ReplacedString( string, "-", "+-" );
    ll2 := SplitString( ll1, "+" );
    ll3 := Filtered( ll2, x-> x <> "" );
    k := Length( ll3 );

    gens := GeneratorsOfAlgebra( A );
    pol := gens[1]*0;
    for i in [1..k] do
        pol := pol + BCH_SigmaExpression2XY( n, ll3[i], A );
    od;
    return pol;
end;

#############################################################################
#
# typical input string = "-1/720*x_1*x_2+1/180*x_3*x_5";
# Conversion corresponding to Reinsch
#
BCH_SumOfSigmaExpresions2List := function( n, string )
    local ll1,ll2,ll3,k,i,result;
    ll1 :=  ReplacedString( string, "-", "+-" );
    ll2 := SplitString( ll1, "+" );
    ll3 := Filtered( ll2, x-> x <> "" );
    k := Length( ll3 );

    result := [];
    for i in [1..k] do
        Add( result , BCH_SigmaExpression2List( n, ll3[i] ));
    od;
    return result;
end;

#############################################################################
#
# IN:
# string .............. represents a POLYNOMIAL of a Free Algebra with One
#                       for example "(1/2)*y.1*y.2+(-1/2)*y.2*y.1"
# OUT
# A list describing this element, in the  example 
# [ [ 1/2, [ 1, 2 ] ], [ -1/2, [ 2, 1 ] ] ]
#
BCH_Polynomial2List := function( string )
    local ll,y,result,i;
    ll := SplitString( string, "+" );
    y := Length( ll );
    result := [];
    for i in [1..y] do
        Add( result , BCH_Monomial2List( ll[i] ));
    od;
    return result;
end;

BCH_WeightInY := function( list )
    local weight,i;
    weight := 0;
    for i in list do
        if i = 2 then 
            weight := weight + 1;
        fi;
    od;
    return weight;
end;

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

# IN:
# ll ............ a list (for example [ -1/720, [ 1, 2 ] ] ) which
#                 specifies a monomial in x,y over Q
#                 Convention: 1 stands for x
#                             2 stands for y
# OUT:
# a list which specifies an elment of the Lie algebra, written 
# with Lie brackets, which is the image under the map of Vaughan-Lee
#
BCH_MonomialList2LieBracketList := function( ll )
    local k,result,i,l,sum,weight;
    k := Length( ll );
    result := [];
    for i in [1..k] do
        # take only terms starting with yx
        if ll[i][2][1]=2 and ll[i][2][2]=1 then
            l := StructuralCopy( ll[i] );
            # weight in y
            weight := BCH_WeightInY( l[2] );
            #sum := Sum( l[2] );
            l[1] := l[1]/weight;
            Add( result, l );
        fi;
    od;
    return result;
end;

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

# IN:
# ll ............ a list (for example [ -1/720, [ 1, 2 ] ] ) which
#                 specifies a monomial in y_1,...,y_k over Q
#                 Convention:  
#                 1 stands for  y_1
#                 2 stands for  y_2
#                 and so on
# OUT:
# a list which specifies an elment of the Lie algebra, written 
# with Lie brackets, which is the image under the map of Jacobson:
# d(m) = 1/i [m] 
# where "i" is the weigth of the monomial.
#
# TODO Is this function really correct for more than 2 variables ? 
#
BCH_MonimalInKVariablesList2LieBracketList := function( ll )
    local k,result,i,l,weight;
    k := Length( ll );
    result := [];
    for i in [1..k] do
        l := StructuralCopy( ll[i] );
        weight := Length( l[2] );
        l[1] := l[1]/weight;
        Add( result, l );
    od;
    return result;
end;


#############################################################################
#
# Calculation of the coefficients of the BCH series of weigt n.

# Eample:

# gap> BCH_ComputeCoefficientsAndBrackets( 2 );
# [ [ -1/2, [ 1, 0 ] ] ]
# gap> BCH_ComputeCoefficientsAndBrackets( 3 );
# [ [ -1/12, [ 1, 0, 1 ] ], [ 1/12, [ 1, 0, 0 ] ] ]
#
BCH_ComputeCoefficientsAndBrackets := function( n )
     local P,F,G,elm,string,ll,lie ;
     P := PolynomialRing( Rationals, n );
     F := BCH_Compute_F( n );;
     G := BCH_Compute_G( n, P );;
     elm := BCH_Logarithm( F*G )[1][n+1];
     string := String( elm );
     ll := BCH_SumOfSigmaExpresions2List( n, string );
     lie := BCH_MonomialList2LieBracketList( ll ); 
     return lie;
end;

# compute bch series up to weight c
BCH_Series := function( c )
    local sers, terms,i;
    sers := [];
    for i in [2..c] do
        terms := BCH_ComputeCoefficientsAndBrackets( i );
        sers := Concatenation( sers, terms );
    od;
    return sers;
end;

# compute bch series up to weight c
BCH_SeriesOrdered := function( c )
    local sers, terms,i;
    sers := [];
    for i in [2..c] do
        terms := BCH_ComputeCoefficientsAndBrackets( i );
        Add( sers, terms );
    od;
    return sers;
end;



BCH_ComputeMonomials := function( n )
     local P,F,G,elm,string,A,ll,lie ;
     P := PolynomialRing( Rationals, n );
     F := BCH_Compute_F( n );;
     G := BCH_Compute_G( n, P );;
     elm := BCH_Logarithm( F*G )[1][n+1];
     string := String( elm );
     #A := FreeAlgebraWithOne( Rationals, 2 );
     ll := BCH_SumOfSigmaExpresions2List( n, string );
     return ll;
end;

#############################################################################
#
# IN:
# n ......... weight, must be bigger than 1.
# word ...... list specifying word in e^y_1,e^y_2
#             For example [-1,-2,1,2] means y_1^-1 * y_2^-1* y_1 * y_2
#            
# Compute z where e^z = word( e^x, e^y ).
# Note that word can be any product of e^x,e^y,e^-x,e^-y
#
BCH_ComputeCoefficientsAndBracketWord := function( n, word )
     local P,F,G,elm,string,ll,lie,mats,i,prod,l ;
     P := PolynomialRing( Rationals, n );
     mats := [];
     # the following could be done better for longer words
     # by saving the F,F^-1,G,G^-1
     l := Length( word );
     for i in [1..l] do
         if AbsoluteValue( word[i] ) = 1 then 
            Add( mats, BCH_Compute_F_Power( n, SignInt( word[i] ) ));
         elif AbsoluteValue( word[i] ) = 2 then 
            Add( mats, BCH_Compute_G_Power( n, P, SignInt( word[i] ) ));
         else 
            Error( "Wrong Input\n" );
         fi;
     od;
     prod := Product( mats );
     elm := BCH_Logarithm( prod )[1][n+1];
     string := String( elm );
     ll := BCH_SumOfSigmaExpresions2List( n, string );
     lie := BCH_MonomialList2LieBracketList( ll ); 
     return lie;
end;

BCH_InverseWord := function( word )
    local res;
    res := Reversed( word );
    res := -1*res;
    return res;
end;

BCH_Comm2Word := function( comm )
    local l,res,word,wordInv;
    l := Length( comm );
    if l = 2 then 
         res := [ -comm[1],-comm[2],comm[1],comm[2] ];
    else  
         word := BCH_Comm2Word( comm{[1..l-1]} );
         wordInv := BCH_InverseWord( word );
         res := Concatenation( wordInv, [-comm[l]], word, [comm[l]] );
     fi;
     return res;
end;

#############################################################################
#
# IN:
# n ......... weight, must be bigger than 1.
# kappa ..... list specifyinga commutator in e^y_1,e^y_2
#             For example [1,2] means [y_1,y_2]
#            
# Compute z where e^z = kappa( e^x, e^y ).
#
BCH_ComputeCoefficientsAndBracketsByCommutator := function( n, kappa )
    local word;
    # check if 
    if Length( kappa ) = n then
        return [ [1,kappa] ];
    else
        word := BCH_Comm2Word( kappa );
        return BCH_ComputeCoefficientsAndBracketWord( n, word );
    fi;
end;


# BCH in k variables 
BCH_ComputeMonomialsExtendedBCHSeries := function( n, k )
     local A,H,mat,elm,string,ll;
     A := FreeAssociativeAlgebraWithOne( Rationals, k, "y" );     
     H := BCH_Compute_HMatrices( n, k, A );
     mat := Product( H );
     elm := BCH_Logarithm( mat )[1][n+1];
     string := StringPrint( elm );
     ll := BCH_Polynomial2List( string );
     return ll;
end;

# BCH in k variables
# e^z = e^y_1* ... * e^y_k
#
BCH_ComputeCoefficientsAndBracketsExtendedBCH :=  function( n, k )
     local A,H,mat,elm,string,ll,lie;
     A := FreeAssociativeAlgebraWithOne( Rationals, k, "y" );     
     H := BCH_Compute_HMatrices( n, k, A );
     mat := Product( H );
     elm := BCH_Logarithm( mat )[1][n+1];
     string := StringPrint( elm );
     ll := BCH_Polynomial2List( string );
     lie := BCH_MonimalInKVariablesList2LieBracketList( ll );
     return lie;
end;


#############################################################################
#
# Compute all terms of the BCH series up to a given weight wCom
# of all commutators up to weight wSers. 
# That is, we compute for all group commutators
# kappa of weight up to w2, all terms of weight up to  w1 in the expression
# z where 
# kappa( e^x, e^y )  = e^z


BCH_ComputeCommutatorSeries := function( wSers, wCom )
    local coms,i,a,lie,j,n,com,series,terms;

    if wSers < wCom then
        Error( "The BCH series of a commutator of Length wCom starts with\n",
               "Lie brackets of Length wCom.\n",
               "Therefore wSers should be at least as big as wCom." );
    fi;
 
    # produce a list coms, containing all possible commutators up 
    # to weight wCom
    coms := [];
    coms[1] := -1;
    coms[2] := [ [1,2], [2,1] ];
    for i in [3..wCom] do
        coms[i] := [];
        for a in coms[i-1] do 
            Add( coms[i], Concatenation( a, [1] ) );
            Add( coms[i], Concatenation( a, [2] ) );
        od;
    od;
    
    # for each commutator compute its BCH series up to weight wSers
    lie := [];
    lie[1] := -1;
    for i in [2..wCom] do
        lie[i] := [];
        for j in [1..Length(coms[i])] do 
            com := coms[i][j];
            series := [];
            # the BCH of com starts with weight length of com
            for n in [Length(com)..wSers] do
                terms := BCH_ComputeCoefficientsAndBracketsByCommutator( 
                                                                n, com );
                series := Concatenation( series, terms );
            od;
            Add( lie[i], series );
        od;
    od;
    
    return rec( coms := coms, lie := lie );
end;

#############################################################################
#
#
# kappa( logx, logy ) = log( kappa(x,y) ) +  tail
# factor*kappa( logx, logy ) = factor*log( kappa(x,y) ) + factor* tail
#
BCH_GetTail := function( kappa, sersOfComs, factor )
    local w, pos,sers,i,l;
    w := Length( kappa );
    pos := Position( sersOfComs.coms[w], kappa );
    
    sers := StructuralCopy( sersOfComs.lie[w][pos] );
    l := Length( sers );
    # get rid of starting term kappa( logx, logy )
    sers := sers{[2..l]};

    # change sign because we have to bring to the other side
    # and multiply it with factor
    for i in [1..l-1] do
        sers[i][1] := -factor*sers[i][1];
    od;
    return sers;
end;


# add lie brackets that are similar.
# for example [ [1/4, [ 2, 1, 2, 1 ] ], [1/4, [ 2, 1, 2, 1 ] ]]
# becomes [  [1/2, [ 2, 1, 2, 1 ] ] ]
BCH_SimplifySers := function( sers )
    local res,l,term,contained,term2,pos,i,res_without_zeros;
    res := [];
    l := Length( sers );
    if l = 0 then
        return [];
    fi;
    Add( res, sers[1] );
    for i in [2..l] do
        term := sers[i];
        # test if term[2] is already contained in res
        contained := false;
        for pos in [1..Length(res)] do
            term2 := res[pos];
            if term2[2] = term[2] then
                contained := true;
                break;
            fi;
        od;
        if contained then
            # summarize
            res[pos][1] := res[pos][1] + term[1];           
        else            
            # else add term
            Add( res, term );
        fi;
    od;

    # delete entries with zero coeff
    res_without_zeros := [];
    for pos in [1..Length( res )] do    
        # if zero coeff then add
        if res[pos][1] <> 0 then
            Add( res_without_zeros, res[pos] );
        fi;
    od;
       
    return res_without_zeros;
end;


#############################################################################
#
# Aim:
#[logx,logy] = Q-linear combination of logs of group commutators.
#
#
# c .............. class of nilpotent groups for which the result
#                  of the computation should be used. 
#                  That is, c is the maximal length of a group commutator
#                  which is non-trivial.
#
# Approach: Compute this expression for a group of fixed nilpotency 
# class. Then we can probably show that a group of nilpotency class
# c+1 contains the old series plus some new terms. 
# We can compute this by replacing in (*) the higher commutators in x,y
# chi(x,y)_L by chi(x,y)_G + higher commutators in x,y, which we 
# compute with the extended BCH-series.
#
#
BCH_LieBracketInTermsOfLogs := function( c )
    local sersOfComs,logs,term,lieTerms,tail,i,logs_ordered,le;

    # get bch series of all commutators up to weight c
    sersOfComs := BCH_ComputeCommutatorSeries( c, c );

    # we know the first term of the logs expressions
    logs := [ [1,[1,2]] ];
    
    # get remaining terms in logx, logy
    lieTerms := BCH_GetTail( [1,2], sersOfComs, 1 );

    # replace iteratively all remaining Lie bracktes
    i := 1;
    while i <= Length( lieTerms ) do
        term := lieTerms[i];
        # replace it by factor*log( kappa(x,y) ) + factor*tail
        Add( logs, term );
        tail := BCH_GetTail( term[2], sersOfComs, term[1] );
        Append( lieTerms, tail );
        i := i+1;
    od;
    logs := BCH_SimplifySers( logs );

    # order result corresponding to weight
    logs_ordered := [];
    for i in [2..c] do
        logs_ordered[i-1] := [];
    od;
    for term in logs do
        le := Length( term[2] );
        Add( logs_ordered[le-1], term );
    od;
  
    return logs_ordered;
end;

BCH_TGroupRec := function( N )
    local sers,i, NN,l,leFactors,s,indices,class,
          wei, weights,a, largestAbelian;
    sers := UpperCentralSeries( N );
    NN := PcpGroupBySeries( sers ); 
    #basisNN := GeneratorsOfGroup( NN );
    #iso := NN!.bijection;
    #basisN := GeneratorsOfGroup( Image( iso ) );

    # get indices of generators of the factors of the upper central series
    l := Length( sers );
    leFactors := [];
    for i in [1..l-1] do
        Add( leFactors, HirschLength( sers[i]) - 
                        HirschLength( sers[i+1]));
    od;
    s := 1;
    indices := [];
    for i in [1..l-1] do
        Add( indices, [s..s+leFactors[i]-1] );
        s := s + leFactors[i];
    od;
    
    # nilpotency class of group
    class := Length( leFactors );

    # weights of generators
    wei := 1;
    weights := [];
    for a in leFactors do
        for i in [1..a] do
            Add( weights, wei );
        od;
        wei := wei + 1;
    od;

    # get larges abelian group in the upper central series
    for i in [1..Length(sers)] do
        if IsAbelian( sers[i] ) then
            largestAbelian := i;
            break;
        fi;
    od;

    return rec( N := N, #basisN := basisN, 
                NN := NN,
                sers := sers, indices := indices,
                class := class, weights := weights,
                largestAbelian := largestAbelian );
end;

BCH_SetUpLieAlgebraRecordByMalcevbasis := function( recTGroup )
    local NN,hl,T,L;
    
    # get dimension of algebra
    NN := recTGroup.NN;
    hl := HirschLength( NN );

    # get prototype for structure constant table and Lie algebra 
    T:= EmptySCTable( hl, 0, "antisymmetric" );
    L:= LieAlgebraByStructureConstants( Rationals, T );

    

    # set the structure constants we already know,
    # i.e. lie brackets involving log g_i where g_i in Z(NN)
        # not necessary, because empty entries are interpreted 
        # as commuting elements

    return rec( L := L, recTGroup := recTGroup, scTable := T  );
end;

BCH_FullBCHInformation := function( w  )
    local bchSers, bchLBITOL;
    bchSers := BCH_SeriesOrdered( w );
    bchLBITOL :=  BCH_LieBracketInTermsOfLogs( w );

    return rec( bchSers := bchSers, 
                bchLBITOL := bchLBITOL );
end;

# x corresponds to 1
# y corresponds to 2 
BCH_EvaluateLieBracket := function( x, y, com, info )
    local r,l,tmp,i;
    tmp := [x,y];
    r := tmp[com[1]];

    l := Length( com );
    if info = "lieAlgebra" then
        for i in [2..l] do
            r := r * tmp[com[i]];
        od; 
    elif info = "matrix" then 
        for i in [2..l] do
            r := LieBracket( r, tmp[com[i]] );
        od;
    else 
        Error( "wront input \n " );
    fi;
    return r;
end;

# g corresponds to 1
# h corresponds to 2 
BCH_EvaluateGroupCommutator := function( g, h, com )
    local tmp,r,l,i;
    tmp := [g,h];
    r := tmp[com[1]];

    l := Length( com );
    for i in [2..l] do
        r := Comm( r, tmp[com[i]] );
    od;
    return r;
end;


BCH_WeightOfCommutator := function( com, wx, wy )
    local weight,a;
    weight := 0;
    for a in com do
        if a = 1 then
            weight := weight + wx;
        elif a = 2 then
            weight := weight + wy;
        else
            Error( "Wrong input\n" );
        fi;
    od;
    return weight;
end;

BCH_CheckWeightOfCommutator := function( com, wx, wy, class )
    local w;
    w := BCH_WeightOfCommutator( com, wx, wy );
    if w > class then
        return false;
    else
        return true;
    fi;
end;

# Very SIMPLE Implementation !!
#
# compute x*y, where "*" is the BCH operation 
# wx ..... weight of x
# wy ..... weight of y
# class ...... nilpotency class of the lie algebra,
#              so brackets of Length class + 1 are always 0.
#
# info ..... strings which determines how lie bracket is evaluated
#
BCH_Star_Simple := function( recBCH, x, y, wx, wy, class, info  )
    local i,r,bchSers,com,a,term,max,min,bound;
    bchSers := recBCH.bchSers;
    
    # start with terms which are not given by Lie brackets
    r := x + y;

    # trivial check 
    if x = 0*x or y = 0*y then
        return r;
    fi;

    # compute upper bound for the Length of commutators, which 
    # can be involved
    max := Maximum( wx,wy );
    min := Minimum( wx,wy );
    # max + min* (bound-1 ) <= class
    bound := Int( (class-max)/min + 1 );

    # up to bound  compute the commutators and add them.
    # Note that the list contains commutators of length i at position i-1.
    for i in [1..bound-1] do
        for term in bchSers[i] do
            com := term[2];
            # check if weight of commutator is not to big
            if BCH_CheckWeightOfCommutator( com, wx, wy, class ) then
                a := BCH_EvaluateLieBracket( x, y, com, info );
                r := r + term[1]*a; 
            fi;
        od;
    od;
    
    return r;
end;


BCH_WeightOfLieAlgElm := function( recLieAlg, elm )
    local basisL,coeff,i,e;
    basisL := Basis( recLieAlg.L );
    coeff := Coefficients( basisL, elm );
    for i in [1..Length(coeff)] do
        e := coeff[i];
        if e <> 0 then
            return recLieAlg.recTGroup.weights[i];
        fi;
    od;
    return recLieAlg.recTGroup.class;
end;

BCH_AbstractLog_Simple_ByExponent := function( recLieAlg, recBCH,  exp )
    local  gensL,r,i,e,x,y,wx,wy,class;

    # setup
    gensL := GeneratorsOfAlgebra( recLieAlg.L );
    class := recLieAlg.recTGroup.class;

    r := Zero( recLieAlg.L );
    # go backwards through exponents. 
    # Which direction is more efficient ?
    for i in Reversed([1..Length( exp )] ) do
        e := exp[i];
        if e <> 0 then 
            x := e*gensL[i];
            y := r;
            # if y is the identity then x*y = x
            if y = Zero( recLieAlg.L ) then
                r := x;
            else
                # compute weights of x,y
                wx := recLieAlg.recTGroup.weights[i];
                wy := BCH_WeightOfLieAlgElm( recLieAlg, y );
                r := BCH_Star_Simple( recBCH,x,y,wx,wy,class, "lieAlgebra" );
            fi;
        fi;
    od;
    return r;
end;

BCH_AbstractLogCoeff_Simple_ByExponent := function( recLieAlg, recBCH, exp )
    local r;
    r := BCH_AbstractLog_Simple_ByExponent( recLieAlg, recBCH,  exp );
    return Coefficients( Basis( recLieAlg.L ), r);
end;

BCH_AbstractLog_Simple_ByElm := function( recLieAlg, recBCH,  g )
    local exp,hl,l,expNN;
    
    # get exponets with respect to gens of T group NN
    # (g might an elment of PcpGroup which contains NN as a normal sugroup,
    # then Exponents(g) would be longer hl(NN))
    exp := Exponents( g );
    hl := HirschLength( recLieAlg.recTGroup.NN );
    l := Length( exp );
    expNN := exp{[l-hl+1..l]};
    return BCH_AbstractLog_Simple_ByExponent( recLieAlg, recBCH,  expNN );
end;

BCH_AbstractLogCoeff_Simple_ByElm := function( recLieAlg, recBCH,  g )
    local r;
    r := BCH_AbstractLog_Simple_ByElm( recLieAlg, recBCH,  g );
    return Coefficients( Basis( recLieAlg.L ), r);
end;

BCH_EvaluateLieBracketsInTermsOfLogarithmsSers 
                            := function( recBCH, recLieAlg, g,h,wg,wh )
    local bchLBITOL,r,max,min,bound,class,i,term,com,a,log_a;
    bchLBITOL := recBCH.bchLBITOL;
  
    r := Zero( recLieAlg.L );

    # compute upper bound for the Length of commutators, which 
    # can be involved
    class := recLieAlg.recTGroup.class;
    max := Maximum( wg,wh );
    min := Minimum( wg,wh );
    # max + min* (bound-1 ) <= class
    bound := Int( (class-max)/min + 1 );

    # up to bound  compute the commutators and add them.
    # Note that the list contains commutators of length i at position i-1.
    for i in [1..bound-1] do
        for term in bchLBITOL[i] do
            com := term[2];
            # check if weight of commutator is not to big
            if BCH_CheckWeightOfCommutator( com, wg, wh, class ) then
                # evaluate commutator in the group
                a := BCH_EvaluateGroupCommutator( g, h, com );
                # map to the Lie algebra
                log_a := BCH_AbstractLog_Simple_ByElm( recLieAlg, recBCH, a );
                r := r + term[1]*log_a; 
            fi;
        od;
    od;
    
    return r;

end;

# output is a list, as required for SetEntrySCTable
BCH_LieAlgElm2CoeffGenList := function( L, x )
    local basis, coeff,i,ll;
    basis := Basis( L );
    coeff := Coefficients( basis, x );
    ll := [];
    for i in [1..Length(coeff)] do
        if coeff[i] <> 0 then
            Append( ll, [coeff[i],i] );
        fi;
    od;
    return ll;
end;

#recBCH := BCH_FullBCHInformation( 5 );

#N := PcpGroupByMatGroup( PolExamples(4 ) );
#recTGroup := BCH_TGroupRec( N );  
#recLieAlg := BCH_SetUpLieAlgebraRecordByMalcevbasis( recTGroup );

# F := FreeGroup( 3 );
# N := NilpotentQuotient( F, 5 );
# recTGroup := BCH_TGroupRec( N );
# recLieAlg := BCH_SetUpLieAlgebraRecordByMalcevbasis( recTGroup );

BCH_ComputeStructureConstants := function( args )
    local factors, index_x, index_y, indices,indicesNoCenter,l,g,h,wg,wh,
          lie_elm,ll,gens,T,out,recLieAlg,recBCH;

    # setup
    recLieAlg := args[2];
    recBCH := args[1];
    indices := recLieAlg.recTGroup.indices;
    l := Length( indices );
    indicesNoCenter := indices{[1..l-1]};
    gens := GeneratorsOfGroup( recLieAlg.recTGroup.NN );
    T := recLieAlg.scTable;

    # go through blocks of generators backwards, 
    # where a block corresponds to the generators of the factors
    # of the upper central series
    for factors in Reversed( indicesNoCenter ) do
        for index_y in Reversed( factors ) do
            for index_x in  [1..index_y-1]   do
                g := gens[index_x];
                h := gens[index_y];
                wg := recLieAlg.recTGroup.weights[index_x];
                wh := recLieAlg.recTGroup.weights[index_y];
                # compute [log(g),log(h)]
                lie_elm := BCH_EvaluateLieBracketsInTermsOfLogarithmsSers( 
                                            recBCH, recLieAlg, g,h, wg, wh );
                # set entry in structure constant table 
                ll := BCH_LieAlgElm2CoeffGenList( recLieAlg.L, lie_elm );
                if Length( ll ) > 0 then
                    SetEntrySCTable( T, index_x, index_y, ll );
                fi;
            od;
        od;
        # update Lie algebra with new structure constant table
        recLieAlg.L:= LieAlgebraByStructureConstants( Rationals, T );
    od;
    return 0;
end;

BCH_Abstract_Exponential_ByElm := function( recBCH, recLieAlg, x )
    local indices,basis,class,tail,coeffs,largestAbelian,exp_x,i,factor,
          divider,w_divider,w_tail,l,exp_x_2ndPart,j;

    indices := recLieAlg.recTGroup.indices;
    basis := Basis( recLieAlg.L );
    class := recLieAlg.recTGroup.class;

    # divide some exponents untill the remaining element lies in an
    # abelian group.
    tail := x;
    coeffs := Coefficients( basis, tail );
    largestAbelian := recLieAlg.recTGroup.largestAbelian;
    exp_x := [];
    for i in [1..largestAbelian-1] do
        factor := indices[i];
        for j in factor do 
            # get element to divide of
            divider := -coeffs[j]*basis[j];

            # save exponents of divider
            Add( exp_x, coeffs[j] );

            # divide off
            w_divider := BCH_WeightOfLieAlgElm ( recLieAlg, divider );
            w_tail := BCH_WeightOfLieAlgElm ( recLieAlg, tail );
            tail := BCH_Star_Simple( recBCH, divider, tail, w_divider, 
                                     w_tail, class, "lieAlgebra"  );
        
            # set up coefficient vector
            coeffs := Coefficients( basis, tail );
        od;
    od;

    # test intermediate result
    l := Length( exp_x );
    if not coeffs{[1..l]} = 0 *  coeffs{[1..l]} then
        Error( "Failure in Abstract_Exponential \n" );
    fi;

    # get the remaining coefficients 
    exp_x_2ndPart := coeffs{[l+1..Length(coeffs)]};
    
    return Concatenation( exp_x, exp_x_2ndPart );
    
end;

BCH_Abstract_Exponential_ByVector := function( recBCH, recLieAlg, vec )
    local basis,x;
    basis := Basis( recLieAlg.L );
    x := LinearCombination( basis, vec );
    return BCH_Abstract_Exponential_ByElm( recBCH, recLieAlg, x ); 
end;

BCH_LieAlgebraByTGroupRec := function( recBCH, recTGroup )
    local recLieAlg;

    recLieAlg := BCH_SetUpLieAlgebraRecordByMalcevbasis( recTGroup );
    BCH_ComputeStructureConstants( [recBCH, recLieAlg] );
   
    return recLieAlg;
end;

#############################################################################
#
# TEST Functions
#
#############################################################################


BCH_Test_LogOfExp := function( recBCH, recLieAlg, noTests )
    local x,exp,x2,i;

    for i in [1..noTests] do
        x := Random( recLieAlg.L );
        exp := BCH_Abstract_Exponential_ByElm( recBCH, recLieAlg, x );
        x2 := BCH_AbstractLog_Simple_ByExponent( recLieAlg, recBCH, exp );
        if not x = x2 then
            Error( "Mist\n" );
        fi;
    od;
    return 0;
end;

BCH_Test_ExpOfLog := function( recBCH, recLieAlg, noTests,range )
    local i,hl,domain,exp,x,exp2;
    hl := HirschLength( recLieAlg.recTGroup.NN );
    domain := [-range..range];
    for i in [1..noTests] do
        exp := List( [1..hl], x -> Random( domain ) );
        x := BCH_AbstractLog_Simple_ByExponent( recLieAlg, recBCH, exp );
        exp2 := BCH_Abstract_Exponential_ByElm( recBCH, recLieAlg, x );
        if not exp = exp2 then
            Error( "Mist\n" );
        fi;
    od;
    return 0;
end;


BCH_Test := function( n )
    local P,F,G,elm,string,A,ll,lie,kk,kk2;        
 
    P := PolynomialRing( Rationals, n );
    F := BCH_Compute_F( n );;
    G := BCH_Compute_G( n, P );;
    elm := BCH_Logarithm( F*G )[1][n+1];
    string := String( elm );
    A := FreeAlgebraWithOne( Rationals, 2 );
    ll := BCH_SumOfSigmaExpresions2List( n, string );
    lie := BCH_MonomialList2LieBracketList( ll );
    Length( ll );
    Length( lie );
    kk := List( lie, x->x[2] );
    kk2 := AsSet( kk );
    return [ Length( lie ), Length( AsSet( kk ) )];
end;


BCH_List2Number := function( base, ll )
    local n,l,numb,i;
    n := Length( ll );
    #throw away the first two entries 1 and 0
    l := ll{[3..n]};

    numb := 0;
    for i in Reversed( [3..n]) do
        if ll[i]<>0 then
            numb := numb + base^(n-i);
        fi;
    od;
    return numb;
end;

# produce random element of Tr_0(dim,Q)
BCH_RandomNilpotentMat := function( dim )
    local range,ll,kk,g,j,k;
    range := 7;
    ll := [ - range .. range ];
    kk := [ - range .. range ];
    ll := Filtered( ll, function ( x )
            return x <> 0;
        end );
    kk := Filtered( kk, function ( x )
            return x <> 0;
        end );

    g := NullMat( dim, dim, Rationals );
    for j  in [ 1 .. dim ]  do
        for k  in [ j .. dim ]  do
            if j < k  then
                g[j][k] := RandomList( ll ) / RandomList( kk );
            else
                g[j][k] := 0;
            fi;
        od;
    od;
    return g;
end;

BCH_TestBchSeriesOrdered := function( recBCH, n )
    local no_tests,i,x,y,wx,wy,x_star_y,exp_x_star_y,exp_x,exp_y;

    no_tests := 100;
    for i in [1..no_tests] do
        # produce two random matrices x,y in Tr_0(n,Q)
        x := BCH_RandomNilpotentMat( n );
        y := BCH_RandomNilpotentMat( n );
        wx := 1;
        wy := 1;

        # compute  exp(x*y) with BCH, 
        # note that we need terms of length at most n-1
        x_star_y := BCH_Star_Simple ( recBCH, x, y, wx, wy, n-1, "matrix"  );
        exp_x_star_y := BCH_Exponential( Rationals, x_star_y );   

        # compute exp(x)exp(y) and compare
        exp_x := BCH_Exponential( Rationals, x );
        exp_y := BCH_Exponential( Rationals, y );

        if not exp_x_star_y = exp_x*exp_y then
            Error( "Mist \n " );
        fi;

    od;
    return 0;
end;

# recComSers as computed by BCH_ComputeCommutatorSeries
# recComSers := BCH_ComputeCommutatorSeries( 6, 3 );
BCH_Test_ComputeCommutatorSeries := function( recComSers, n, kappa )
    local  no_tests,i,x,y,wx,wy,exp_x,exp_y,exp_z,r,class,
          sers,com,a,term,exp_z_bch,weight, pos;

    no_tests := 10;
    for i in [1..no_tests] do
        # produce two random matrices x,y in Tr_0(n,Q)
        x := BCH_RandomNilpotentMat( n );
        y := BCH_RandomNilpotentMat( n );
        wx := 1;
        wy := 1;
   
        # compute kappa( exp(x),exp(y) ) normally
        exp_x := BCH_Exponential( Rationals, x );
        exp_y := BCH_Exponential( Rationals, y );
        exp_z := BCH_EvaluateGroupCommutator( exp_x, exp_y, kappa );

        # compute z where exp(z)= kappa( exp(x),exp(y) ) with extended BCH
        r := NullMat( n,n );
        class := n-1;
        weight := Length( kappa );
        pos := Position( recComSers.coms[weight], kappa );
        sers := recComSers.lie[weight][pos];
        for term in sers do
            com := term[2];
            #Print( "term ", term, "\n" );
            # check if weight of commutator is not to big
            if BCH_CheckWeightOfCommutator( com, wx, wy, class ) then
                # evaluate commutator in the lie algebra
                a := BCH_EvaluateLieBracket( x, y, com, "matrix" );
                r := r + term[1]*a;
                #        Print( "log_a ", log_a, "\n" );
                #        Print( "r ", r, "\n\n" );
            fi;
        od;
        exp_z_bch := BCH_Exponential( Rationals, r );

        # compare
        if not exp_z_bch = exp_z then 
            Error( "Mist\n" );
        fi;
    od;
    return 0;
end;

BCH_TestSeriesLieBracketInTermsOfLogs := function( recBCH, n )
    local no_tests,i,x,y,x_bracket_y,g,h,wg,wh,r,class,max,min,bound,j,
          term,a,log_a,x_bracket_y_2,bchLBITOL,com;

    no_tests := 10;
    for j in [1..no_tests] do
        # produce two random matrices x,y in Tr_0(n,Q)
        x := BCH_RandomNilpotentMat( n );
        y := BCH_RandomNilpotentMat( n );
              
        # compute [x,y] in normal way
        x_bracket_y := LieBracket( x, y );

        # compute [x,y] with series "liebrackets in terms of logs"
            g := BCH_Exponential( Rationals, x );
            h := BCH_Exponential( Rationals, y );
            wg := 1;
            wh := 1;

            bchLBITOL := recBCH.bchLBITOL;
            r := NullMat( n,n );
            # compute upper bound for the Length of commutators, which 
            # can be involved
            class := n-1;
            max := Maximum( wg,wh );
            min := Minimum( wg,wh );
            # max + min* (bound-1 ) <= class
            bound := Int( (class-max)/min + 1 );

            # up to bound  compute the commutators and add them.
            # Note that the list contains comms of length i at position i-1.
            for i in [1..bound-1] do
                for term in bchLBITOL[i] do
                    com := term[2];
                    #Print( "term ", term, "\n" );
                    # check if weight of commutator is not to big
                    if BCH_CheckWeightOfCommutator( com, wg, wh, class ) then
                        # evaluate commutator in the group
                        a := BCH_EvaluateGroupCommutator( g, h, com );
                        # map to the Lie algebra
                        log_a := BCH_Logarithm( a );
                        r := r + term[1]*log_a;
                        #Print( "log_a ", log_a, "\n" );
                        #Print( "r ", r, "\n\n" );
                    fi;
                od;
            od;
            x_bracket_y_2 := r;
    
        # compare
        if not x_bracket_y = x_bracket_y_2 then
            Error( "Mist\n" );
        fi;
    od;
    return 0;
end;

[ Dauer der Verarbeitung: 0.60 Sekunden  ]