############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Thomas Breuer, and Willem de Graaf. ## ## 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 methods for Lie algebras. ##
############################################################################# ## #M LieUpperCentralSeries( <L> ) . . . . . . . . . . for a Lie algebra ##
InstallMethod( LieUpperCentralSeries, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local S, # upper central series of <L>, result
C, # Lie centre
hom; # homomorphisms of <L> to `<L>/<C>'
S := [ TrivialSubalgebra( L ) ];
C := LieCentre( L ); while C <> Last(S) do
# Replace `L' by `L / C', compute its centre, and get the preimage # under the natural homomorphism.
Add( S, C );
hom:= NaturalHomomorphismByIdeal( L, C );
C:= PreImages( hom, LieCentre( Range( hom ) ) ); #T we would like to get ideals! #T is it possible to teach the hom. that the preimage of an ideal is an ideal?
od;
# Return the series when it becomes stable.
return Reversed( S ); end );
############################################################################# ## #M LieLowerCentralSeries( <L> ) . . . . . . . . . . for a Lie algebra ##
InstallMethod( LieLowerCentralSeries, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local S, # lower central series of <L>, result
C; # commutator subalgebras
# Compute the series by repeated calling of `ProductSpace'.
S := [ L ];
C := LieDerivedSubalgebra( L ); while C <> Last(S) do
Add( S, C );
C:= ProductSpace( L, C );
od;
# Return the series when it becomes stable.
return S; end );
############################################################################# ## #M LieDerivedSubalgebra( <L> ) ## ## is the (Lie) derived subalgebra of the Lie algebra <L>. ## This is the ideal/algebra/subspace (equivalent in this case) ## generated/spanned by all products $uv$ ## where $u$ and $v$ range over a basis of <L>. ##
InstallMethod( LieDerivedSubalgebra, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0,
L -> ProductSpace( L, L ) );
############################################################################# ## #M LieDerivedSeries( <L> ) ##
InstallMethod( LieDerivedSeries, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function ( L )
local S, # (Lie) derived series of <L>, result
D; # (Lie) derived subalgebras
# Compute the series by repeated calling of `LieDerivedSubalgebra'.
S := [ L ];
D := LieDerivedSubalgebra( L ); while D <> Last(S) do
Add( S, D );
D:= LieDerivedSubalgebra( D );
od;
# Return the series when it becomes stable.
return S; end );
############################################################################# ## #M IsLieSolvable( <L> ) . . . . . . . . . . . . . . . for a Lie algebra ##
InstallMethod( IsLieSolvable, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local D;
D:= LieDerivedSeries( L );
return Dimension( Last(D) ) = 0; end );
############################################################################# ## #M IsLieAbelian( <L> ) . . . . . . . . . . . . . . for a Lie algebra ## ## It is of course sufficient to check products of algebra generators, ## no basis and structure constants of <L> are needed. ## But if we have already a structure constants table we use it. ##
InstallMethod( IsLieAbelian, "for a Lie algebra with known basis",
true,
[ IsAlgebra and IsLieAlgebra and HasBasis ], 0, function( L )
local B, # basis of `L'
T, # structure constants table w.r.t. `B'
i, # loop variable
j; # loop variable
B:= Basis( L ); if not HasStructureConstantsTable( B ) then
TryNextMethod(); fi;
T:= StructureConstantsTable( B ); for i in T{ [ 1 .. Length( T ) - 2 ] } do for j in i do if not IsEmpty( j[1] ) then
return false; fi;
od;
od;
return true; end );
InstallMethod( IsLieAbelian, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local i, # loop variable
j, # loop variable
zero, # zero of `L'
gens; # algebra generators of `L'
zero:= Zero( L );
gens:= GeneratorsOfAlgebra( L ); for i in [ 1 .. Length( gens ) ] do for j in [ 1 .. i-1 ] do if gens[i] * gens[j] <> zero then
return false; fi;
od;
od;
# The algebra multiplication is trivial, and the algebra does # not know about a basis. # Here we know at least that the algebra generators are space # generators. if not HasGeneratorsOfLeftModule( L ) then
SetGeneratorsOfLeftModule( L, gens ); fi;
# Return the result.
return true; end );
InstallTrueMethod( IsLieAbelian, IsAlgebra and IsZeroMultiplicationRing );
############################################################################## ## #M LieCentre( <L> ) . . . . . . . . . . . . . . . . . . . for a Lie algebra ## ## We solve the system ## $\sum_{i=1}^n a_i c_{ijk} = 0$ for $1 \leq j, k \leq n$ ## (instead of $\sum_{i=1}^n a_i ( c_{ijk} - c_{jik} ) = 0$). ## ## Additionally we know that the centre of a Lie algebra is an ideal. ##
InstallMethod( LieCentre, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( A )
local R, # left acting domain of `A'
C, # Lie centre of `A', result
B, # a basis of `A'
T, # structure constants table w.r. to `B'
n, # dimension of `A'
M, # matrix of the equation system
zerovector, #
i, j, # loop over ...
row; # one row of `M'
R:= LeftActingDomain( A );
if Characteristic( R ) <> 2 and HasCentre( A ) then
C:= Centre( A ); #T change it to an ideal!
else
# Catch the trivial case.
n:= Dimension( A ); if n = 0then
return A; fi;
# Construct the equation system.
B:= Basis( A );
T:= StructureConstantsTable( B );
M:= [];
zerovector:= [ 1 .. n*n ] * Zero( R ); for i in [ 1 .. n ] do
row:= ShallowCopy( zerovector ); for j in [ 1 .. n ] do if IsBound( T[i][j] ) then
row{ (j-1)*n + T[i][j][1] }:= T[i][j][2]; fi;
od;
M[i]:= row;
od;
# Solve the equation system.
M:= NullspaceMat( M );
# Get the generators from the coefficient vectors.
M:= List( M, x -> LinearCombination( B, x ) );
# Construct the Lie centre.
C:= IdealNC( A, M, "basis" );
fi;
# Return the Lie centre.
return C; end );
############################################################################## ## #M LieCentralizer( <A>, <S> ) . . . . . for a Lie algebra and a vector space ## ## Let $(b_1, \ldots, b_n)$ be a basis of <A>, and $(s_1, \ldots, s_m)$ ## be a basis of <S>, with $s_j = \sum_{l=1}^m v_{jl} b_l$. ## The structure constants of <A> are $c_{ijk}$ with ## $b_i b_j = \sum_{k=1}^n c_{ijk} b_k$. ## Then we compute a basis of the solution space of the system ## $\sum_{i=1}^n a_i \sum_{l=1}^m v_{jl} c_{ilk} = 0$ for ## $1 \leq j \leq m$ and $1 \leq k \leq n$. ## ## (left null space of an $n \times (nm)$ matrix) ##
InstallMethod( LieCentralizer, "for an abelian Lie algebra and a vector space",
IsIdenticalObj,
[ IsAlgebra and IsLieAlgebra and IsLieAbelian,
IsVectorSpace ], 0, function( A, S )
if IsSubset( A, S ) then
return A; else
TryNextMethod(); fi; end );
InstallMethod( LieCentralizer, "for a Lie algebra and a vector space",
IsIdenticalObj,
[ IsAlgebra and IsLieAlgebra, IsVectorSpace ], 0, function( A, S )
local R, # left acting domain of `A'
B, # basis of `A'
T, # structure constants table w. r. to `B'
n, # dimension of `A'
m, # dimension of `S'
M, # matrix of the equation system
v, # coefficients of basis vectors of `S' w.r. to `B'
zerovector, # initialize one row of `M'
row, # one row of `M'
i, j, k, l, # loop variables
cil, #
offset,
vjl,
pos;
# catch trivial case if Dimension(S) = 0then
return A; fi;
R:= LeftActingDomain( A );
B:= Basis( A );
T:= StructureConstantsTable( B );
n:= Dimension( A );
m:= Dimension( S );
M:= [];
v:= List( BasisVectors( Basis( S ) ),
x -> Coefficients( B, x ) );
zerovector:= [ 1 .. n*m ] * Zero( R );
# Column $(j-1)*n + k$ contains in row $i$ the value # $\sum_{l=1}^m v_{jl} c_{ilk}$
for i in [ 1 .. n ] do
row:= ShallowCopy( zerovector ); for l in [ 1 .. n ] do
cil:= T[i][l]; for j in [ 1 .. m ] do
offset := (j-1)*n;
vjl := v[j][l]; for k in [ 1 .. Length( cil[1] ) ] do
pos:= cil[1][k] + offset;
row[ pos ]:= row[ pos ] + vjl * cil[2][k];
od;
od;
od;
Add( M, row );
od;
# Solve the equation system.
M:= NullspaceMat( M );
# Construct the generators from the coefficient vectors.
M:= List( M, x -> LinearCombination( B, x ) );
# Return the subalgebra.
return SubalgebraNC( A, M, "basis" );
end );
############################################################################## ## #M LieNormalizer( <L>, <U> ) . . . . . . for a Lie algebra and a vector space ## ## If $(x_1, \ldots, x_n)$ is a basis of $L$ and $(u_1, \ldots, u_s)$ is ## a basis of $U$, then $x = \sum_{i=1}^n a_i x_i$ is an element of $N_L(U)$ ## iff $[x,u_j] = \sum_{k=1}^s b_{j,k} u_k$ for $j = 1, \ldots, s$. ## This leads to a set of $n s$ equations for the $n + s^2$ unknowns $a_i$ ## and $b_{jk}$. ## If $u_k= \sum_{l=1}^n v_{kl} x_l$, then these equations can be written as ## $\sum_{i=1}^n (\sum_{j=1}^n v_{lj} c_{ijk} a_i - ## \sum_{i=1}^s v_{ik} b_{li} = 0$, ## for $1 \leq k \leq n$ and $1 \leq j \leq s$, ## where the $c_{ilp}$ are the structure constants of $L$. ## From the solution we only need the "normalizer part" (i.e., ## the $a_i$ part). ##
InstallMethod( LieNormalizer, "for a Lie algebra and a vector space",
IsIdenticalObj,
[ IsAlgebra and IsLieAlgebra, IsVectorSpace ], 0, function( L, U )
local R, # left acting domain of `L'
B, # a basis of `L'
T, # the structure constants table of `L' w.r.t. `B'
n, # the dimension of `L'
s, # the dimension of `U'
A, # the matrix of the equation system
i, j, k, l, # loop variables
v, # the coefficients of the basis of `U' wrt `B'
cij,
bas,
b,
pos;
# catch trivial case if Dimension(U) = 0then
return L; fi;
# We need not work if `U' knows to be an ideal in its parent `L'. if HasParent( U ) and IsIdenticalObj( L, Parent( U ) )
and HasIsLeftIdealInParent( U ) and IsLeftIdealInParent( U ) then
return L; fi;
R:= LeftActingDomain( L );
B:= Basis( L );
T:= StructureConstantsTable( B );
n:= Dimension( L );
s:= Dimension( U );
if s = 0 or n = 0then
return L; fi;
v:= List( BasisVectors( Basis( U ) ),
x -> Coefficients( B, x ) );
# The equations. # First the normalizer part, \ldots
A:= NullMat( n + s*s, n*s, R ); for i in [ 1..n ] do for j in [ 1..n ] do
cij:= T[i][j]; for l in [ 1..s ] do for k in [ 1..Length( cij[1] ) ] do
pos:= (l-1)*n+cij[1][k];
A[i][pos]:= A[i][pos]+v[l][j]*cij[2][k];
od;
od;
od;
od;
# \ldots and then the "superfluous" part.
for k in [1..n] do for l in [1..s] do for i in [1..s] do
A[ n+(l-1)*s+i ][ (l-1)*n+k ]:= -v[i][k];
od;
od;
od;
# Solve the equation system.
b:= NullspaceMat(A);
# Extract the `normalizer part' of the solution.
l:= Length(b);
bas:= NullMat( l, n, R ); for i in [ 1..l ] do for j in [ 1..n ] do
bas[i][j]:= b[i][j];
od;
od;
# Construct the generators from the coefficients list.
bas:= List( bas, x -> LinearCombination( B, x ) );
# Return the subalgebra.
return SubalgebraNC( L, bas, "basis" ); end );
############################################################################## ## #M KappaPerp( <L>, <U> ) . . . . . . . . for a Lie algebra and a vector space ## #T Should this better be `OrthogonalSpace( <F>, <U> )' where <F> is a #T bilinear form? #T How to represent forms in GAP? #T (Clearly the form must know about the space <L>.) ## ## If $(x_1,\ldots, x_n)$ is a basis of $L$ and $(u_1,\ldots, u_s)$ is a ## basis of $U$ such that $u_k = \sum_{j=1}^n v_{kj} x_j$ then an element ## $x = \sum_{i=1}^n a_i x_i$ is an element of $U^{\perp}$ iff the $a_i$ ## satisfy the equations ## $\sum_{i=1}^n ( \sum_{j=1}^n v_{kj} \kappa(x_i,x_j) ) a_i = 0$ for ## $k = 1, \ldots, s$. ##
InstallMethod( KappaPerp, "for a Lie algebra and a vector space",
IsIdenticalObj,
[ IsAlgebra and IsLieAlgebra, IsVectorSpace ], 0, function( L, U )
local R, # left acting domain of `L'
B, # a basis of L
kap, # the matrix of the Killing form w.r.t. `B'
A, # the matrix of the equation system
n, # the dimension of L
s, # the dimension of U
v, # coefficient list of the basis of U w.r.t. the basis of L
i,j,k, # loop variables
bas; # the basis of the solution space
R:= LeftActingDomain( L );
B:= Basis( L );
n:= Dimension( L );
s:= Dimension( U );
if s = 0 or n = 0then
return L; fi;
v:= List( BasisVectors( Basis( U ) ),
x -> Coefficients( B, x ) );
A:= NullMat( n, s, R );
kap:= KillingMatrix( B );
# Compute the equations that define the subspace. for k in [ 1..s ] do for i in [ 1..n ] do for j in [ 1..n ] do
A[i][k]:= A[i][k] + v[k][j] * kap[i][j];
od;
od;
od;
# Solve the equation system.
bas:= NullspaceMat( A );
# Extract the generators.
bas:= List( bas, x -> LinearCombination( B, x ) );
return SubspaceNC( L, bas, "basis" );
end );
############################################################################# ## #M AdjointMatrix( <B>, <x> ) ## ## If the basis vectors are $(b-1, b_2, \ldots, b_n)$, and ## $x = \sum_{i=1}^n x_i b_i$ then $b_j$ is mapped to ## $[ x, b_j ] = \sum_{i=1}^n x_i [ b_i b_j ] ## = \sum_{k=1}^n ( \sum_{i=1}^n x_i c_{ijk} ) b_k$, ## so the entry in the $k$-th row and the $j$-th column of the adjoint ## matrix is $\sum_{i=1}^n x_i c_{ijk}$. ## ## Note that $ad_x$ is a left multiplication, so also the action of the ## adjoint matrix is from the left (i.e., on column vectors). ##
InstallMethod( AdjointMatrix, "for a basis of a Lie algebra, and an element",
IsCollsElms,
[ IsBasis, IsRingElement ], 0, function( B, x )
local n, # dimension of the algebra
T, # structure constants table w.r. to `B'
zerovector, # zero of the field
M, # adjoint matrix, result
j, i, l, # loop variables
cij, # structure constants vector
k, # one position in structure constants vector
row; # one row of `M'
x:= Coefficients( B, x );
n:= Length( BasisVectors( B ) );
T:= StructureConstantsTable( B );
zerovector:= [ 1 .. n ] * Last(T);
M:= []; for j in [ 1 .. n ] do
row:= ShallowCopy( zerovector ); for i in [ 1 .. n ] do
cij:= T[i][j]; for l in [ 1 .. Length( cij[1] ) ] do
k:= cij[1][l];
row[k]:= row[k] + x[i] * cij[2][l];
od;
od;
M[j]:= row;
od;
return TransposedMat( M ); end );
#T general function for arbitrary algebras? (right/left multiplication) #T RegularRepresentation: right multiplication satisfies M_{xy} = M_x M_y #T is just the negative of the adjoint ...
############################################################################# ## #M RightDerivations( <B> ) ## ## Let $n$ be the dimension of $A$. ## We start with $n^2$ indeterminates $D = [ d_{i,j} ]_{i,j}$ which ## means that $D$ maps $b_i$ to $\sum_{j=1}^n d_{ij} b_j$. ## ## (Note that this is row convention.) ## ## This leads to the following linear equation system in the $d_{ij}$. ## $\sum_{k=1}^n ( c_{ijk} d_{km} - c_{kjm} d_{ik} - c_{ikm} d_{jk} ) = 0$ ## for all $1 \leq i, j, m \leq n$. ## The solution of this system gives us a vector space basis of the ## algebra of derivations. ##
InstallMethod( RightDerivations, "method for a basis of an algebra",
true,
[ IsBasis ], 0, function( B )
local T, # structure constants table w.r. to 'B'
L, # underlying Lie algebra
R, # left acting domain of 'L'
n, # dimension of 'L'
eqno,offset,
A,
i, j, k, m,
M; # the Lie algebra of derivations
if not IsAlgebra( UnderlyingLeftModule( B ) ) then
Error( "<B> must be a basis of an algebra" ); fi;
if IsLieAlgebra( UnderlyingLeftModule( B ) ) then
offset:= 1; else
offset:= 0; fi;
T:= StructureConstantsTable( B );
L:= UnderlyingLeftModule( B );
R:= LeftActingDomain( L );
n:= Dimension( L );
if n = 0then
return NullAlgebra( R ); fi;
# The rows in the matrix of the equation system are indexed # by the $d_{ij}$; the $((i-1) n + j)$-th row belongs to $d_{ij}$.
# Construct the equation system. if offset = 1then
A:= NullMat( n^2, (n-1)*n*n/2, R ); else
A:= NullMat( n^2, n^3, R ); fi;
eqno:= 0; for i in [ 1 .. n ] do for j in [ offset*i+1 .. n ] do for m in [ 1 .. n ] do
eqno:= eqno+1; for k in [ 1 .. n ] do
A[ (k-1)*n+m ][eqno]:= A[ (k-1)*n+m ][eqno] +
SCTableEntry( T,i,j,k );
A[ (i-1)*n+k ][eqno]:= A[ (i-1)*n+k ][eqno] -
SCTableEntry( T,k,j,m );
A[ (j-1)*n+k ][eqno]:= A[ (j-1)*n+k ][eqno] -
SCTableEntry( T,i,k,m );
od;
od;
od;
od;
# Solve the equation system. # Note that if `L' is a Lie algebra and $n = 1$ the matrix is empty.
if n = 1 and offset = 1then
A:= [ [ One( R ) ] ]; else
A:= NullspaceMatDestructive( A ); fi;
# Construct the generating matrices from the vectors.
A:= List( A, v -> List( [ 1 .. n ],
i -> v{ [ (i-1)*n + 1 .. i*n ] } ) );
# Construct the Lie algebra. if IsEmpty( A ) then
M:= AlgebraByGenerators( R, [],
LieObject( Immutable( NullMat( n, n, R ) ) ) ); else
A:= List( A, LieObject );
M:= AlgebraByGenerators( R, A );
UseBasis( M, A ); fi;
# Return the derivations.
return M; end );
############################################################################# ## #M LeftDerivations( <B> ) ## ## Let $n$ be the dimension of $A$. ## We start with $n^2$ indeterminates $D = [ d_{i,j} ]_{i,j}$ which ## means that $D$ maps $b_i$ to $\sum_{j=1}^n d_{ji} b_j$. ## ## (Note that this is column convention.) ##
InstallMethod( LeftDerivations, "method for a basis of an algebra",
true,
[ IsBasis ], 0, function( B )
local T, # structure constants table w.r. to 'B'
L, # underlying Lie algebra
R, # left acting domain of 'L'
n, # dimension of 'L'
eqno,offset,
A,
i, j, k, m,
M; # the Lie algebra of derivations
if not IsAlgebra( UnderlyingLeftModule( B ) ) then
Error( "<B> must be a basis of an algebra" ); fi;
if IsLieAlgebra( UnderlyingLeftModule( B ) ) then
offset:= 1; else
offset:= 0; fi;
T:= StructureConstantsTable( B );
L:= UnderlyingLeftModule( B );
R:= LeftActingDomain( L );
n:= Dimension( L );
if n = 0then
return NullAlgebra( R ); fi;
# The rows in the matrix of the equation system are indexed # by the $d_{ij}$; the $((i-1) n + j)$-th row belongs to $d_{ij}$.
# Construct the equation system. if offset = 1then
A:= NullMat( n^2, (n-1)*n*n/2, R ); else
A:= NullMat( n^2, n^3, R ); fi;
eqno:= 0; for i in [ 1 .. n ] do for j in [ offset*i+1 .. n ] do for m in [ 1 .. n ] do
eqno:= eqno+1; for k in [ 1 .. n ] do
A[ (m-1)*n+k ][eqno]:= A[ (m-1)*n+k ][eqno] +
SCTableEntry( T,i,j,k );
A[ (k-1)*n+i ][eqno]:= A[ (k-1)*n+i ][eqno] -
SCTableEntry( T,k,j,m );
A[ (k-1)*n+j ][eqno]:= A[ (k-1)*n+j ][eqno] -
SCTableEntry( T,i,k,m );
od;
od;
od;
od;
# Solve the equation system. # Note that if `L' is a Lie algebra and $n = 1$ the matrix is empty.
if n = 1 and offset = 1then
A:= [ [ One( R ) ] ]; else
A:= NullspaceMatDestructive( A ); fi;
# Construct the generating matrices from the vectors.
A:= List( A, v -> List( [ 1 .. n ],
i -> v{ [ (i-1)*n + 1 .. i*n ] } ) );
# Construct the Lie algebra. if IsEmpty( A ) then
M:= AlgebraByGenerators( R, [],
LieObject( Immutable( NullMat( n, n, R ) ) ) ); else
A:= List( A, LieObject );
M:= AlgebraByGenerators( R, A );
UseBasis( M, A ); fi;
# Return the derivations.
return M; end );
############################################################################# ## #M KillingMatrix( <B> ) ## ## We have $\kappa_{i,j} = \sum_{k,l=1}^n c_{jkl} c_{ilk}$ if $c_{ijk}$ ## are the structure constants w.r. to <B>. ## ## (The matrix is symmetric, no matter whether the multiplication is ## (anti-)symmetric.) ##
InstallMethod( KillingMatrix, "for a basis of a Lie algebra",
true,
[ IsBasis ], 0, function( B )
local T, # s.c. table w.r. to `B'
L, # the underlying algebra
R, # left acting domain of `L'
kappa, # the matrix of the killing form, result
n, # dimension of `L'
zero, # the zero of `R'
i, j, k, t, # loop variables
row, # one row of `kappa'
val, # one entry of `kappa'
cjk; # `T[j][k]'
T:= StructureConstantsTable( B );
L:= UnderlyingLeftModule( B );
R:= LeftActingDomain( L );
n:= Dimension( L );
kappa:= [];
zero:= Zero( R );
for i in [ 1 .. n ] do
row:= []; for j in [ 1 .. i ] do
val:= zero; for k in [ 1 .. n ] do
cjk:= T[j][k]; for t in [ 1 .. Length( cjk[1] ) ] do
val:= val + cjk[2][t] * SCTableEntry( T, i, cjk[1][t], k );
od;
od;
row[j]:= val; if i <> j then
kappa[j][i]:= val; fi;
od;
kappa[i]:= row;
od;
# Return the result.
return kappa; end );
############################################################################## ## #M AdjointBasis( <B> ) ## ## The input is a basis of a (Lie) algebra $L$. ## This function returns a particular basis $C$ of the matrix space generated ## by $ad L$, namely a basis consisting of elements of the form $ad x_i$ ## where $x_i$ is a basis element of <B>. ## An extra component `indices' is added to this space. ## This is a list of integers such that `ad <B>.basisVectors[ indices[i] ]' ## is the `i'-th basis vector of <C>, for i in [1..Length(indices)]. ## (This list is added in order to be able to identify the basis element of ## <B> with the property that its adjoint matrix is equal to a given basis ## vector of <C>.) ##
InstallMethod( AdjointBasis, "for a basis of a Lie algebra",
true,
[ IsBasis ], 0, function( B )
local bb, # the basis vectors of `B'
n, # the dimension of `B'
F, # the field over which the algebra is defined
adL, # a list of matrices that form a basis of adLsp
adLsp, # the matrix space spanned by ad L
inds, # the list of indices
i, # loop variable
adi, # the adjoint matrix of the i-th basis vector of `B'
adLbas; # the basis of `adLsp' compatible with `adL'
bb:= BasisVectors( B );
n:= Length( bb );
F:= LeftActingDomain( UnderlyingLeftModule( B ) );
adL:= [];
adLsp:= MutableBasis( F, [ NullMat(n,n,F) ] ); #T better declare the zero ?
inds:= []; for i in [1..n] do
adi:= AdjointMatrix( B, bb[i] ); if not IsContainedInSpan( adLsp, adi ) then
Add( adL, adi );
Add( inds, i );
CloseMutableBasis( adLsp, adi ); fi;
od;
if adL = [ ] then
adLbas:= Basis( VectorSpace( F, [ ], NullMat( n, n, F ) ) ); else
adLbas:= Basis( VectorSpace( F, adL ), adL ); fi;
SetIndicesOfAdjointBasis( adLbas, inds );
return adLbas; end );
############################################################################## ## #M IsRestrictedLieAlgebra( <L> ) . . . . . . . . . . . . . for a Lie algebra ## ## A Lie algebra <L> is defined to be {\em restricted} when it is defined ## over a field of characteristic $p \neq 0$, and for every basis element ## $x$ of <L> there exists $y\in <L>$ such that $(ad x)^p = ad y$ ## (see Jacobson, p. 190). ##
InstallMethod( IsRestrictedLieAlgebra, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local F, # the field over which L is defined
B, # the basis of L
p, # the characteristic of F
adL, # basis for the (matrix) vector space generated by ad L
v; # loop over basis vectors of adL
F:= LeftActingDomain( L );
p:= Characteristic( F ); if p = 0then
return false; fi;
B:= Basis( L );
adL:= AdjointBasis( B );
# Check if ad(L) is closed under the p-th power operation. for v in BasisVectors( adL ) do if not v^p in UnderlyingLeftModule( adL ) then
return false; fi;
od;
local si, # a function of two arguments: seqs, a list of sequences, # and l, a list containing the two arguments of the # function s_i. The list seqs contains # all possible sequences of i-1 1's and p-2-i+1 2's # This function returns the value of s_i(l[1],l[2])
j,k, # loop variables
p, # the characteristic of F
combs, # the list of all i-1 element subsets of {1,2,\ldots, p-2} # it serves to make the list seqs
v, # a vector of 1's and 2's
seqs; # the list of all sequences of 1's and 2's of length p-2, # with i-1 1's and p-2 2's serving as input for si # for example, the sequence [1,1,2] means the element # [[[[x,y],x],x],y] (the first element [x,y] is present # 1 1 2 in all terms of the sum s_i(x,y)).
si:= function( seqs, l )
local x,
j,k,
sum;
for j in [1..Length(seqs)] do
x:= l[1]*l[2]; for k in seqs[j] do
x:= x*l[k];
od; if j=1then
sum:= x; else
sum:= sum+x; fi;
od;
return ( i * One( F ) )^(-1)*sum; end;
p:= Characteristic( F );
combs:= Combinations( [1..p-2], i-1 );
# Now all sequences of 1's and 2's of length p and containing i-1 1's # are constructed the 1's in the jth sequence are put at the positions # contained in combs[j].
seqs:=[]; for j in [1..Length( combs )] do
v:= List( [1..p-2], x -> 2); for k in combs[j] do
v[k]:= 1;
od;
Add( seqs, v );
od;
return arg -> si( seqs, arg ); end );
local F, # the coefficients domain
p; # the characteristic of `F'
F:= LeftActingDomain( L );
p:= Characteristic( F );
return List( [ 1 .. p-1 ], i -> PowerSi( F , i ) ); end );
############################################################################## ## #F PthPowerImage( <B>, <x> ) ##
BindGlobal("PTHPOWERIMAGE_PPI_VEC", function(L,zero,p,bv,pmap,cf,x)
local
n, # the dimension of L
s, # the list of s_i functions
im, # the image of x under the p-th power map
i,j; # loop variables
n:= Dimension( L );
s:= PowerS( L );
im:= Zero( L );
# First the sum of all $\alpha_i^p x_i^{[p]}$ is calculated. for i in [1..n] do
im:= im + cf[i]^p * pmap[i];
od;
# To this the double sum of all # $s_i(\alpha_j x_j, \sum_{k=j+1}^n \alpha_k x_k)$ # is added. for j in [1..n-1] do if cf[j] <> zero then
x:= x - cf[j] * bv[j]; for i in [1..p-1] do
im:= im + s[i]( [cf[j]*bv[j],x] );
od; fi;
od;
return im; end);
InstallMethod( PthPowerImage, "for a basis of an algebra, and a ring element",
IsCollsElms,
[ IsBasis, IsRingElement ], 0, function( B, x )
local L, # the Lie algebra of which B is a basis
F, # the coefficients domain of `L'
n, # the dimension of L
p, # the characteristic of the ground field
s, # the list of s_i functions
pmap, # the list containing x_i^{[p]}
cf, # the coefficients of x wrt the basis of L
im, # the image of x under the p-th power map
i,j, # loop variables
zero, # zero of `F'
bv, # basis vectors of `B'
adx, # adjoint matrix of x
adL; # a basis of the matrix space ad L
L:= UnderlyingLeftModule( B ); if not IsLieAlgebra( L ) then
TryNextMethod(); fi;
F:= LeftActingDomain( L );
p:= Characteristic( F );
if Dimension( LieCentre( L ) ) = 0then
# We calculate the inverse image $ad^{-1} ((ad x)^p)$.
adx:= AdjointMatrix( B, x );
adL:= AdjointBasis( B );
adx:= adx^p;
cf:= Coefficients( adL, adx );
return LinearCombination( B, cf );
else
return PTHPOWERIMAGE_PPI_VEC(L,Zero(F),p,BasisVectors(B),PthPowerImages(B),Coefficients(B,x),x); fi; end );
InstallMethod( PthPowerImage, "for an element of a restricted Lie algebra",
[ IsJacobianElement ], # weaker filter, we maybe only discovered later # that the algebra is restricted function(x)
local fam;
fam := FamilyObj(x); if not IsBound(fam!.pMapping) then TryNextMethod(); fi;
return PTHPOWERIMAGE_PPI_VEC(fam!.fullSCAlgebra,fam!.zerocoeff,Characteristic(fam),fam!.basisVectors,fam!.pMapping,ExtRepOfObj(x),x); end);
InstallMethod( PthPowerImage, "for an element of a restricted Lie algebra and an integer",
[ IsJacobianElement, IsInt ], function(x,n)
local fam;
fam := FamilyObj(x); if not IsBound(fam!.pMapping) then TryNextMethod(); fi; while n>0do
x := PTHPOWERIMAGE_PPI_VEC(fam!.fullSCAlgebra,fam!.zerocoeff,Characteristic(fam),fam!.basisVectors,fam!.pMapping,ExtRepOfObj(x),x);
n := n-1;
od;
return x; end);
InstallMethod( PClosureSubalgebra, "for a subalgebra of restricted jacobian elements",
[ IsLieAlgebra and IsJacobianElementCollection ], function(A)
local i, oldA;
repeat
oldA := A; for i in Basis(oldA) do
A := ClosureLeftModule(A,PthPowerImage(i));
od;
until A=oldA;
return A; end);
############################################################################# ## #M PthPowerImages( <B> ) . . . . . . . . . . . for a basis of a Lie algebra ##
InstallMethod( PthPowerImages, "for a basis of a Lie algebra",
true,
[ IsBasis ], 0, function( B )
local L, # the underlying algebra
p, # the characteristic of `L'
adL, # a basis of the matrix space spanned by ad L
basL; # the list of basis vectors `b' of `B' such that # `ad b' is a basis vector of `adL'
L:= UnderlyingLeftModule( B ); if not IsRestrictedLieAlgebra( L ) then
Error( "<L> must be a restricted Lie algebra" ); fi;
p:= Characteristic( LeftActingDomain( L ) );
adL:= AdjointBasis( B );
if Dimension( UnderlyingLeftModule( adL ) ) = 0then
# The algebra is abelian.
return List( BasisVectors( B ), x -> Zero( L ) );
fi;
# Now `IndicesOfAdjointBasis( adL )' is a list of indices with `i'-th # entry the position of the basis vector of `B' # whose adjoint matrix is the `i'-th basis vector of `adL'.
basL:= BasisVectors( B ){ IndicesOfAdjointBasis( adL ) };
# We calculate the coefficients of $x_i^{[p]}$ wrt the basis basL.
return List( BasisVectors( B ),
x -> Coefficients( adL, AdjointMatrix( B, x ) ^ p ) * basL ); #T And why do you compute the adjoint matrices again? #T Aren't they stored as basis vectors in adL ? end );
############################################################################ ## #M CartanSubalgebra( <L> ) ## ## A Cartan subalgebra of the Lie algebra <L> is by definition a nilpotent ## subalgebra equal to its own normalizer in <L>. ## ## By definition, an Engel subalgebra of <L> is the generalized eigenspace ## of a non nilpotent element, corresponding to the eigenvalue 0. ## In a restricted Lie algebra of characteristic p we have that every Cartan ## subalgebra of an Engel subalgebra of <L> is a Cartan subalgebra of <L>. ## Hence in this case we construct a decreasing series of Engel subalgebras. ## When it becomes stable we have found a Cartan subalgebra. ## On the other hand, when <L> is not restricted and is defined over a field ## $F$ of cardinality greater than the dimension of <L> we can proceed as ## follows. ## Let $a$ be a non nilpotent element of <L> and $K$ the corresponding ## Engel subalgebra. Furthermore, let $b$ be a non nilpotent element of $K$. ## Then there is an element $c \in F$ such that $a + c ( b - a )$ has an ## Engel subalgebra strictly contained in $K$ ## (see Humphreys, proof of Lemma A, p 79). ##
InstallMethod( CartanSubalgebra, "for a Lie algebra",
true,
[ IsLieAlgebra ], 0, function( L )
local n, # the dimension of L
F, # coefficients domain of `L'
root, # prim. root of `F' if `F' is finite
K, # a subalgebra of L (on termination a Cartan subalg.)
a,b, # (non nilpotent) elements of L
A, # matrix of the equation system (ad a)^n(x)=0
bas, # basis of the solution space of Ax=0
sp, # the subspace of L generated by bas
found,ready, # boolean variables
c, # an element of `F'
newelt, # an element of L of the form a+c*(b-a)
i; # loop variable
n:= Dimension(L);
F:= LeftActingDomain( L );
if IsRestrictedLieAlgebra( L ) then
K:= L; while true do
a:= NonNilpotentElement( K );
if a = fail then # `K' is a nilpotent Engel subalgebra, hence a Cartan subalgebra.
return K; fi;
# `a' is a non nilpotent element of `K'. # We construct the generalized eigenspace of this element w.r.t. # the eigenvalue 0. This is a subalgebra of `K' and of `L'.
A:= TransposedMat( AdjointMatrix( Basis( K ), a));
A:= A ^ Dimension( K );
bas:= NullspaceMat( A );
bas:= List( bas, x -> LinearCombination( Basis( K ), x ) );
K:= SubalgebraNC( L, bas, "basis");
od;
elif n < Size( F ) then
# We start with an Engel subalgebra. If it is nilpotent # then it is a Cartan subalgebra and we are done. # Otherwise we make it smaller.
a:= NonNilpotentElement( L );
if a = fail then # `L' is nilpotent.
return L; fi;
# `K' will be the Engel subalgebra corresponding to `a'.
A:= TransposedMat( AdjointMatrix( Basis( L ), a ) );
A:= A^n;
bas:= NullspaceMat( A );
bas:= List( bas, x -> LinearCombination( Basis( L ), x ) );
K:= SubalgebraNC( L, bas, "basis");
# We locate a nonnilpotent element in this Engel subalgebra.
b:= NonNilpotentElement( K );
# If `b = fail' then `K' is nilpotent and we are done.
ready:= ( b = fail );
while not ready do
# We locate an element $a + c*(b-a)$ such that the Engel subalgebra # belonging to this element is smaller than the Engel subalgebra # belonging to `a'. # We do this by checking a few values of `c' # (At most `n' values of `c' will not yield a smaller subalgebra.)
sp:= VectorSpace( F, BasisVectors( Basis(K) ), "basis");
found:= false; if Characteristic( F ) = 0then
c:= 0; else
root:= PrimitiveRoot( F );
c:= root; fi; while not found do
if Characteristic( F ) = 0then
c:= c+1; else
c:= c*root; fi;
newelt:= a+c*(b-a);
# Calculate the Engel subalgebra belonging to `newelt'.
A:= TransposedMat( AdjointMatrix( Basis( K ), newelt ) );
A:= A^Dimension( K );
bas:= NullspaceMat( A );
bas:= List( bas, x -> LinearCombination( Basis( K ), x ) );
# We have found a smaller subalgebra if the dimension is smaller # and new basis elements are contained in the old space.
found:= Length( bas ) < Dimension( K );
i:= 1; while i <= Length( bas ) and found do if not bas[i] in sp then
found:= false; fi;
i:= i+1;
od;
od;
# If `b = fail' then `K' is nilpotent and we are done.
ready:= b = fail;
od;
return K;
else
# the field over which <L> is defined is too small
TryNextMethod();
fi; end );
############################################################################## ## #M AdjointAssociativeAlgebra( <L>, <K> ) ## ## This function calculates a basis of the associative matrix algebra ## generated by ad_L K, where <K> is a subalgebra of <L>. ## If {x_1,\ldots ,x_n} is a basis of K, then this algebra is spanned ## by all words ## ad x_{i_1}\cdots ad x_{i_t} ## where t>0. ## The degree of such a word is t. ## The algorithm first calculates a maximal linearly independent set ## of words of degree 1, then of degree 2 and so on. ## Since ad x ad y -ady ad x = ad [x,y], we have that we only have ## to consider words where i_1\leq i_2\leq \cdots \leq i_t. ##
InstallMethod( AdjointAssociativeAlgebra, "for a Lie algebra and a subalgebra",
true,
[ IsAlgebra and IsLieAlgebra, IsAlgebra and IsLieAlgebra ], 0, function( L, K )
local n, # the dimension of L
F, # the field of L
asbas, # a list containing the basis elts. of the assoc. alg.
highdeg, # a list of the elements of the highest degree computed # so far
degree1, # a list of elements of degree 1 (i.e. ad x_i)
lowinds, # a list of indices such that lowinds[i] is the smallest # index in the word highdeg[i]
hdeg, # the new highdeg constructed each step
linds, # the new lowinds constructed each step
i,j,k, # loop variables
ind, # an index
m, # a matrix
posits, # a list of positions in matrices: # posits[i] is a list of the form [p,q] such that # the matrix asbas[i] has a nonzero entry at position # [p][q] and furthermore the matrices asbas[j] with j>i # will have a zero at that position (so the basis # constructed will be in `upper triangular form')
l1,l2, # loop variables
found; # a boolean
F:= LeftActingDomain( L );
if Dimension( K ) = 0then
return Algebra( F, [ [ [ Zero(F) ] ] ] ); elif IsLieAbelian( L ) then
return Algebra( F, [ AdjointMatrix( Basis( L ),
GeneratorsOfAlgebra( K )[1] ) ] ); fi;
n:= Dimension( L );
# Initialisations that ensure that the first step of the loop will select # a maximal linearly independent set of matrices of degree 1.
degree1:= List( BasisVectors( Basis(K) ),
x -> AdjointMatrix( Basis(L), x ) );
posits := [ [ 1, 1 ] ];
highdeg := [ IdentityMat( n, F ) ];
asbas := [ Immutable( highdeg[1] ) ];
lowinds := [ Dimension( K ) ];
# If after some steps all words of degree t (say) can be reduced modulo # lower degree, then all words of degree >t can be reduced to linear # combinations of words of lower degree. # Hence in that case we are done.
while not IsEmpty( highdeg ) do
hdeg:= [];
linds:= [];
for i in [1..Length(highdeg)] do
# Now we multiply all elements `highdeg[i]' with all possible # elements of degree 1 (i.e. elements having an index <= the lowest # index of the word `highdeg[i]')
ind:= lowinds[i]; for j in [1..ind] do
m:= degree1[j]*highdeg[i];
# Now we first reduce `m' on the basis computed so far # and then add it to the basis.
for k in [1..Length(posits)] do
l1:= posits[k][1];
l2:= posits[k][2];
m:= m-(m[l1][l2]/asbas[k][l1][l2])*asbas[k];
od;
if not IsZero( m ) then
#'m' is not an element of the span of `asbas'
Add( hdeg, m );
Add( linds, j );
Add( asbas, m);
# Now we look for a nonzero entry in `m' # and add the position of that entry to `posits'.
found:= false;
l1:= 1; l2:= 1; while not found do if not IsZero( m[l1][l2] ) then
Add( posits, [l1,l2] );
found:= true; else if l2 = n then
l1:= l1+1;
l2:= 1; else
l2:= l2+1; fi; fi;
od;
fi;
od;
od;
if lowinds = [Dimension(K)] then
# We are in the first step and hence `degree1' must be made # equal to the linearly independent set that we have just calculated.
############################################################################## ## #M LieNilRadical( <L> ) ## ## Let $p$ be the characteristic of the coefficients field of <L>. ## If $p=0$ the we use the following characterisation of the LieNilRadical: ## Let $S$ be the solvable radical of <L>. And let $H$ be a Cartan subalgebra ## of $S$. Decompose $S$ as $S = H \oplus S_1(H)$, where $S_1(H)$ is the ## Fitting 1-component of the adjoint action of $H$ on $S$. Let $H*$ be the ## associative algebra generated by $ad H$, then $S_1(H)$ is the intersection ## of the spaces $H*^i( S )$ for $i>0$. Let $R$ be the radical of the ## algebra $H*$. Then the LieNilRadical of <L> consists of $S_1(H)$ together ## with all elements $x$ in $H$ such that $ad x\in R$. This last space ## is also characterised as the space of all elements $x$ such that ## $ad x$ lies in the vector space spanned by all nilpotent parts of all ## $ad h$ for $h\in H$. ## ## In the case where $p>0$ we calculate the radical of the associative ## matrix algebra $A$ generated by $ad `L'$. ## The nil radical is then equal to $\{ x\in L \mid ad x \in A \}$. ##
InstallMethod( LieNilRadical, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local F, # the coefficients domain of `L'
p, # the characteristic of `F'
bv, # basis vectors of a basis of `L'
S, # the solvable radical of `L'
H, # Cartan subalgebra of `S'
HS, # Fitting 1-component of `S' wrt `H'
adH, # list of ad x for x in a basis of `H'
n, # dimension of `L'
t, # the dimension of an ideal
eqs, # equation set
I, # basis vectors of an ideal of `L'
i,j,k, # loop variables
sol, # solution set
adL, # list of matrices ad x where x runs through a basis of # `L'
A, # an associative algebra
R, # the radical of this algebra
B; # list of basis vectors of R
F:= LeftActingDomain( L );
p:= Characteristic( F );
if p = 0then
# The LieNilRadical of <L> is equal to # the LieNilRadical of its solvable radical.
S:= LieSolvableRadical( L );
n:= Dimension( S );
if n in [ 0, 1 ] then return S; fi;
H:= CartanSubalgebra(S);
if Dimension(H) = n then return S; fi;
# We calculate the Fitting 1-component $S_1(H)$.
HS:= ProductSpace( H, S ); while Dimension( HS ) + Dimension( H ) <> n do
HS:= ProductSpace( H, HS );
od;
if Dimension( H ) = 1then
return IdealNC( L, BasisVectors(Basis(HS)), "basis" ); fi;
# Now we compute the intersection of `R' and `<ad H>'.
adH:= List( BasisVectors(Basis(H)), x -> AdjointMatrix(Basis(S),x));
R:= RadicalOfAlgebra( AdjointAssociativeAlgebra( S, H ) );
B:= BasisVectors( Basis( R ) );
eqs:= NullMat(Dimension(H)+Dimension(R),n^2,F); for i in [1..n] do for j in [1..n] do for k in [1..Dimension(H)] do
eqs[k][j+(i-1)*n]:= adH[k][i][j];
od; for k in [1..Dimension(R)] do
eqs[Dimension(H)+k][j+(i-1)*n]:= B[k][i][j];
od;
od;
od;
sol:= NullspaceMat( eqs );
I:= List( sol, x-> LinearCombination( Basis(H), x{[1..Dimension(H)]} ) );
Append( I, BasisVectors( Basis( HS ) ) );
return IdealNC( L, I, "basis" );
else
n:= Dimension( L );
bv:= BasisVectors( Basis(L) );
adL:= List( bv, x -> AdjointMatrix(Basis(L),x) );
A:= AdjointAssociativeAlgebra( L, L );
R:= RadicalOfAlgebra( A );
if Dimension( R ) = 0then
# In this case the intersection of `ad L' and `R' is the centre of L.
return LieCentre( L );
fi;
B:= BasisVectors( Basis( R ) );
t:= Dimension( R );
# Now we compute the intersection of `R' and `<ad L>'.
eqs:= NullMat(n+t,n*n,F); for i in [1..n] do for j in [1..n] do for k in [1..n] do
eqs[k][j+(i-1)*n]:= adL[k][i][j];
od; for k in [1..t] do
eqs[n+k][j+(i-1)*n]:= -B[k][i][j];
od;
od;
od;
sol:= NullspaceMat( eqs );
I:= List( sol, x-> LinearCombination( bv, x{[1..n]} ) );
return SubalgebraNC( L, I, "basis" );
fi;
end );
############################################################################## ## #M LieSolvableRadical( <L> ) ## ## In characteristic zero, the solvable radical of the Lie algebra <L> is ## just the orthogonal complement of $[ <L> <L> ]$ w.r.t. the Killing form. ## ## In characteristic $p > 0$, the following fact is used: ## $R( <L> / NR( <L> ) ) = R( <L> ) / NR( <L> )$ where ## $R( <L> )$ denotes the solvable radical of $L$ and $NR( <L> )$ its ## nil radical). ##
InstallMethod( LieSolvableRadical, "for a Lie algebra",
true,
[ IsLieAlgebra ], 0, function( L )
local LL, # the derived algebra of L
n, # the nil radical of L
B, # a basis of the solvable radical of L
quo, # the quotient L/n
r1, # the solvable radical of L/n
hom; # the canonical map L -> L/n
if Characteristic( LeftActingDomain( L ) ) = 0then
if Dimension( n ) = 0 or Dimension( n ) = Dimension( L ) then
return n; fi;
hom:= NaturalHomomorphismByIdeal( L, n );
quo:= ImagesSource( hom );
r1:= LieSolvableRadical( quo );
B:= BasisVectors( Basis( r1 ) );
B:= List( B, x -> PreImagesRepresentative( hom, x ) );
Append( B, BasisVectors( Basis( n ) ) );
fi;
SetIsLieSolvable( L, Length( B ) = Dimension( L ) );
return IdealNC( L, B, "basis");
end );
############################################################################## ## #M DirectSumDecomposition( <L> ) ## ## This function calculates a list of ideals of `L' such that `L' is equal ## to the direct sum of them. ## The existence of a decomposition of `L' is equivalent to the existence ## of a nontrivial idempotent in the centralizer of `ad L' in the full ## matrix algebra `M_n(F)'. In the general case we try to find such ## idempotents. ## In the case where the Killing form of `L' is nondegenerate we can use ## a more elegant method. In this case the action of the Cartan subalgebra ## will `identify' the direct summands. ##
InstallMethod( DirectSumDecomposition, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local F, # The field of `L'.
BL, # basis of `L'
bvl, # basis vectors of `BL'
n, # The dimension of `L'.
m, # An integer.
set, # A list of integers.
C, # The centre of `L'.
bvc, # basis vectors of a basis of `C'
D, # The derived subalgebra of `L'.
CD, # The intersection of `C' and `D'.
H, # A Cartan subalgebra of `L'.
BH, # basis of `H'
B, # A list of bases of subspaces of `L'.
cf, # Coefficient list.
comlist, # List of commutators.
ideals, # List of ideals.
bb, # List of basis vectors.
B1,B2, # Bases of the ideals.
sp, # A vector space.
x, # An element of `sp'.
b, # A list of basis vectors.
bas,res, # Bases of associative algebras.
i,j,k,l, # Loop variables.
centralizer, # The centralizer of `adL' in the matrix algebra.
Rad, # The radical of `centralizer'.
M,mat, # Matrices.
facs, # A list of factors of a polynomial.
f, # Polynomial.
contained, # Boolean variable.
adL, # A basis of the matrix space `ad L'.
Q, # The factor algebra `centralizer/Rad'
q, # Number of elements of the field of `L'.
ei,ni,E, # Elements from `centralizer'
hom, # A homomorphism.
id, # A list of idempotents.
vv; # A list of vectors.
F:= LeftActingDomain( L );
n:= Dimension( L ); if n=0then
return [ L ]; fi;
if RankMat( KillingMatrix( Basis( L ) ) ) = n then
# The algorithm works as follows. # Let `H' be a Cartan subalgebra of `L'. # First we decompose `L' into a direct sum of subspaces `B[i]' # such that the minimum polynomial of the adjoint action of an element # of `H' restricted to `B[i]' is irreducible. # If `L' is a direct sum of ideals, then each of these subspaces # will be contained in precisely one ideal. # If the field `F' is big enough then we can look for a splitting # element in `H'. # This is an element `h' such that the minimum polynomial of `ad h' # has degree `dim L - dim H + 1'. # If the size of the field is bigger than `2*m' then there is a # powerful randomised algorithm (Las Vegas type) for finding such an # element. We just take a random element from `H' and with probability # > 1/2 this will be a splitting element. # If the field is small, then we use decomposable elements instead.
H:= CartanSubalgebra( L );
BH:= Basis( H );
BL:= Basis( L );
m:= (( n - Dimension(H) ) * ( n - Dimension(H) + 2 )) / 8;
if2*m < Size(F) and ( not Characteristic( F ) in [2,3] ) then
set:= [ -m .. m ];
repeat
cf:= List([ 1 .. Dimension( H ) ], x -> Random( set ) );
x:= LinearCombination( BH, cf );
M:= AdjointMatrix( BL, x );
f:= CharacteristicPolynomial( F, F, M );
f:= f/Gcd( f, Derivative( f ) );
until DegreeOfLaurentPolynomial( f )
= Dimension( L ) - Dimension( H ) + 1;
# We decompose the action of the splitting element:
facs:= Factors( PolynomialRing( F ), f );
B:= []; for i in facs do
Add( B, List( NullspaceMat( TransposedMat( Value( i, M ) ) ),
x -> LinearCombination( BL, x ) ) );
od;
B:= Filtered( B, x -> not ( x[1] in H ) );
else
# Here `L' is a semisimple Lie algebra over a small field or a field # of characteristic 2 or 3. This means that # the existence of splitting elements is not assured. So we work # with decomposable elements rather than with splitting ones. # A decomposable element is an element from the associative # algebra `T' generated by `ad H' that has a reducible minimum # polynomial. Let `V' be a stable subspace (under the action of `H') # computed in the process. Then we proceed as follows. # We choose a random element from `T' and restrict it to `V'. If this # element has an irreducible minimum polynomial of degree equal to # the dimension of the associative algebra `T' restricted to `V', # then `V' is irreducible. On the other hand, # if this polynomial is reducible, then we decompose `V'.
# `bas' will be a basis of the associative algebra generated by # `ad H'. The computation of this basis is facilitated by the fact # that we know the dimension of this algebra.
bas:= List( BH, x -> AdjointMatrix( Basis( L ), x ) );
sp:= MutableBasis( F, bas );
k:=1; l:=1; while k<=Length(bas) do if Length(bas)=Dimension(L)-Dimension(H) then break; fi;
M:= bas[ k ]*bas[ l ]; if not IsContainedInSpan( sp, M ) then
CloseMutableBasis( sp, M );
Add( bas, M ); fi; if l < Length(bas) then l:=l+1; else k:=k+1; l:=1; fi;
od;
Add( bas, Immutable( IdentityMat( Dimension( L ), F ) ) );
# Now `B' will be a list of subspaces of `L' stable under `H'. # We stop once every element from `B' is irreducible.
cf:= AsList( F );
B:= [ ProductSpace( H, L ) ];
k:= 1;
while k <= Length( B ) do if Dimension( B[k] ) = 1then
k:=k+1; else
b:= BasisVectors( Basis( B[k] ) );
M:= LinearCombination( bas, List( bas, x -> Random( cf ) ) );
# Now we restrict `M' to the space `B[k]'.
mat:= [ ]; for i in [1..Length(b)] do
x:= LinearCombination( BL, M*Coefficients( BL, b[i] ) );
Add( mat, Coefficients( Basis( B[k], b ), x ) );
od;
M:= TransposedMat( mat );
f:= MinimalPolynomial( F, M );
facs:= Factors( PolynomialRing( F ), f );
if Length(facs)=1then
# We restrict the basis `bas' to the space `B[k]'. If the length # of the result is equal to the degree of `f' then `B[k]' is # irreducible.
sp:= MutableBasis( F,
[ Immutable( IdentityMat( Dimension(B[k]), F ) ) ] ); for j in [1..Length(bas)] do
mat:= [ ]; for i in [1..Length(b)] do
x:= LinearCombination( BL, bas[j]*Coefficients( BL, b[i] ) );
Add( mat, Coefficients( Basis( B[k], b ), x ) );
od;
mat:= TransposedMat( mat );
if not IsContainedInSpan( sp, mat ) then
CloseMutableBasis( sp, mat ); fi;
od;
res:= BasisVectors( sp );
if Length( res ) = DegreeOfLaurentPolynomial( f ) then
# The space is irreducible.
k:=k+1;
fi; else
# We decompose.
for i in facs do
vv:= List( NullspaceMat( TransposedMat( Value( i, M ) ) ),
x -> LinearCombination( b, x ) );
sp:= VectorSpace( F, vv ); if not sp in B then Add( B, sp ); fi;
od;
# We remove the old space from the list;
B:= Filtered( B, x -> (x <> B[k]) );
fi; fi;
od;
B:= List( B, x -> BasisVectors( Basis( x ) ) ); fi;
# Now the pieces in `B' are grouped together.
ideals:=[];
while B <> [ ] do
# Check whether `B[1]' is contained in any of # the ideals obtained so far.
contained := false;
i:=1; while not contained and i <= Length(ideals) do if B[1][1] in ideals[i] then
contained:= true; fi;
i:=i+1;
od;
if contained then# we do not need B[1] any more
B:= Filtered( B, x -> x<> B[1] );
else
# `B[1]' generates a new ideal. # We form this ideal by taking `B[1]' together with # all pieces from `B' that do not commute with `B[1]'. # At the end of this process, `bb' will be a list of elements # commuting with all elements of `B'. # From this it follows that `bb' will generate # a subalgebra that is a simple ideal. (No remaining piece of `B' # can be in this ideal because in that case this piece would # generate a smaller ideal inside this one.)
bb:= ShallowCopy( B[1] );
B:= Filtered( B, x -> x<> B[1] );
i:=1; while i<= Length( B ) do
comlist:= [ ]; for j in [1..Length(bb)] do
Append( comlist, List( B[i], y -> bb[j]*y ) );
od;
if not ForAll( comlist, IsZero ) then
Append( bb, B[i] );
B:= Filtered( B, x -> x <> B[i] );
i:= 1; else
i:=i+1; fi;
od;
Add( ideals, SubalgebraNC( L, bb ) );
fi;
od;
return List( ideals,
I -> IdealNC( L, BasisVectors( Basis( I ) ), "basis" ));
else
# First we try to find a central component, i.e., a decomposition # `L=I_1 \oplus I_2' such that `I_1' is contained in the center of `L'. # Such a decomposition exists if and only if the center of `L' is not # contained in the derived subalgebra of `L'.
C:= LieCentre( L );
bvc:= BasisVectors( Basis( C ) );
if Dimension( C ) = Dimension( L ) then
#Now `L' is abelian; hence `L' is the direct sum of `dim L' ideals.
return List( bvc, v -> IdealNC( L, [ v ], "basis" ) );
fi;
BL:= Basis( L );
bvl:= BasisVectors( BL );
if0 < Dimension( C ) then
D:= LieDerivedSubalgebra( L );
CD:= Intersection2( C, D );
if Dimension( CD ) < Dimension( C ) then
# The central component is the complement of `C \cap D' in `C'.
B1:=[];
k:=1;
sp:= MutableBasis( F,
BasisVectors( Basis( CD ) ), Zero( CD ) ); while Length( B1 ) + Dimension( CD ) <> Dimension( C ) do
x:= bvc[k]; if not IsContainedInSpan( sp, x ) then
Add( B1, x );
CloseMutableBasis( sp, x ); fi;
k:=k+1;
od;
# The second ideal is a complement of the central component # in `L' containing `D'. #W next statement modified:
B2:= ShallowCopy( BasisVectors( Basis( D ) ) );
k:= 1;
b:= ShallowCopy( B1 );
Append( b, B2 );
sp:= MutableBasis( F, b ); while Length( B2 )+Length( B1 ) <> n do
x:= bvl[k]; if not IsContainedInSpan( sp, x ) then
Add( B2, x );
CloseMutableBasis( sp, x ); fi;
k:= k+1;
od;
# Now we assume that `L' does not have a central component # and compute the centralizer of `ad L' in `M_n(F)'.
adL:= List( bvl, x -> AdjointMatrix( BL, x ) );
centralizer:= FullMatrixAlgebraCentralizer( F, adL );
Rad:= RadicalOfAlgebra( centralizer ); if Dimension( centralizer ) - Dimension( Rad ) = 1then
return [ L ]; fi;
# We calculate a complete set of orthogonal primitive idempotents # in the Abelian algebra `centralizer/Rad'.
hom:= NaturalHomomorphismByIdeal( centralizer, Rad );
Q:= ImagesSource( hom );
SetCentre( Q, Q );
SetRadicalOfAlgebra( Q, Subalgebra( Q, [ Zero( Q ) ] ) );
# Now we lift the idempotents to the big algebra `A'. The # first idempotent is lifted as follows: # We have that `id[1]^2-id[1]' is an element of `Rad'. # We construct the sequences e_{i+1} = e_i + n_i - 2e_in_i, # and n_{i+1}=e_{i+1}^2-e_{i+1}, starting with e_0=id[1]. # It can be proved by induction that e_q is an idempotent in `A' # because n_0^{2^q}=0. # Now `E' will be the sum of all idempotents lifted so far. # Then the next lifted idempotent is obtained by setting # `ei:=id[i]-E*id[i]-id[i]*E+E*id[i]*E;' # and lifting as above. It can be proved that in this manner we # get an orthogonal system of primitive idempotents.
E:= Zero( F )*id[1];
for i in [1..Length(id)] do
ei:= id[i]-E*id[i]-id[i]*E+E*id[i]*E;
q:= 0; while2^q <= Dimension( Rad ) do
q:= q+1;
od;
ni:= ei*ei-ei; for j in [1..q] do
ei:= ei+ni-2*ei*ni;
ni:= ei*ei-ei;
od;
id[i]:= ei;
E:= E+ei;
od;
# For every idempotent of `centralizer' we calculate # a direct summand of `L'.
ideals:= List( id, e -> List( TransposedMat( e ), v ->
LinearCombination( BL, v ) ) );
ideals:= List( ideals, ii -> BasisVectors(
Basis( VectorSpace( F, ii ) ) ) );
return List( ideals, ii ->
IdealNC( L, ii, "basis" ) );
fi;
end );
############################################################################## ## #M IsSimpleAlgebra( <L> ) . . . . . . . . . . . . . . . . for a Lie algebra ## ## A test whether <L> is simple. ## It works only over fields of characteristic 0. ##
InstallMethod( IsSimpleAlgebra, "for a Lie algebra in characteristic zero",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L ) if Characteristic( LeftActingDomain( L ) ) <> 0then
TryNextMethod(); elif RankMat( KillingMatrix( Basis( L ) ) ) <> Dimension( L ) then
return false; else
return Length( DirectSumDecomposition( L ) ) = 1; fi; end );
local n, # the dimension of `L'
F, # the field of `L'
B, # basis of `L'
T, # the table of structure constants of `L'
xc, # coefficient vector
eqs, # a system of equations
i,j,k,l, # loop variables
cij, # the element `T[i][j]'
b, # the right hand side of the equation system
v, # solution of the equations
z, # element of `L'
h, # element of `L'
R, # centralizer of `x' in `L'
BR, # basis of `R'
Rvecs, # basis vectors of `R'
H, # the matrix of `ad H' restricted to `R'
e0, # coefficient vector
e1, # coefficient vector
y; # element of `L'
if not IsNilpotentElement( L, x ) then
Error( "<x> must be a nilpotent element of the Lie algebra <L>" ); fi;
n:= Dimension( L );
F:= LeftActingDomain( L );
B:= Basis( L );
T:= StructureConstantsTable( B );
xc:= Coefficients( B, x );
eqs:= NullMat( 2*n, 2*n, F );
# First we try to find elements `z' and `h' such that `[x,z]=h' # and `[h,x]=2x' (i.e., such that two of the three defining equations # of sl_2 are satisfied). # This results in a system of `2n' equations for `2n' variables.
for i in [1..n] do for j in [1..n] do
cij:= T[i][j]; for k in [1..Length(cij[1])] do
l:= cij[1][k];
eqs[i][l] := eqs[i][l] + xc[j]*cij[2][k];
eqs[n+i][n+l]:= eqs[n+i][n+l] + xc[j]*cij[2][k];
od;
od;
eqs[n+i][i]:= One( F );
od;
b:= []; for i in [1..n] do
b[i]:= Zero( F );
b[n+i]:= 2*One( F )*xc[i];
od;
v:= SolutionMat( eqs, b );
if v = fail then # There is no sl_2 containing <x>.
return fail; fi;
R:= LieCentralizer( L, SubalgebraNC( L, [ x ] ) );
BR:= Basis( R );
Rvecs:= BasisVectors( BR );
# `ad h' maps `R' into `R'. `H' will be the matrix of that map.
H:= List( Rvecs, v -> Coefficients( BR, h * v ) );
# By the proof of the lemma of Jacobson-Morozov (see Jacobson, # Lie Algebras, p. 98) there is an element `e1' in `R' such that # `(H+2)e1=e0' where `e0=[h,z]+2z'. # If we set `y=z-e1' then `x,h,y' will span a subalgebra of `L' # isomorphic to sl_2.
H:= H+2*IdentityMat( Dimension( R ), F ); #T cheaper!
e0:= Coefficients( BR, h * z + 2*z );
e1:= SolutionMat( H, e0 );
if e1 = fail then # There is no sl_2 containing <x>.
return fail; fi;
y:= z-LinearCombination(Rvecs,e1);
return SubalgebraNC( L, [x,h,y], "basis" ); end );
############################################################################# ## #M SemiSimpleType( <L> ) ## ## This function works for Lie algebras over a field of characteristic not ## 2 or 3, having a nondegenerate Killing form. Such Lie algebras are ## semisimple. They are characterized as direct sums of simple Lie algebras, ## and these have been classified: a simple Lie algebra is either an element ## of the "great" classes of simple Lie algebas (A_n, B_n, C_n, D_n), or ## an exceptional algebra (E_6, E_7, E_8, F_4, G_2). This function finds ## the type of the semisimple Lie algebra `L'. Since for the calculations ## eigenvalues and eigenvectors of the action of a Cartan subalgebra are ## needed, we reduce the Lie algebra mod p (if it is of characteristic 0). ## The p may not divide the determinant of the matrix of the Killing form, ## nor may it divide the last nonzero coefficient of a minimum polynomial ## of an element of the basis of the Cartan subalgebra. ##
InstallMethod( SemiSimpleType, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local CartanInteger, # Function that computes the Cartan integer.
bvl, # basis vectors of a basis of `L'
a, # Element of `L'.
T,S,S1, # Structure constants tables.
den, # Denominator of a structure constant.
denoms, # List of denominators.
i,j,k, # Loop variables.
scal, # A scalar.
K, # A Lie algebra.
BK, # basis of `K'
d, # The determinant of the Killing form of `K'.
p, # A prime.
H, # Cartan subalgebra.
s, # An integer.
mp, # List of minimum polynomials.
F, # Field.
bas, # List of basis vectors.
simples, # List of simple subalgebras.
types, # List of the types of the elements of simples.
I, # An element of simples.
BI, # basis of `I'
bvi, # basis vectors of `BI'
HI, # Cartan subalgebra of `I'.
rk, # The rank of `I'.
adH, # List of adjoint matrices.
R, # Root system.
basR, # Basis of `R'.
posR, # List of the positive roots.
fundR, # A fundamental system.
r,r1,r2,rt, # Roots.
Rvecs, # List of root vectors.
basH, # List of basis vectors of a Cartan subalg. of `I'
sp, # Vector space.
h, # Element of a Cartan subalgebra of `I'.
cf, # Coefficient.
issum, # Boolean.
CM, # Cartan Matrix.
endpts; # The endpoints of the Dynkin diagram of `I'.
if Characteristic( LeftActingDomain( L ) ) in [ 2, 3 ] then
Info( InfoAlgebra, 1, "The field of <L> must not have characteristic 2 or 3." );
return fail; fi;
# The following function computes the Cartan integer of two roots # `r1' and `r2'. # If `s' and `t' are the largest integers such that `r1 - s*r2' and # `r1 + t*r2' are elements of the root system `R', # then the Cartan integer of `r1' and `r2' is `s-t'.
CartanInteger := function( R, r1, r2 )
local R1,s,t,rt;
R1:= ShallowCopy( R );
Add( R1, R[1]-R[1] );
s:= 0;
t:= 0;
rt:= r1-r2; while rt in R1 do
rt:= rt-r2;
s:= s+1;
od;
rt:= r1+r2; while rt in R1 do
rt:= rt+r2;
t:= t+1;
od;
return s-t; end;
# We test whether the Killing form of `L' is nondegenerate.
if RankMat( KillingMatrix( Basis( L ) ) ) <> Dimension( L ) then
Info( InfoAlgebra, 1, "The Killing form of <L> is degenerate." );
return fail; fi;
# First we produce a basis of `L' such that the first basis elements # form a basis of a Cartan subalgebra of `L'. Then if `L' is defined # over a field of characteristic 0 we do the following. We # multiply by an integer in order to ensure that the structure # constants are integers. # Finally we reduce modulo an appropriate prime `p'.
H:= CartanSubalgebra( L );
rk:= Dimension( H );
bas:= ShallowCopy( BasisVectors( Basis( H ) ) );
sp:= MutableBasis( LeftActingDomain( L ), bas );
k:= 1;
bvl:= BasisVectors( Basis( L ) ); while Length( bas ) < Dimension( L ) do
a:= bvl[k]; if not IsContainedInSpan( sp, a ) then
Add( bas, a );
CloseMutableBasis( sp, a ); fi;
k:= k+1;
od;
T:= StructureConstantsTable( BasisNC( L, bas ) );
p:= Characteristic( LeftActingDomain( L ) );
if p = 0then
denoms:=[]; for i in [1..Dimension(L)] do for j in [1..Dimension(L)] do for k in [1..Length(T[i][j][2])] do
den:= DenominatorRat( T[i][j][2][k] ); if (den <> 1) and (not den in denoms) then
Add( denoms, den ); fi;
od;
od;
od;
if denoms <> [] then
S:= EmptySCTable( Dimension( L ), 0, "antisymmetric" );
scal:= Lcm( denoms ); for i in [1..Dimension(L)] do for j in [1..Dimension(L)] do
S[i][j]:= [T[i][j][1],scal*T[i][j][2]];
od;
od; else
S:=T; fi;
K:= LieAlgebraByStructureConstants( LeftActingDomain( L ), S );
BK:= Basis( K );
d:= DeterminantMat( KillingMatrix( BK ) );
F:= LeftActingDomain( L );
# `mp' will be a list of minimum polynomials of basis elements of the # Cartan subalgebra.
mp:= List( BasisVectors( BK ){[1..rk]},
x -> CharacteristicPolynomial( F, F, AdjointMatrix( BK, x ) ) );
mp:= List( mp, x -> x/Gcd( Derivative( x ), x ) );
d:= d * Product( List( mp, p ->
CoefficientsOfLaurentPolynomial(p)[1][1] ) );
p:= 5;
s:=7;
# We determine a prime `p>5' not dividing `d' and an integer `s' # such that the minimum polynomials of the basis elements # of the Cartan subalgebra will split into linear factors # over the field of `p^s' elements, # and such that `p^s<=2^16' # (the maximum size of a finite field in GAP).
while p^s > 65536do
while d mod p = 0do
p:= NextPrimeInt( p );
od;
F:= GF( p );
S1:= EmptySCTable( Dimension( K ), Zero( F ), "antisymmetric" ); for i in [1..Dimension(K)] do for j in [1..Dimension(K)] do
S1[i][j]:= [S[i][j][1], One( F )*List( S[i][j][2], x -> x mod p)];
od;
od;
K:= LieAlgebraByStructureConstants( F, S1 );
BK:= Basis( K );
mp:= List( BasisVectors( BK ){[1..rk]},
x -> CharacteristicPolynomial( F, F, AdjointMatrix( BK, x ) ) );
s:= Lcm( Flat( List( mp, p -> List( Factors( p ),
DegreeOfLaurentPolynomial ) )));
if p=65521then p:= 1; fi;
od;
if p = 1then
Info( InfoAlgebra, 1, "We cannot find a small modular splitting field for <L>" );
return fail; fi;
else
# Here `L' is defined over a field of characteristic p>0. We determine # an integer `s' such that the Cartan subalgebra splits over # `GF( p^s )'.
F:= LeftActingDomain( L );
K:= LieAlgebraByStructureConstants( F, T );
BK:= Basis( K );
mp:= List( BasisVectors( BK ){[1..rk]},
x -> CharacteristicPolynomial( F, F, AdjointMatrix( BK, x ) ) );
s:= Lcm( Flat( List( mp, p -> List( Factors( p ),
DegreeOfLaurentPolynomial ) )));
s:= s*Dimension( LeftActingDomain( L ) ); if p^s > 2^16then
Info( InfoAlgebra, 1, "We cannot find a small modular splitting field for <L>" );
BK:= Basis( K );
H:= SubalgebraNC( K, BasisVectors( BK ){ [ 1 .. rk ] }, "basis" );
SetCartanSubalgebra( K, H );
simples:= DirectSumDecomposition( K );
types:= "";
# Now for every simple Lie algebra in simples we have to determine # its type. # For Lie algebras not equal to B_l, C_l or E_6, # this is determined by the dimension and the rank. # In the other cases we have to examine the root system.
for I in simples do
if not IsEmpty( types ) then
Append( types, " " ); fi;
HI:= Intersection2( H, I );
rk:= Dimension( HI );
if Dimension( I ) = 133 and rk = 7then
Append( types, "E7" ); elif Dimension( I ) = 248 and rk = 8then
Append( types, "E8" ); elif Dimension( I ) = 52 and rk = 4then
Append( types, "F4" ); elif Dimension( I ) = 14 and rk = 2then
Append( types, "G2" ); else if Dimension( I ) = rk^2 + 2*rk then
Append( types, "A" ); Append( types, String( rk ) ); elif Dimension( I ) = 2*rk^2-rk then
Append( types, "D" ); Append( types, String( rk ) ); elif Dimension( I ) = 10then
Append( types, "B2" ); else
# We now determine the list of roots and the corresponding # root vectors. # Since the minimum polynomials of the elements of the # Cartan subalgebra split completely, # after the call of DirectSumDecomposition, # the root vectors are contained in the basis of `I'.
BI:= Basis( I );
bvi:= BasisVectors( BI );
adH:= List( BasisVectors(Basis(HI)), x->AdjointMatrix(BI,x)); #T better!
R:=[];
Rvecs:=[]; for i in [ 1 .. Dimension( I ) ] do
rt:= List( adH, x -> x[i][i] ); if not IsZero( rt ) then
Add( R, rt );
Add( Rvecs, bvi[i] ); fi;
od;
# A set of roots `basR' is determined such that the set # { [x_r,x_{-r}] | r\in basR } is a basis of `HI'.
basH:= [ ];
basR:= [ ];
sp:= MutableBasis( F, [], Zero(I) );
i:= 1; while Length( basH ) < Dimension( HI ) do
r:= R[i];
k:= Position( R, -r );
h:= Rvecs[i] * Rvecs[k]; if not IsContainedInSpan( sp, h ) then
Add( basH, h );
CloseMutableBasis( sp, h );
Add( basR, r ); fi;
i:= i+1;
od;
# `posR' will be the set of positive roots. # A root `r' is called positive if in the list # [ < r, basR[i] >, i=1...Length(basR) ] the first nonzero # coefficient is positive # (< r_1, r_2 > is the Cartan integer of r_1 and r_2).
posR:= [ ]; for r in R do if (not r in posR) and (not -r in posR) then
cf:= 0;
i:= 0; while cf = 0do
i:= i+1;
cf:= CartanInteger( R, r, basR[i] );
od; if0 < cf then
Add( posR, r ); else
Add( posR, -r ); fi; fi;
od;
# A positive root is a fundamental root if it is not # the sum of two other positive roots.
fundR:= [ ]; for r in posR do
issum:= false; for r1 in posR do for r2 in posR do if r = r1+r2 then
issum:= true;
break; fi;
od; if issum then break; fi;
od; if not issum then
Add( fundR, r ); fi;
od;
# `CM' will be the matrix of Cartan integers # of the fundamental roots.
############################################################################## ## #M NonNilpotentElement( <L> ) ##
InstallMethod( NonNilpotentElement, "for a Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local n, # the dimension of `L'
F, # the field over which `L' is defined
bvecs, # a list of the basisvectors of `L'
D, # a list of elements of `L', forming a basis of a nilpotent # subspace
sp, # the space spanned by `D'
r, # the dimension of `sp'
found, # a Boolean variable
i, j, # loop variables
b, c, # elements of `L'
elm; #
# First rule out some trivial cases.
n:= Dimension( L ); if n = 1 or n = 0then
return fail; fi;
F:= LeftActingDomain( L );
bvecs:= BasisVectors( Basis( L ) );
if Characteristic( F ) <> 0then
# `D' will be a basis of a nilpotent subalgebra of L. if IsNilpotentElement( L, bvecs[1] ) then
D:= [ bvecs[1] ]; else
return bvecs[1]; fi;
# `r' will be the dimension of the span of `D'. # If `r = n' then `L' is nilpotent and hence does not contain # non nilpotent elements.
r:= 1;
while r < n do
sp:= VectorSpace( F, D, "basis" );
# We first find an element `b' of `L' that does not lie in `sp'.
found:= false;
i:= 2; while not found do
b:= bvecs[i]; if b in sp then
i:= i+1; else
found:= true; fi;
od;
# We now replace `b' by `b * D[i]' if # `b * D[i]' lies outside `sp' in order to ensure that # `[b,sp] \subset sp'. # Because `sp' is a nilpotent subalgebra we only need # a finite number of replacement steps.
i:= 1; while i <= r do
c:= b*D[i]; if c in sp then
i:= i+1; else
b:= c;
i:= 1; fi;
od;
if IsNilpotentElement( L, b ) then
Add( D, b );
r:= r+1; else
return b; fi;
od;
else
# Now `char F =0'. # In this case either `L' is nilpotent or one of the # elements $L.1, \ldots , L.n, L.i + L.j; 1 \leq i < j$ # is non nilpotent.
for i in [ 1 .. n ] do if not IsNilpotentElement( L, bvecs[i] ) then
return bvecs[i]; fi;
od;
for i in [ 1 .. n ] do for j in [ i+1 .. n ] do
elm:= bvecs[i] + bvecs[j]; if not IsNilpotentElement( L, elm ) then
return elm; fi;
od;
od;
fi;
# A non nilpotent element has not been found, # hence `L' is nilpotent.
return fail;
end );
############################################################################ ## #M PrintObj( <R> ) . . . . . . . . . . . . . . . . . . for a root system ##
InstallMethod( PrintObj, "for a root system",
true, [ IsRootSystem ], 0, function( R )
if HasCartanMatrix( R ) then
Print("<root system of rank ",Length(SimpleSystem(R)),">"); else
Print("<root system>"); fi;
end );
############################################################################ ## #M \.( <R>, <name> ) . . . . . . . record component access for a root system ##
InstallMethod( \., "for a root system and a record component",
true, [ IsRootSystem, IsObject ], 0, function( R, name )
name:= NameRNam( name ); if name = "roots"then
return Concatenation( PositiveRoots(R), NegativeRoots(R) ); elif name = "rootvecs"then
return Concatenation( PositiveRootVectors(R),
NegativeRootVectors(R) ); elif name = "fundroots"then
return SimpleSystem( R ); elif name = "cartanmat"then
return CartanMatrix(R); else
TryNextMethod(); fi; end );
############################################################################## ## #M RootSystem( <L> ) . . . . . . . . . . . . . . . . . . . for a Lie algebra ##
InstallMethod( RootSystem, "for a (semisimple) Lie algebra",
true,
[ IsAlgebra and IsLieAlgebra ], 0, function( L )
local F, # coefficients domain of `L'
BL, # basis of `L'
H, # A Cartan subalgebra of `L'
basH, # A basis of `H'
sp, # A vector space
B, # A list of bases of subspaces of `L' whose direct sum # is equal to `L'
newB, # A new version of `B' being constructed
i,j,l, # Loop variables
facs, # List of the factors of `p'
V, # A basis of a subspace of `L'
M, # A matrix
cf, # A scalar
a, # A root vector
ind, # An index
basR, # A basis of the root system
h, # An element of `H'
posR, # A list of the positive roots
fundR, # A list of the fundamental roots
issum, # A boolean
CartInt, # The function that calculates the Cartan integer of # two roots
C, # The Cartan matrix
S, # A list of the root vectors
zero, # zero of `F'
hts, # A list of the heights of the root vectors
sorh, # The set `Set( hts )'
sorR, # The soreted set of roots
R, # The root system.
Rvecs, # The root vectors.
x,y, # Canonical generators.
noPosR; # Number of positive roots.
# Let `a' and `b' be two roots of the rootsystem `R'. # Let `s' and `t' be the largest integers such that `a-s*b' and `a+t*b' # are roots. # Then the Cartan integer of `a' and `b' is `s-t'.
CartInt := function( R, a, b )
local s,t,rt;
s:=0; t:=0;
rt:=a-b; while (rt in R) or (rt=0*R[1]) do
rt:=rt-b;
s:=s+1;
od;
rt:=a+b; while (rt in R) or (rt=0*R[1]) do
rt:=rt+b;
t:=t+1;
od;
return s-t; end;
F:= LeftActingDomain( L );
if RankMat( KillingMatrix( Basis( L ) ) ) <> Dimension( L ) then
Info( InfoAlgebra, 1, "the Killing form of <L> is degenerate" );
return fail; fi;
# First we compute the common eigenvectors of the adjoint action of a # Cartan subalgebra `H'. Here `B' will be a list of bases of subspaces # of `L' such that `H' maps each element of `B' into itself. # Furthermore, `B' has maximal length w.r.t. this property.
H:= CartanSubalgebra( L );
BL:= Basis( L );
B:= [ ShallowCopy( BasisVectors( BL ) ) ];
basH:= BasisVectors( Basis( H ) );
for i in basH do
newB:= [ ]; for j in B do
V:= Basis( VectorSpace( F, j, "basis" ), j );
M:= List( j, x -> Coefficients( V, i*x ) );
facs:= Factors( PolynomialRing( F ), MinimalPolynomial( F, M ) );
for l in facs do
V:= NullspaceMat( Value( l, M ) );
Add( newB, List( V, x -> LinearCombination( j, x ) ) );
od;
od;
B:= newB;
od;
# Now we throw away the subspace `H'.
B:= Filtered( B, x -> ( not x[1] in H ) );
# If an element of `B' is not one dimensional then `H' does not split # completely, and hence we cannot compute the root system.
for i in [ 1 .. Length(B) ] do if Length( B[i] ) <> 1then
Info( InfoAlgebra, 1, "the Cartan subalgebra of <L> in not split" );
return fail; fi;
od;
# Now we compute the set of roots `S'. # A root is just the list of eigenvalues of the basis elements of `H' # on an element of `B'.
S:= [];
zero:= Zero( F ); for i in [ 1 .. Length(B) ] do
a:= [ ];
ind:= 0;
cf:= zero; while cf = zero do
ind:= ind+1;
cf:= Coefficients( BL, B[i][1] )[ ind ];
od; for j in [1..Length(basH)] do
Add( a, Coefficients( BL, basH[j]*B[i][1] )[ind] / cf );
od;
Add( S, a );
od;
Rvecs:= List( B, x -> x[1] );
# A set of roots `basR' is calculated such that the set # { [ x_r, x_{-r} ] | r\in R } is a basis of `H'.
basH:= [ ];
basR:= [ ];
sp:= MutableBasis( F, [], Zero(L) );
i:=1; while Length( basH ) < Dimension( H ) do
a:= S[i];
j:= Position( S, -a );
h:= B[i][1]*B[j][1]; if not IsContainedInSpan( sp, h ) then
CloseMutableBasis( sp, h );
Add( basR, a );
Add( basH, h ); fi;
i:=i+1;
od;
# A root `a' is said to be positive if the first nonzero element of # `[ CartInt( S, a, basR[j] ) ]' is positive. # We calculate the set of positive roots.
posR:= [ ];
i:=1; while Length( posR ) < Length( S )/2do
a:= S[i]; if (not a in posR) and (not -a in posR) then
cf:= zero;
j:= 0; while cf = zero do
j:= j+1;
cf:= CartInt( S, a, basR[j] );
od; if0 < cf then
Add( posR, a ); else
Add( posR, -a ); fi; fi;
i:=i+1;
od;
# A positive root is called simple if it is not the sum of two other # positive roots. # We calculate the set of simple roots `fundR'.
fundR:= [ ]; for a in posR do
issum:= false; for i in [1..Length(posR)] do for j in [i+1..Length(posR)] do if a = posR[i]+posR[j] then
issum:=true; fi;
od;
od; if not issum then
Add( fundR, a ); fi;
od;
# Now we calculate the Cartan matrix `C' of the root system.
C:= List( fundR, i -> List( fundR, j -> CartInt( S, i, j ) ) );
# Every root can be written as a sum of the simple roots. # The height of a root is the sum of the coefficients appearing # in that expression. # We order the roots according to increasing height.
sorR:= [ ]; for i in [1..Length(sorh)] do
Append( sorR, Filtered( posR, r -> hts[Position(posR,r)] = sorh[i] ) );
od;
Append( sorR, -1*sorR );
Rvecs:= List( sorR, r -> Rvecs[ Position(S,r) ] );
# We calculate a set of canonical generators of `L'. Those are elements # x_i, y_i, h_i such that h_i=x_i*y_i, h_i*x_j = c_{ij} x_j, # h_i*y_j = -c_{ij} y_j for i \in {1..rank}
x:= Rvecs{[1..Length(C)]};
noPosR:= Length( Rvecs )/2;
y:= Rvecs{[1+noPosR..Length(C)+noPosR]}; for i in [1..Length(x)] do
V:= VectorSpace( LeftActingDomain(L), [ x[i] ] );
B:= Basis( V, [x[i]] );
y[i]:= y[i]*2/Coefficients( B, (x[i]*y[i])*x[i] )[1];
od;
h:= List([1..Length(C)], j -> x[j]*y[j] );
# Now we construct the root system, and install as many attributes # as possible. The roots are represented as lists [ \alpha(h_1),.... # ,\alpha(h_l)], where the h_i form the `Cartan' part of the canonical # generators.
R:= Objectify( NewType( NewFamily( "RootSystemFam", IsObject ),
IsAttributeStoringRep and IsRootSystemFromLieAlgebra ),
rec() );
SetCanonicalGenerators( R, [ x, y, h ] );
SetUnderlyingLieAlgebra( R, L );
SetPositiveRootVectors( R, Rvecs{[1..noPosR]});
SetNegativeRootVectors( R, Rvecs{[noPosR+1..2*noPosR]} );
SetCartanMatrix( R, C );
posR:= [ ]; for i in [1..noPosR] do
B:= Basis( VectorSpace( F, [ Rvecs[i] ] ), [ Rvecs[i] ] );
posR[i]:= List( h, hj -> Coefficients( B, hj*Rvecs[i] )[1] );
od;
############################################################################## ## #M CanonicalGenerators( <R> ) . . . . for a root system from a Lie algebra ##
InstallMethod( CanonicalGenerators, "for a root system from a (semisimple) Lie algebra",
true,
[ IsRootSystemFromLieAlgebra ], 0, function( R )
local L, rank, x, y, i, V, b, c;
L:= UnderlyingLieAlgebra( R );
rank:= Length( CartanMatrix( R ) );
x:= PositiveRootVectors( R ){[1..rank]};
y:= NegativeRootVectors( R ){[1..rank]}; for i in [1..Length(x)] do
V:= VectorSpace( LeftActingDomain(L), [ x[i] ] );
b:= Basis( V, [x[i]] );
c:= Coefficients( b, (x[i]*y[i])*x[i] )[1];
y[i]:= y[i]*2/c;
od;
return [ x, y, List([1..rank], j -> x[j]*y[j] ) ];
end );
############################################################################# ## #M ChevalleyBasis( <L> ) . . . . . . for a semisimple Lie algebra ##
InstallMethod( ChevalleyBasis, "for a semisimple Lie algebra with a split Cartan subalgebra",
true, [ IsLieAlgebra ], 0, function( L )
local R, n, cg, b1p, b1m, b2p, b2m, k, r, i, r1, pos,
b1, b2, f, cfs, bHa, posRV, negRV, x, y, ha, cf,
F, T, K, B, BK;
# We first calculate an automorphism `f' of `L' such that # F(L_{\alpha}) = L_{-\alpha}, and f(H)=H, and f acts as multiplication # by -1 on H. For this we take the canonical generators of `L', # map its `x'-part onto its `y' part (and vice versa), and map # the `h'-part on minus itself. The automorphism is determined by this.
R:= RootSystem( L );
n:= Length( PositiveRoots( R ) );
cg:= CanonicalGenerators( R );
k:= 1; while k <= n do
r:= PositiveRoots( R )[k]; for i in [1..Length( CartanMatrix( R ) )] do
r1:= r + SimpleSystem( R )[i];
pos:= Position( PositiveRoots( R ), r1 ); if pos<>fail and not IsBound( b1p[pos] ) then
# Now for every positive root vector `x' we set `y= -Image( f, x )'. # We compute a scalar `cf' such that `[x,y]=h', where `h' is the # canonical Cartan element corresponding to the root (unquely determined). # Then we have to multiply `x' and `y' by Sqrt( 2/cf ), in order to get # elements of a Chevalley basis.
cfs:= [ ];
bHa:= [ ];
posRV:= [ ];
negRV:= [ ]; for i in [1..n] do
x:= PositiveRootVectors( R )[i];
y:= -Image( f, x );
ha:= x*y;
cf:= Coefficients( Basis( VectorSpace( LeftActingDomain(L),
[x] ), [x] ), ha*x )[1]; if i <= Length( CartanMatrix( R ) ) then Add( bHa, (2/cf)*ha ); fi;
Add( cfs, Sqrt( 2/cf ) );
posRV[i]:= x; negRV[i]:= y;
od;
# In general the `cfs' will lie in a field extension of the ground field. # We construct the Lie algebra over that field with the same structure # constants as `L'. Then we map the Chevalley basis elements into # this new Lie algebra. Then we take the structure constants table of # this new Lie algebra with respect to the Chevalley basis, and # form a new Lie algebra over the same field as `L' with this table.
F:= DefaultField( cfs );
T:= StructureConstantsTable( Basis( L ) );
K:= LieAlgebraByStructureConstants( F, T );
BK:= CanonicalBasis( K );
B:= [ ]; for i in [1..n] do
B[i]:= LinearCombination( BK, cfs[i]*Coefficients( Basis(L),
posRV[i] ) );
B[n+i]:= LinearCombination( BK, cfs[i]*Coefficients( Basis(L),
negRV[i] ) );
od; for i in [1..Length(bHa)] do
B[2*n+i]:= LinearCombination( BK, Coefficients( Basis(L),
bHa[i] ) );
od;
T:= StructureConstantsTable( Basis( K, B ) );
K:= LieAlgebraByStructureConstants( LeftActingDomain(L), T );
B:= BasisVectors( CanonicalBasis( K ) );
# Now the basis elements of `K' form a Chevalley basis. Furthermore, # `K' is isomorphic to `L'. We construct the isomorphism, and map # the basis elements of `K' into `L', thus getting a Chevalley basis # in `L'.
k:= 1; while k <= n do
r:= PositiveRoots( R )[k]; for i in [1..Length( CartanMatrix( R ) )] do
r1:= r + SimpleSystem( R )[i];
pos:= Position( PositiveRoots( R ), r1 ); if pos<>fail and not IsBound( b1p[pos] ) then
local normalized, # ordered list of normalized coeff./monom. pairs
indices, # list that stores at position $i$ up to what # position the $i$-th monomial is known to be # normalized
s, i, j, k, l, # loop variables 2i, # `2*i'
scalar, # coefficient of the monomial under work
mon, # monomial under work
len, # length of the monomial under work
head, # initial part of the monomial under work
middle, # middle part of the monomial under work
tail, # trailing part of the monomial under work
index, # new value of `indices[i]'
Tcoeffs, # one entry in `T'
lennorm, # length of `normalized' at the moment
zero; # zero coefficient
normalized := [];
while not IsEmpty( listofpairs ) do
listofpairs:= Compacted( listofpairs );
# `indices' is a list of positive integers $[ j_1, j_2, \ldots, j_m ]$ # s.t. the initial part $x_{i_1}^{e_1} \cdots x_{i_{j_k}}^{e_{j_k}}$ # of the $k$-th monomial is known to be normalized, # i.e., $i_1 < i_2 < \cdots < i_{j_k}$. # (So $j_k = 1$ for all $k$ will always be correct.)
indices:= ListWithIdenticalEntries( Length( listofpairs )/2, 1 );
# Loop over the monomials that shall be normalized. for i in [ 1, 2 .. Length( indices ) ] do
# If the `i'-th monomial is already normalized, # put it into `normalized'. # Otherwise swap the first non-ordered generators. 2i:= 2*i;
scalar:= listofpairs[ 2i ];
mon:= listofpairs[ 2i-1 ];
len:= Length( mon );
j:= 2 * indices[i] - 1; while j < len - 2do
if mon[j] < mon[ j+2 ] then
# `mon' is better normalized than `indices' tells.
j:= j+2;
indices[i]:= indices[i] + 1;
elif mon[j] = mon[ j+2 ] then
# absorption
mon[ j+1 ]:= mon[ j+1 ] + mon[ j+3 ]; for k in [ j+2 .. len-2 ] do
mon[k]:= mon[ k+2 ];
od;
Unbind( mon[ len ] );
Unbind( mon[ len-1 ] );
len:= len - 2;
else
# We must swap two generators. # First construct head and tail of the arising monomials.
head:= mon{ [ 1 .. j-1 ] };
# Adjust `indices[i]'.
index:= indices[i] - 1; if index = 0then
index:= 1; fi;
indices[i]:= index;
# Replace the monomial by the swapped one.
listofpairs[ 2i-1 ]:= Concatenation( head, middle, tail );
# Add the coeffs/monomials that are given by the commutator. # The part between `head' and `tail' of these listofpairs is # $a_{ji}=\sum_{k=1}^d c_{ijk} x_d$. # Here we use the following formula (which is easily proved # by induction): # # x_j^m x_i^n = x_i^n x_j^m + \sum_{l=0}^{m-1} \sum_{k=0}^{n-1} # x_j^l x_i^k a_{ji} x_i^{n-1-k} x_j^{m-1-l} # # # where x_jx_i = x_ix_j + a_{ji} #
Tcoeffs:= T[ mon[j] ][ mon[ j+2 ] ]; for s in [ 1 .. Length( Tcoeffs[1] ) ] do for l in [ 0 .. mon[j+1] - 1 ] do for k in [ 0 .. mon[j+3] - 1 ] do
middle:= [ ];
if l > 0then
middle:= [ mon[j], l ]; fi; if k > 0then
Append( middle, [ mon[j+2], k ] ); fi;
Append( middle, [ Tcoeffs[1][s], 1 ] ); if mon[j+3]-1-k > 0then
Append( middle, [ mon[j+2], mon[j+3]-1-k ] ); fi; if mon[j+1]-1-l > 0then
Append( middle, [ mon[j], mon[j+1]-1-l ] ); fi;
# If the monomial is normalized then move it to `normalized'. if len - 2 <= j then
# Find the correct position in `normalized', # and insert the monomial.
lennorm:= Length( normalized );
k:= 2; while k <= lennorm do if listofpairs[ 2i-1 ] < normalized[ k-1 ] then for l in [ lennorm, lennorm-1 .. k-1 ] do
normalized[l+2]:= normalized[l];
od;
normalized[ k-1 ]:= listofpairs[ 2i-1 ];
normalized[ k ]:= scalar;
break; elif listofpairs[ 2i-1 ] = normalized[ k-1 ] then
normalized[k]:= normalized[k] + scalar;
break; fi;
k:= k+2;
od; if lennorm < k then
normalized[ lennorm+1 ]:= listofpairs[ 2i-1 ];
normalized[ lennorm+2 ]:= scalar; fi;
# Remove the monomial from `listofpairs'.
Unbind( listofpairs[ 2i-1 ] );
Unbind( listofpairs[ 2i ] );
fi;
od;
od;
# Remove monomials with multiplicity zero; if not IsEmpty( normalized ) then
zero:= Zero( normalized[2] ); for i in [ 2, 4 .. Length( normalized ) ] do if normalized[i] = zero then
Unbind( normalized[ i-1 ] );
Unbind( normalized[ i ] ); fi;
od;
normalized:= Compacted( normalized ); fi;
# Return the normal form.
return normalized; end );
############################################################################# ## #M UniversalEnvelopingAlgebra( <L> ) . . . . . . . . . . . for a Lie algebra ##
InstallOtherMethod( UniversalEnvelopingAlgebra, "for a finite dimensional Lie algebra and a basis of it",
true,
[ IsLieAlgebra, IsBasis ], 0, function( L, B )
local F, # free associative algebra
U, # universal enveloping algebra, result
gen, # loop over algebra generators of `U'
Fam, # elements family of `U'
T, # s.c. table of a basis of `L'
FamMon, # family of monomials
FamFree; # elements family of `F'
# Check the argument. if not IsFiniteDimensional( L ) then
Error( "<L> must be finite dimensional" ); fi;
# Construct the universal enveloping algebra.
F:= FreeAssociativeAlgebraWithOne( LeftActingDomain( L ),
Dimension( L ), "x" );
U:= FactorFreeAlgebraByRelators( F, [ Zero( F ) ] ); #T do not cheat here!
# Enter knowledge about `U'.
SetDimension( U, infinity ); for gen in GeneratorsOfLeftOperatorRingWithOne( U ) do
SetIsNormalForm( gen, true );
od;
SetIsNormalForm( Zero( U ), true );
# Enter data to handle elements.
Fam:= ElementsFamily( FamilyObj( U ) );
Fam!.normalizedType:= NewType( Fam,
IsElementOfFpAlgebra
and IsPackedElementDefaultRep
and IsNormalForm );
T:= StructureConstantsTable( B );
FamMon:= ElementsFamily( FamilyObj( UnderlyingMagma( F ) ) );
FamFree:= ElementsFamily( FamilyObj( F ) );
SetNiceNormalFormByExtRepFunction( Fam, function( Fam, extrep )
local zero, i;
zero:= extrep[1];
extrep:= DescriptionOfNormalizedUEAElement( T, extrep[2] ); for i in [ 1, 3 .. Length( extrep ) - 1 ] do
extrep[i]:= ObjByExtRep( FamMon, extrep[i] );
od;
return Objectify( Fam!.normalizedType,
[ Objectify( FamFree!.defaultType, [ zero, extrep ] ) ] ); end );
SetOne( U, ElementOfFpAlgebra( Fam, One( F ) ) );
# Enter `L'; it is used to set up the embedding (as a vector space).
Fam!.liealgebra:= L; #T is not allowed ...
# Return the universal enveloping algebra.
return U; end );
#T missing: embedding of the Lie algebra (as vector space) #T missing: relators (only compute them if they are explicitly wanted) #T (attribute `Relators'?)
InstallMethod( UniversalEnvelopingAlgebra, "for a finite dimensional Lie algebra",
true,
[ IsLieAlgebra ], 0, function( L )
return UniversalEnvelopingAlgebra( L, Basis(L) ); end );
############################################################################# ## #F IsSpaceOfUEAElements( <V> ) ## ## If <V> is a space of elements of a universal enveloping algebra, ## then the `NiceFreeLeftModuleInfo' value of <V> is a record with the ## following components. ## \beginitems ## `family' & ## the elements family of <V>, ## ## `monomials' & ## a list of monomials occurring in the generators of <V>, ## ## ## `zerocoeff' & ## the zero coefficient of elements in <V>, ## ## `zerovector' & ## the zero row vector in the nice free left module, ## ## `characteristic' & ## the characteristic of the ground field. ## \enditems ## The `NiceVector' value of $v \in <V>$ is defined as the row vector of ## coefficients of $v$ w.r.t. the list `monomials'. ## ##
DeclareHandlingByNiceBasis( "IsSpaceOfUEAElements", "for free left modules of elements of a universal enveloping algebra" );
NiceFreeLeftModuleInfo := function( V )
local gens,
monomials,
gen,
list,
zero,
info;
gens:= GeneratorsOfLeftModule( V );
monomials:= [];
for gen in gens do
list:= ExtRepOfObj( gen )[2];
UniteSet( monomials, list{ [ 1, 3 .. Length( list ) - 1 ] } );
od;
zero:= Zero( LeftActingDomain( V ) );
info:= rec( monomials := monomials,
zerocoeff := zero,
characteristic:= Characteristic( LeftActingDomain( V ) ),
family := ElementsFamily( FamilyObj( V ) ) );
# For the zero row vector, catch the case of empty `monomials' list. if IsEmpty( monomials ) then
info.zerovector := MakeImmutable([ zero ]); else
info.zerovector := MakeImmutable(ListWithIdenticalEntries( Length( monomials ),
zero ) ); fi;
return info; end,
NiceVector := function( V, v )
local info, c, monomials, i, pos;
info:= NiceFreeLeftModuleInfo( V );
c:= ShallowCopy( info.zerovector );
v:= ExtRepOfObj( v )[2];
monomials:= info.monomials; for i in [ 2, 4 .. Length( v ) ] do
pos:= Position( monomials, v[ i-1 ] ); if pos = fail then
return fail; fi;
c[ pos ]:= v[i];
od;
return c; end,
UglyVector := function( V, r )
local info, list, i;
info:= NiceFreeLeftModuleInfo( V ); if Length( r ) <> Length( info.zerovector ) then
return fail; elif IsEmpty( info.monomials ) then if IsZero( r ) then
return Zero( V ); else
return fail; fi; fi;
list:= []; for i in [ 1 .. Length( r ) ] do if r[i] <> info.zerocoeff then
Add( list, info.monomials[i] );
Add( list, r[i] ); fi;
od;
return ObjByExtRep( info.family, [ info.characteristic, list ] ); end ) );
local R, # coefficients ring
names, # names of the algebra generators
M, # free magma
F, # family of magma ring elements
one, # identity of `R'
zero, # zero of `R'
L; # free Lie algebra, result
# Check the argument list. if Length( arg ) = 0 or not IsRing( arg[1] ) then
Error( "first argument must be a ring" ); fi;
R:= arg[1];
# Construct names of generators. if Length( arg ) = 2 and IsInt( arg[2] ) then
names:= List( [ 1 .. arg[2] ],
i -> Concatenation( "x", String(i) ) );
MakeImmutable( names ); elif Length( arg ) = 2
and IsList( arg[2] )
and ForAll( arg[2], IsString ) then
names:= arg[2]; elif Length( arg ) = 3 and IsInt( arg[2] ) and IsString( arg[3] ) then
names:= List( [ 1 .. arg[2] ],
x -> Concatenation( arg[3], String(x) ) );
MakeImmutable( names ); elif ForAll( arg{ [ 2 .. Length( arg ) ] }, IsString ) then
names:= arg{ [ 2 .. Length( arg ) ] }; else
Error( "usage: FreeLieAlgebra( <R>, <rank> )\n", "or FreeLieAlgebra( <R>, <name1>, ... )" ); fi;
# Construct the algebra as magma algebra modulo relations # over a free magma.
M:= FreeMagma( names );
# Construct the family of elements of our ring.
F:= NewFamily( "FreeLieAlgebraObjFamily",
IsElementOfMagmaRingModuloRelations,
IsJacobianElement and IsZeroSquaredElement );
SetFilterObj( F, IsFamilyElementOfFreeLieAlgebra );
one:= One( R );
zero:= Zero( R );
F!.defaultType := NewType( F, IsMagmaRingObjDefaultRep );
F!.familyRing := FamilyObj( R );
F!.familyMagma := FamilyObj( M );
F!.zeroRing := zero; #T no !!
F!.names := names;
# Set the characteristic. if HasCharacteristic( R ) or HasCharacteristic( FamilyObj( R ) ) then
SetCharacteristic( F, Characteristic( R ) ); fi;
# Make the magma ring object.
L:= Objectify( NewType( CollectionsFamily( F ),
IsMagmaRingModuloRelations
and IsAttributeStoringRep ),
rec() );
# Set the necessary attributes.
SetLeftActingDomain( L, R );
SetUnderlyingMagma( L, M );
# Deduce useful information.
SetIsFiniteDimensional( L, false ); if HasIsWholeFamily( R ) and HasIsWholeFamily( M ) then
SetIsWholeFamily( L, IsWholeFamily( R ) and IsWholeFamily( M ) ); fi;
# Construct the generators.
SetGeneratorsOfLeftOperatorRing( L,
List( GeneratorsOfMagma( M ),
x -> ElementOfMagmaRing( F, zero, [ one ], [ x ] ) ) );
# Install grading
SetGrading( L, rec( min_degree := 1,
max_degree := infinity,
source := Integers,
hom_components := function(degree)
local B, d, i, x, y, z;
B := GeneratorsOfMagma(M);
B := [List([1..Length(B)],i->[[i],fail,B[i]])]; for d in [2..degree] do
Add(B,[]); for i in [1..d-1] do for x in B[i] dofor y in B[d-i] do
z := Concatenation(x[1],y[1]); if z<y[1] and x[1]<y[1] and (x[2]=fail or x[2]>=y[1]) then
Add(B[d],[z,y[1],x[3]*y[3]]);
fi;
od; od;
od;
od; if degree<1then B := []; else B := B[degree]; fi;
return FreeLeftModule( R, List( B,
p->ElementOfMagmaRing( F, zero, [ one ], [ p[3] ] )), Zero(L)); end) ); # Return the ring.
return L; end );
############################################################################# ## #M NormalizedElementOfMagmaRingModuloRelations( <Fam>, <descr> ) ## ## <descr> is a list of the form `[ <z>, <list> ]', <z> being the zero ## coefficient of the ring, and <list> being the list of monomials and ## their coefficients. ## This function returns the element described in <descr> expanded on ## the Lyndon basis of the free Lie algebra. In order to do this we do not ## need to know this basis; we only need a test whether something is a ## Lyndon element (this is done in the function `IsLyndonT'). ## For the algorithm we refer to C. Reutenauer, Free Lie Algebras, Clarendon ## Press, Oxford, 1993. ##
DeclareGlobalName( "IsLyndonT" );
BindGlobal( "IsLyndonT", function( t )
# This function tests whether the bracketed expression `t' is # a Lyndon tree.
local w,w1,w2,b,y;
if not IsList( t ) then return true; fi;
w:= Flat( t ); if IsList( t[1] ) then
w1:= Flat( t[1] );
b:= false; else
w1:= [ t[1] ];
b:=true; fi; if IsList( t[2] ) then
w2:= Flat( t[2] ); else
w2:= [ t[2] ]; fi;
if w<w2 and w1<w2 then if not b then
y:= Flat( [ t[1][2] ] ); if y < w2 then return false; fi; fi; else
return false; fi;
return IsLyndonT(t[1]) and IsLyndonT(t[2]); end);
InstallMethod( NormalizedElementOfMagmaRingModuloRelations, "for family of free Lie algebra elements, and list",
true,
[ IsFamilyElementOfFreeLieAlgebra, IsList ], 0, function( Fam, descr )
local todo, #The list of elements that are to be expanded
k,i, #Loop variables
z,s,u,v,x,y,w, #Bracketed expressions (or `trees')
cf, #Coefficient
found, #Boolean
ll, #List
zero, #The zero element of the field
tlist, #List of elements of the free Lie algebra
Dcopy; #Two functions
Dcopy:=function( l )
if not IsList(l) then return ShallowCopy( l ); fi;
return List( l, Dcopy ); end;
zero:= descr[1];
todo:= [ ];
i:= 1;
# Every element in `todo' has the following format: [ bool, cf, br ], # where bool is a boolean; it is true if the br is a Lyndon tree. # cf is the coefficient (number) and br is a bracketed expression. # The reason for `tagging' everything is that almost anywhere in the # list cancellations may occur. This tagging provides an efficient way # of remembering which trees were dealt with before.
while i+1 <= Length(descr[2]) do
Add( todo, [ false, descr[2][i+1], ExtRepOfObj( descr[2][i] ) ] );
i:= i+2;
od;
k:= 1; while k<=Length(todo) do
s:= todo[k][3];
cf:= todo[k][2]; if not IsList( s ) then # `s' is a Lyndon tree
todo[k][1]:= true;
k:= k+1; elif cf = zero or s[1]=s[2] then # `s' is zero
ll:=Filtered([1..Length(todo)], x -> x<> k);
todo:= todo{ll}; elif todo[k][1] then # we already dealt with `s'
k:=k+1; elif IsLyndonT( s ) then # we do not need to expand `s'
todo[k][1]:=true;
k:=k+1; else #we expand `s'
found:= false; u:=s;
z:= Dcopy( s );
v:= z;
# we look for a subtree `u' such that is not a Lyndon tree # such that its left and right subtrees are Lyndon trees.
while not found do if IsLyndonT(u[1]) then if IsLyndonT(u[2]) then
found:=true; else
u:= u[2]; v:=v[2]; fi; else
u:= u[1]; v:=v[1]; fi;
od;
if u[1]=u[2] then # the whole expression `s' reduces to zero.
ll:= Filtered([1..Length(todo)], x->x<>k);
todo:= todo{ll}; else if Flat([u[1]]) > Flat([u[2]]) then # interchange u[1] and u[2]; this introduces a -.
w:=u[1];
u[1]:=u[2];
u[2]:=w;
i:= 1;
found:= false; while i<= Length( todo ) and not found do if todo[i][3] = s and k<>i then
todo[i][2]:= todo[i][2]-cf; if todo[i][2] = zero then
ll:=Filtered([1..Length(todo)],x->(x<>k and x<>i )); else
ll:=Filtered([1..Length(todo)],x->x<>k); fi;
todo:= todo{ll};
found:= true; fi;
i:=i+1;
od; if not found then todo[k][2]:=-todo[k][2]; fi; else #use the Jacobi identity.
x:=u[1][1];
y:=u[1][2];
w:= u[2];
u[1]:=[x,w];
u[2]:=y;
i:= 1;
found:= false; while i<= Length( todo ) and not found do if todo[i][3] = s and k<>i then
todo[i][2]:= todo[i][2]+cf; if todo[i][2] = zero then
ll:=Filtered([1..Length(todo)],x->(x<>k and x<>i )); else
ll:=Filtered([1..Length(todo)],x->x<>k); fi;
todo:= todo{ll};
found:= true; fi;
i:=i+1;
od;
i:= 1;
found:= false; while i<= Length( todo ) and not found do if todo[i][3] = z then
todo[i][2]:= todo[i][2]+cf;
found:= true; fi;
i:= i+1;
od; if not found then
Add( todo, [false,cf,z] ); fi; fi;
k:=1; fi; fi;
od;
# wrap the list `todo' into an element of the free Lie algebra.
todojava.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 35
Sort java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 20
MakeConfluent
Append( ##
od;
([ ;
end
############################################################################## ## #M ImageElm( <h>, <x> ) #M ImagesRepresentative( <h>, <x> ) ## ## A special method for calculating the (unique) image of an element <x> ## under an FptoSCAMorphism <h>. The fact that <h> knows the images of the ## generators together with the fact that <h> is an algebra morphism is used ## (rather than the linearity of <h>). ##
(java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 55
,
e:=MappingGeneratorsImages(h);
imgs:= e[2];
e:= ExtRepOfObj(x)[2];
im:= 0*imgs[1];
k:= 1; while k <= Length(e) do
im:= im + e[k+1]*EvalProduct( e[k], imgs );
k:= k+2;
od;
return im; end );
InstallMethod( ImageElm, "for Fp to SCA mapping, and element",
FamSourceEqFamElm,
[ IsFptoSCAMorphism, IsElementOfFpAlgebra ], 0,
FptoSCAMorphismImageElm );
InstallMethod( ImagesRepresentative, "for Fp to SCA mapping, and element",
FamSourceEqFamElm,
[ IsFptoSCAMorphism, IsElementOfFpAlgebra ], 0,
FptoSCAMorphismImageElm );
########################################################################### ## #M PreImagesRepresentative( f, x ) ##
InstallMethod( PreImagesRepresentative, "for Fp to SCA mapping, and element",
FamRangeEqFamElm,
[ IsFptoSCAMorphism, IsSCAlgebraObj ], 0,
function( f, x )
local dim, e, gens, imgs, b1, b2, levs,
brackets, sp, deg, newlev, newbracks, d, br1, br2,
i, j, a, b, c, z, imz, cf;
if not IsBound( f!.bases ) then
# We find bases of the source and the range that are mapped to # each other.
dim:= Dimension( Range(f) );
e:=MappingGeneratorsImages(f);
gens:= e[1];
imgs:= e[2];
b1:= ShallowCopy( gens );
b2:= ShallowCopy( imgs );
levs:= [ gens ];
brackets:= [ [1..Length(gens)] ];
sp:= MutableBasis( LeftActingDomain(Range(f)), b2 );
deg:= 1; while Length( b1 ) <> dim do
deg:= deg+1;
newlev:= [ ];
newbracks:= [ ]; # get all Lyndon elements of degree deg: for d in [1..Length(brackets)] do if Length( b1 ) = dim then break; fi;
br1:= brackets[d];
br2:= brackets[deg-d]; for i in [1..Length(br1)] do if Length( b1 ) = dim then break; fi; for j in [1..Length(br2)] do if Length( b1 ) = dim then break; fi;
a:= br1[i]; b:= br2[j]; if IsLyndonT( [a,b] ) then
c:= [a,b];
z:= levs[d][i]*levs[deg-d][j]; elif IsLyndonT( [b,a] ) then
c:= [b,a];
z:= levs[deg-d][j]*levs[d][i]; else
c:= [ ]; fi;
if c <> [] then
imz:= Image( f, z ); if not IsContainedInSpan( sp, imz ) then
CloseMutableBasis( sp, imz );
Add( b1, z );
Add( newlev, z );
Add( newbracks, c );
Add( b2, imz ); fi; fi;
cf:= Coefficients( f!.bases[2], x );
return cf*f!.bases[1];
end);
############################################################################# ## #M Dimension( <FpL> ) ## ## A method for the dimension of a finitely-presented Lie algebra. ##
InstallMethod( Dimension, "for a f.p. Lie algebra",
true,
[ IsLieAlgebra and IsSubalgebraFpAlgebra], 0, function( L )
local h;
h:= NiceAlgebraMonomorphism( L ); if h <> fail then
return Dimension( Range( h ) ); else
TryNextMethod(); fi; end);
############################################################################## ## #M IsFiniteDimensional( <FpL> ) ## ## For finitely-presented Lie algebras. ##
InstallMethod( IsFiniteDimensional, "for a f.p. Lie algebra",
true,
[ IsLieAlgebra and IsSubalgebraFpAlgebra], 0, function( L )
local h;
h:= NiceAlgebraMonomorphism( L ); if h <> fail then
return Dimension( Range( h ) ) < infinity; else
TryNextMethod(); fi; end);
############################################################################## ## ## FpLieAlgebraEnumeration( <arg> ) Juergen Wisliceny ## Willem de Graaf ## ## This function calculates a homomorphism of a finitely presented ## Lie algebra onto a structure constants algebra. ## The algorithm is guaranteed to terminate when the algebra is finite ## dimensional. In full length the list <arg> contains `FpL', a ## finitely presented Lie algebra, `MAX_WEIGHT', a bound on the length ## of the monomials (used for nilpotent quotients), `weights' (a list ## of weights of the variables) and finally a boolean indicating ## whether the relations are homogeneous (if so then the nilpotent ## quotient will be graded, the grading is set as an attribute of the ## range of the homomorphism). ## ## By a straightforward application of the Jacobi identity (see also the ## comments to the sub-function `LeftNormalization'), it can be seen that ## the space of all commutators of degree `n' is spanned by all left ## normed commutators (i.e., commutators of the form [[[[a,b],c],d]...]). ## By antisymmetry we have that a and b can be chosen such that a > b. ## This is the format for elements of the free Lie algebra used in the ## program. A left-normed commutator is represented by a list ## `[a,b,c,d,..]', meaning `[[[[a,b],c],d]...]'. A monomial is such a list ## together with a coefficient, e.g., `[ [a,b,c,d..], -2/3 ]'. Finally, a ## polynomial is a list of monomials.
vg, # List of pairs (newly defined commutators)
i,j,k,l,s, # Loop variables.
end_reached, #
table_init, # Booleans
relation_found, #
u,v,rr, # Lists of relations.
r,u1,r1,r2,k1,k2,k11, # Polynomials, monomials etc.
S,_T, # Structure constants tables.
rowS, # A row of the multiplication table.
sij,tij, # Entries of the multiplication table.
inds, # Indices (list of integers).
tab_pols, # List of polynomials of degree two.
intrel, # Initial relations (after first conversion).
pp, # Ext rep of a polynomial.
cf, # Coefficient.
t1,t2, # Indices.
max, # Maximum.
R, # Lists of commtators that have been defined.
Rw1, # A new roe of `R'.
one, # One of the field.
zero, # Zero of the field.
d, # maximum of the list of (pseudo-)generators
e, # Flat(e) is the list of (pseudo-)generators
w,ww, # Weights.
temp,
defs, # Definitions of generators in terms of other # generators.
FL, # The free Lie algebra.
rels, # Relators.
bound, # Bound for `w'.
gens, # Generators of `FpL'.
imgs, # Images.
map, # The map that is constructed.
im, # An image.
Fam, # Elements family of `FpL'.
K, # Structure constants algebra.
FpL,wts,wght,pos,fle,weight,MAX_WEIGHT,genweights,comp_grad,is_hom,
bas,gradcomps,degs,bgc;
if not IsList(l) then return ShallowCopy(l); fi;
m:=[]; for i in [1..Length(l)] do if IsBound(l[i]) then m[i]:= Dcopy(l[i]); fi;
od;
return m; end;
############################################################## ############################################################## # v, w are associative monomials. is v>w? ## ## v > w if and only if 1) Length(v)>Length(w) or ## 2) Length(v)=Length(w) and Length(v) > 1 and ## v[2] > w[2] or ## 3) Length(v)=Length(w) and v[2]=w[2] and ## v>w alphabetically. ##
gradorder:=function(v,w)
local k,l;
k:=Length(v[1]); l:=Length(w[1]); if k<>l then return k>l; elif k>1 and v[1][2]<>w[1][2] then return v[1][2]>w[1][2]; else return v>w; fi;
end;
grado:= function( v, w ) # tries to mimic gradorder for monomials of deg 2.
if v[2]<>w[2] then return v[2]>w[2]; else return v>w; fi; end;
# A function that collects equal things together, and gets rid of # things in the polynomial r that are zero.
local i,n,t;
if r <> [ ] then
# first regularize... for i in r do if Length(i[1])>1 and i[1][1]<i[1][2] then
t:=i[1][2]; i[1][2]:=i[1][1]; i[1][1]:=t;
i[2]:=-i[2]; fi;
od;
Sort( r, gradorder );
n:= Length( r );
for i in [1..n-1] do if r[i][2]=0*r[i][2] or
(Length(r[i][1])>1 and r[i][1][1]=r[i][1][2]) then
#the thing is zero; get rid of it.
Unbind(r[i]); elif r[i][1] = r[i+1][1] then
#the monomials are equal; collect them together.
r[i+1][2]:=r[i][2]+r[i+1][2];
Unbind(r[i]); fi;
od; if r[n][2]=0*r[n][2] or
(Length(r[n][1])>1 and r[n][1][1]=r[n][1][2]) then
#the thing is zero; get rid of it.
Unbind(r[n]); fi;
r:= Compacted( r );
fi;
return r;
end;
ReductionModuloTable := function( k )
# In this function a Lie polynomial `k' in standard form is # reduced by one step modulo the commutators already known by the # table. So if [x_i,x_j]= c*z is a relation in the table, and `k' # contains a monomial of the form [ [i,j,k,....], cf ] then this # monomial is replaced by [ [z,k,...], -c*cf ]
local i,j,k1,l,m,tst,t,s,cf,p,q,a;
a:= Dcopy( k ); for i in [1..Length(a)] do
l:=Length(a[i][1]); if l>1then
s:= a[i][1][1]; t:=a[i][1][2]; if s < t then
p:= t; q:= s; else
p:=s; q:=t; fi; if IsBound( _T[p] ) and IsBound( _T[p][q] ) then
k1:= [ ];
tst:= _T[p][q]; if s <> p then cf:= -1; else cf:= 1; fi; for j in [1..Length(tst[1])] do
Add( k1, [[tst[1][j]], cf*a[i][2]*tst[2][j]] );
od; if l>2then
m:=a[i][1]{[3..l]}; for j in [1..Length(k1)] do
Append(k1[j][1],m);
od; fi;
Unbind(a[i]);
Append(a,k1); fi; fi;
od;
a:=Compacted(a);
a:= CollectPolynomial( a );
if a = [ ] or a[1][2] = one then
return a;
else
cf:= 1/a[1][2];
return List( a, x -> [x[1],x[2]*cf] ); fi; end;
LeftNormalization:= function( rel )
# a left-normed monomial is of the form # # [a,b,c,d,e,...], meaning [[[[[a,b],c],d],e],...] # # Using the Jacobi identity every commutator can be represented # as a linear combination of left-normed commutators. # # In this function a polynomial `rel' is left normed. # The Jacobi identity is applied successively to achieve this. # This means that an expression of the form # # [a,b,c,[d,e],f] (where a,b,c are generators (this part is already # `done') and [d,e] is any bracketed expression having d and e as # left and right subtrees, # # to a sum # # [a,b,c,d,e,f] - [a,b,c,e,d,f]. # # Justification: # # [a,b,c,[d,e]]=[[[a,b],c],[d,e]] = [X,[d,e]] (with X=[[a,b],c]) # =-[d,[e,X]]-[e,[X,d]] # =[[e,X],d]+[[X,d],e] # =-[[X,e],d]+[[X,d],e]. #
local i,j,s,s1,s2,t,step_occurred;
step_occurred:= true; while step_occurred do
# if there no longer occur any Jacobi steps, then we stop.
i:=0;
step_occurred:= false; while i < Length( rel ) do
i:=i+1; j:=0; while j<Length(rel[i][1]) and not step_occurred do
j:=j+1; if IsList(rel[i][1][j]) and Length(rel[i][1][j])=2then
step_occurred:= true;
s:=rel[i][1]{[1..j-1]}; #i.e., the part already done (the X)
s1:=Concatenation(s,rel[i][1][j]);
s2:=Concatenation(s,[rel[i][1][j][2],rel[i][1][j][1]]);
t:=rel[i][1]{[j+1..Length(rel[i][1])]};
Append(s1,t); Append(s2,t);
rel[i][1]:=Dcopy(s1);
# If j=1 (so if the tree starts with [x,y], then we didn't do # much other than changing the notation ([[x,y],b] -> [x,y,b]).
# Here `rs' is a relation of the form `var = othervars', and `rels' is # a list of Lie polynomials. This function substitutes `var' # everywhere in the polynomials `rels'.
local i,j,p,s,s1,s2,result,rel,cf;
result:= [ ];
for rel in rels do
i:= 1; while i <= Length(rel) do
p:= Position( rel[i][1], rs[1][1][1] ); if p <> fail then
# s will be the polynomial that is gotten from r by substituting # `the rest of rs' for the variable rs[1][1][1] on the position p # in r.
s:= Dcopy( rs{[2..Length(rs)]} );
s1:= rel[i][1]{[1..p-1]};
s2:= rel[i][1]{[p+1..Length(rel[i][1])]}; for j in [1..Length(s)] do
s[j][1]:=Concatenation(s1,s[j][1],s2);
od;
s:= List( s, x -> [ x[1], -rel[i][2]*x[2] ] );
Append( rel, s );
Unbind( rel[i] );
rel:= Compacted( rel );
else
i:= i+1; fi;
od;
#collect the result...
rel:= CollectPolynomial( rel ); if rel <> [ ] and rel[1][2] <> one then
cf:= 1/rel[1][2];
rel:= List( rel, x -> [x[1],cf*x[2]] ); fi; if rel <> [ ] then AddSet( result, rel ); fi;
od;
return result; end;
UpdateTable:= function( i, j, p )
# Sets the commutator [xi,xj] in the table equal to the polynomial `p'.
local inds,cfs,k,s,t;
inds:=[];
cfs:=[]; for k in [1..Length(p)] do
inds[k]:= p[k][1][1];
cfs[k]:= p[k][2];
od; if i < j then
s:= j; t:= i; else
s:=i; t:= j; fi;
if s = i then cfs:= -cfs; fi; if not IsBound(_T[s]) then _T[s]:=[]; fi;
_T[s][t]:= [inds,cfs];
end;
RemoveEntry:= function( k )
# Removes all occurrences of the variable xk in the commutators # of the table.
local i;
Unbind(_T[k]); for i in [1..Length(_T)] do if IsBound( _T[i] ) then Unbind(_T[i][k]); fi;
od; end;
RemoveComm:= function( k, l )
# Removes the commutator [xk,xl] from the table.
local s,t;
s:= Maximum( k, l ); t:= Minimum( k, l ); if IsBound(_T[s][t]) then Unbind(_T[s][t]); fi; end;
SubstituteVariable:= function( coms, rel )
# Here `rel' is a polynomial of the form `var = othervars'; this # function substitutes `var' for `othervar' in the commutators of # the table prescribed by `coms'.
local var,inds,i,cfs,c,Tij,pos,cf,ii,cc,ind,s,t;
var := rel[1][1][1];
inds:= [ ]; cfs:= [ ]; for i in [2..Length(rel)] do
Add( inds, rel[i][1][1] );
Add( cfs, -rel[i][2] );
od;
cfs:= cfs/rel[1][2];
for c in coms do
s:= Maximum( c ); t:= Minimum( c );
Tij:= _T[s][t];
pos:= Position( Tij[1], var ); if pos <> fail then
Remove( Tij[1], pos );
cf:= Tij[2][pos]; if s <> c[1] then cf:= -cf; fi;
Remove( Tij[2], pos );
Append( Tij[1], inds );
Append( Tij[2], cf*cfs );
ii:= [ ]; cc:= [ ]; if Tij[1] <> [ ] then
SortParallel( Tij[1], Tij[2] );
ind:= Tij[1][1]; cf:= Tij[2][1];
ii:= [ ]; cc:= [ ]; for i in [2..Length(Tij[1])] do if Tij[1][i] = ind then
cf:= Tij[2][i] + cf; else
Add( ii, ind );
Add( cc, cf );
ind:= Tij[1][i];
cf:= Tij[2][i]; fi;
od;
Add( ii, ind ); Add( cc, cf ); fi;
_T[s][t]:= [ ii, cc ]; fi;
od;
end;
wght:= function( e, wts, var )
local p,q;
p:= PositionProperty( e, x -> var in x );
q:= Position( e[p], var );
return wts[p][q]; end;
############################################################################## # # The program starts. First the relations are transformed into internal format. # That is: represented as lists of lists etc., and left-normalized. #
# `intrel' will be the set of relations, but represented in # `internal form'; meaning [ [ [[1,2],3], 1 ], [[4],-1] ], instead # of (x1*x2)*x3-x4 etc.
intrel:= [ ]; for r in rels do
pp:= Dcopy( ExtRepOfObj( r )[2] );
Add( intrel, List( [1,3..Length(pp)-1], x -> [ pp[x], pp[x+1] ] ) );
od;
############################################################################# # now we left normalize the relations, using `LeftNormalization', i.e., # the relations are written as [ [ [1,2,5], -1], [.....], [......],.... ] # furthermore, all relations of degree at most two will go into `pr' # (those will be used to initialize the table). All the others go into # `u'.
tab_pols:= [ ]; u:= [ ];
for r in intrel do
max:= 0; for j in [1..Length(r)] do if not IsList(r[j][1]) then#transform [ i, cst ] into [ [i], cst ]
r[j][1]:= [ r[j][1] ]; fi; if Length(Flat(r[j][1])) >= 2 and r[j][1][1]=r[j][1][2] then
Unbind(r[j]); else
max:= Maximum( max, Length( Flat(r[j][1]) ) ); fi;
od;
r:= Compacted( r );
r:= LeftNormalization( r );
r:= CollectPolynomial( r ); if not max = 0then if max <= 2then
cf:= 1/r[1][2];
r:= List( r, x -> [x[1],cf*x[2]] );
Add( tab_pols, r); # So if the relation only # involves monomials of deg # at most two, then this relation # goes into the 'tab_pols'. else
Add( u, r ); fi; fi;
od;
e:= [ List( [1..Length( GeneratorsOfAlgebra( FL ) )], x -> x ), [ ] ]; if MAX_WEIGHT < infinity then
wts:= [ genweights, [] ];
comp_grad:= true; else
wts:= [ ];
comp_grad:= false; fi;
if e[1] = [ ] then
K:= LieAlgebraByStructureConstants( LeftActingDomain( FL ),
EmptySCTable( 0, zero, "antisymmetric" ) );
gens:= GeneratorsOfAlgebra( FpL );
imgs:= List( gens, x -> Zero( K ) );
map:= Objectify( TypeOfDefaultGeneralMapping( FpL, K,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsFptoSCAMorphism
and IsAlgebraGeneralMappingByImagesDefaultRep ),
rec(
generators := gens,
genimages := imgs
) );
SetMappingGeneratorsImages(map,[Immutable(gens),Immutable(imgs)]);
return map; fi;
# `v' will be a history of relations, i.e., `v[w]' will be the relations # as they were when the program was dealing with weight `w'. This is # used to reset the relations if a collision among variables is found.
####################################################################### # Initialize the table.... # Meaning: fill in all possible commutators of generators using the # relations, make definitions for the commutators that cannot be decided # upon by using the relations. If this leads to a relation among the variables, # then that relation is substituted first, and the process is started all # over again.
relation_found:= false;
for r in tab_pols do
r1:= ReductionModuloTable( r ); if r1<>[] then
if Length(r1[1][1])=1then
relation_found:= true;
break; else for k in [2..Length(r1)] do if Length(r1[k][1])=2then
d:=d+1;
Add(e[2],d); if comp_grad then
Add(wts[2],wght(e,wts,r1[k][1][1])+
wght(e,wts,r1[k][1][2]) ); fi;
UpdateTable( r1[k][1][1], r1[k][1][2], [ [[d],-one] ] );
Add(R[2],r1[k][1]);
r1[k][1]:=[d]; fi;
od;
UpdateTable( r1[1][1][1], r1[1][1][2], r1{[2..Length(r1)]} ); fi;
Add(R[2],r1[1][1]);
fi;
od;
if not relation_found then
# i.e., the previous loop has been executed without breaking # caused by finding a relation among the generators.
vg:=Difference( List( Combinations(e[1],2), Reversed ), R[2] );
Append( R[2], vg ); for i in [1..Length(vg)] do
d:=d+1;
Add(e[2],d); if comp_grad then
Add(wts[2],wght(e,wts,vg[i][1])+wght(e,wts,vg[i][2])); fi;
UpdateTable( vg[i][1], vg[i][2], [ [[d],-one] ] );
od;
rr:= [ ]; for i in [1..Length(u)] do
r:= Dcopy( u[i] ); while true do
r1:= ReductionModuloTable( r ); if r1 = r then break; else r:= r1; fi;
od; if r <> [ ] then if Length(r[1][1]) = 1 and r[1][1][1] in e[1] then
relation_found:= true;
break; else
Add( rr, r ); fi; fi;
od; fi;
if relation_found then
# i.e., a relation among the variables has been found in the # previous piece of code.
w:= Position( List( e, x -> r1[1][1][1] in x ), true ); if w = 1then if comp_grad then
pos:= Position( e[1], r1[1][1][1] );
Remove( wts[1], pos );
Remove( e[1], pos); else
RemoveSet( e[1], r1[1][1][1] ); fi;
Add( defs, r1 ); if e[1] = [ ] then
K:= LieAlgebraByStructureConstants( LeftActingDomain( FL ),
EmptySCTable( 0, zero, "antisymmetric" ) );
gens:= GeneratorsOfAlgebra( FpL );
imgs:= List( gens, x -> Zero( K ) );
map:= Objectify( TypeOfDefaultGeneralMapping( FpL, K,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsFptoSCAMorphism
and IsAlgebraGeneralMappingByImagesDefaultRep ),
rec(
generators := gens,
genimages := imgs
) );
SetMappingGeneratorsImages(map,[Immutable(gens),Immutable(imgs)]);
return map; fi;
e[2]:= [ ]; if comp_grad then
wts[2]:= [ ]; fi;
tab_pols:= SubsVarInRels( tab_pols, r1 );
u:= SubsVarInRels( u, r1 );
_T:= [ ];
R:= [ [], [] ]; else if comp_grad then
pos:= Position( e[w], r1[1][1][1] );
Remove( wts[w], pos );
Remove( e[w], pos); else
RemoveSet( e[w], r1[1][1][1]); fi;
########################################################################## # # The table has been initialized, and the commutators of weight 2 # have been defined. Now the process of increasing the weight starts. #
w:=1; while w < bound do
w:=w+1;
Sort( R[w], grado );
if comp_grad then
fle:= Flat(e); for i in [1..Length(fle)] do for j in [i+1..Length(fle)] do if wght(e,wts,fle[i])+wght(e,wts,fle[j])>MAX_WEIGHT then
UpdateTable( fle[i], fle[j], [] ); fi;
od;
od; fi;
############################################################################# # reduction modulo relations and Jacobi identity.... # # In this function also _T is changed; but if the function # exits with a relation among the vars, then we change `_T' back to its # old value (the copy `S'). #
S:= Dcopy( _T );
rr:= Dcopy( u );
Rw1:= [ ];
e[w+1]:= [ ]; if comp_grad then
wts[w+1]:= [ ]; fi;
d:= Maximum( Flat( e ) );
relation_found:= false;
for r in R[w] do
t1:=r[1]; t2:=r[2]; if t1 > t2 then
tij:= _T[t1][t2]; else
tij:= ShallowCopy( _T[t2][t1] );
tij[2]:= -ShallowCopy( tij[2] ); fi;
r1:= List( [1..Length(tij[1])], k -> [ [tij[1][k]], tij[2][k] ] );
for j in e[1] do
# The Jacobi identity that will be inspected reads as # [ [ t1, t2 ], j ] - [ [ t1, j ], t2 ] + [ [ t2, j ], t1 ] = 0 # This relation can be evaluated (using the partial table) to a # polynomial of degree <=2. This will lead to new definitions # (in the case of deg. = 2), or collisions (in the case of # deg. = 1).
ww:= 0; for i in [1..Length(e)] do if k11[1] in e[i] then ww:=i; break; fi;
od;
if ww = w+1then
# A collision (among the new basis elements) has been found.
if comp_grad then
pos:= Position( e[w+1], k11[1] );
Remove( wts[w+1], pos ); fi;
RemoveSet( e[w+1], k11[1] );
RemoveEntry( k11[1] );
SubstituteVariable( Rw1, k );
rr:= SubsVarInRels( rr, k ); elif ww > 0then
_T:=S;
relation_found:= true;
r1:= [ ww, k ];
break; fi; fi;
i:= 0; while i < Length(rr) do
i:= i+1; # Reduce the relations modulo the table and process them.
while true do
u1:= ReductionModuloTable( rr[i] ); if u1 = rr[i] then break; else rr[i]:=u1; fi;
od;
if rr[i]=[] then
Unbind( rr[i] ); elif Length(rr[i][1][1])=1then
ww:= 0;
temp:= rr[i][1][1][1]; for l in [1..Length(e)] do if temp in e[l] then ww:=l; break; fi;
od;
if ww = w+1then if comp_grad then
pos:= Position( e[w+1],rr[i][1][1][1] );
Remove( wts[w+1], pos ); fi;
RemoveSet(e[w+1],rr[i][1][1][1]);
RemoveEntry(rr[i][1][1][1]);
SubstituteVariable( Rw1, rr[i] );
temp:= rr[i];
Remove( rr, i );
rr:= SubsVarInRels( rr, temp );
i:= i-1; # (last call removed holes...). elif ww > 0then
_T:=S;
relation_found:= true;
r1:= [ww,rr[i]];
break; fi; elif Length(rr[i][1][1])=2then
max := 0; for s in rr[i] do
ww:= 0; for l in [1..Length(e)] do if s[1][1] in e[l] then ww:=l; break; fi;
od; if Length(s[1]) = 1then
max:= Maximum(max,ww); else # We calculate the weight of `s[1][1]' + the weight # of `s[1][2]' i.e., the weight of `[s[1][1], s[1][2]]'
for l in [1..Length(e)] do if s[1][2] in e[l] then ww:=ww+l; break; fi;
od;
max:= Maximum(max,ww); fi;
od;
if max = w+1then
s:= 2; while s <= Length( rr[i] ) do if Length(rr[i][s][1]) = 2then if wts <> [ ] then
weight:= wght(e,wts,rr[i][s][1][1])+
wght(e,wts,rr[i][s][1][2] ); else
weight:= 0; fi; if weight <= MAX_WEIGHT then
d:= d+1;
Add( e[w+1], d ); if wts <> [ ] then
Add( wts[w+1], weight ); fi;
UpdateTable( rr[i][s][1][1], rr[i][s][1][2],
[ [[d], -one] ] );
Add(Rw1,rr[i][s][1]);
rr[i][s][1]:= [ d ]; else
Remove( rr[i], s ); fi; fi;
s:= s+1;
od;
Add(Rw1,rr[i][1][1]);
UpdateTable( rr[i][1][1][1], rr[i][1][1][2],
rr[i]{[2..Length(rr[i])]});
Unbind(rr[i]); fi; fi;
od; if relation_found then break; fi;
rr:=Compacted(rr); fi;
# Here `r1[2]' is a relation among basis elements. # `r1[1]' is the weight of the homogeneous component containing # the first variable (variable of highest weight).
w:= r1[1];
if w = 1then
# A relation among the variables of weight 1 has been found. # We reset everything and return to the point where the table # is initialized.
if comp_grad then
pos:= Position( e[1], r1[2][1][1][1] );
Remove( wts[1], pos ); fi;
RemoveSet( e[1], r1[2][1][1][1] );
Add( defs, r1[2] ); if e[1]=[] then
K:= LieAlgebraByStructureConstants( LeftActingDomain( FL ),
EmptySCTable( 0, zero, "antisymmetric" ) );
gens:= GeneratorsOfAlgebra( FpL );
imgs:= List( gens, x -> Zero( K ) );
map:= Objectify( TypeOfDefaultGeneralMapping( FpL, K,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsFptoSCAMorphism
and IsAlgebraGeneralMappingByImagesDefaultRep ),
rec(
generators := gens,
genimages := imgs
) );
SetMappingGeneratorsImages(map,[Immutable(gens),Immutable(imgs)]);
return map; fi;
e:=[ e[1], [] ]; if comp_grad then
wts:= [ wts[1], [] ]; fi;
u:= SubsVarInRels( v[1], r1[2] );
tab_pols:= SubsVarInRels( tab_pols, r1[2] );
_T:=[];
R:=[ [ ], List( tab_pols, x -> x[1][1] ) ];
v[1]:= Dcopy( u );
# We break to the principal loop.
break; else
# here `r1[2]' is of the form `var=something' where `var' is of weight # `w', and `w>1'. This means that `var' was introduced somewhere; namely # on level `w'. Hence the definition was [x_i,x_j]=var, where w(x_i)+ # w(x_j)=w. Hence `var' only appears in tails (right hand sides) of commutators # of weight `>= w'. Now `var' is substituted in all products of weight `w', # and the program starts again on that level.
if comp_grad then
pos:= Position( e[w], r1[2][1][1][1] );
Remove( wts[w], pos ); fi;
RemoveSet(e[w], r1[2][1][1][1]);
u:= SubsVarInRels( v[w-1], r1[2]);
v[w-1]:=u;
w:= w-1;
SubstituteVariable( R[w+1], r1[2] ); for i in [w+2..Length(e)] do e[i]:=[]; od; for i in [w+2..Length(R)] do for j in [1..Length(R[i])] do
RemoveComm( R[i][j][1], R[i][j][2] );
od;
R[i]:= [ ];
od;
fi;
else
# Here Jacobi identities have been applied # without finding collisions between variables.
if e[w] = [ ] and not end_reached then
bound:= 2*w; end_reached:= true; elif w = bound and not end_reached then
return fail; fi;
R[w+1]:= Rw1; v[w]:= rr; u:= rr;
if Flat( e ) = [ ] then
K:= LieAlgebraByStructureConstants( LeftActingDomain( FL ),
EmptySCTable( 0, zero, "antisymmetric" ) );
gens:= GeneratorsOfAlgebra( FpL );
imgs:= List( gens, x -> Zero( K ) );
map:= Objectify( TypeOfDefaultGeneralMapping( FpL, K,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsFptoSCAMorphism
and IsAlgebraGeneralMappingByImagesDefaultRep ),
rec(
generators := gens,
genimages := imgs
) );
SetMappingGeneratorsImages(map,[Immutable(gens),Immutable(imgs)]);
return map; fi;
d:= Maximum( Flat( e ) );
vg:= [ ]; for i in e[w] do for j in e[1] do if i>j then AddSet( vg, [i,j] ); fi;
od;
od;
vg:= Difference( vg, R[w+1] );
Append( R[w+1], vg );
for i in [1..Length(vg)] do if comp_grad then
weight:= wght(e,wts,vg[i][1])+wght(e,wts,vg[i][2]); else
weight:= 0; fi; if weight <= MAX_WEIGHT then
d:= d+1;
Add( e[w+1], d ); if comp_grad then
Add( wts[w+1], weight ); fi;
Add( R[w+1], vg[i] );
UpdateTable( vg[i][1], vg[i][2], [ [[d],-1*one] ]); else
UpdateTable( vg[i][1], vg[i][2], [ ] ); fi;
od;
fi;
od; # end of the loop in which `w' is successively increased.
od; # end of the main loop,
# Now we construct a table of structure constants from `_T'.
e:=Filtered(e,x->x<>[]);
inds:=Flat(e);
S:=[]; for i in inds do
rowS:= [ ]; for j in inds do if i=j then
Add( rowS, [ [], [] ] ); else if i < j then
tij:= ShallowCopy( _T[j][i] );
tij[2]:= -ShallowCopy( tij[2] ); else
tij:= _T[i][j]; fi;
sij:=[[],[]]; for k in [1..Length(tij[1])] do
sij[1][k]:= Position( inds, tij[1][k] );
sij[2][k]:= tij[2][k];
od;
Add( rowS, sij ); fi;
od;
Add( S, rowS );
od;
Add( S, -1 ); Add( S, zero );
K:= LieAlgebraByStructureConstants( LeftActingDomain( FL ), S ); if is_hom then
wts:= Flat( wts );
bas:= [1..Dimension(K)];
SortParallel( wts, bas );
gradcomps:= [ ];
degs:= [ ];
k:= 1; while k <= Length(wts) do
bgc:= [ Basis( K )[bas[k]] ];
Add( degs, wts[k] ); while k < Length( wts ) and wts[k]=wts[k+1] do
k:= k+1;
Add( bgc, Basis(K)[bas[k]] );
od;
Add( gradcomps, VectorSpace( LeftActingDomain( K ), bgc ) );
k:= k+1;
od;
Add( gradcomps, Subspace( K, [ ] ) );
SetGrading( K, rec( min_degree:= Minimum( wts ),
max_degree:= Maximum( wts ),
source:= Integers,
hom_components:= function( d ) if d in degs then
return gradcomps[Position(degs,d)]; else
return Last(gradcomps); fi; end
) );
fi;
gens:= GeneratorsOfAlgebra( FpL );
if Dimension( K ) = 0then#trivial case
imgs:= List( gens, x -> Zero(K) ); else # We process the definitions, (of generators as linear combinations # of other generators).
i:= Length( defs ); while i > 1do for j in [1..i-1] do for k in [1..Length(defs[j])] do if defs[j][k][1] = defs[i][1][1] then
Append( defs[j], List( defs[i]{[2..Length(defs[i])]}, x ->
[ x[1], -defs[j][k][2]*x[2] ] )
);
Unbind( defs[j][k] ); fi;
od;
defs[j]:= Compacted( defs[j] );
od;
i:= i-1;
od;
imgs:= [ ];
#For every generator of the Fp Lie algebra we calculate an image...
for i in [1..Length(gens)] do if i in e[1] then
Add( imgs, Basis( K )[Position( inds, i )] ); else for j in [1..Length(defs)] do if defs[j][1][1][1] = i then break; fi;
od;
im:= Zero( K ); for k in [2..Length(defs[j])] do
im:= im + -defs[j][k][2]*Basis( K )[defs[j][k][1][1]];
od;
Add (imgs, im ); fi;
od; fi;
# Construct the map...
map:= Objectify( TypeOfDefaultGeneralMapping( FpL, K,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsFptoSCAMorphism
and IsAlgebraGeneralMappingByImagesDefaultRep ),
rec(
generators := gens,
genimages := imgs
) );
SetMappingGeneratorsImages(map,[Immutable(gens),Immutable(imgs)]);
return map;
end );
InstallMethod( NiceAlgebraMonomorphism, "for a f.p. Lie algebra",
true,
[ IsLieAlgebra and IsSubalgebraFpAlgebra], 0,
weight:= infinity;
er:= ExtRepOfObj( r )[2]; for k in [1,3..Length(er)-1] do
fol:= Flat( [ er[k] ] );
w:= 0; for j in fol do
w:= w+weights[j];
od; if weight = infinity then
weight:= w; elif weight <> w then
is_homogeneous:= false;
break; fi;
od; if not is_homogeneous then break; fi;
od;
local i,j,k, # Loop variables.
l, # The rank.
L, # The free Lie algebra.
g, # Generators of `L'.
x,h,y, # Lists of generators of `L'.
rels, # List of relations.
rx,ry; # Relations.
l:= Length( C );
L:= FreeLieAlgebra( Rationals, 3*l );
g:= GeneratorsOfAlgebra( L );
x:= g{[1..l]};
h:= g{[l+1..2*l]};
y:= g{[2*l+1..3*l]};
rels:= [ ]; for i in [1..l] do for j in [i+1..l] do
Add( rels, h[i]*h[j] );
od;
od;
for i in [1..l] do for j in [1..l] do if i=j then
Add( rels, x[i]*y[j]-h[i] ); else
Add( rels, x[i]*y[j] ); fi;
od;
od;
for i in [1..l] do for j in [1..l] do
Add( rels, h[i]*x[j]-C[j][i]*x[j] );
Add( rels, h[i]*y[j]+C[j][i]*y[j] );
od;
od;
for i in [1..l] do for j in [1..l] do if i <> j then
rx:= x[j]; ry:= y[j]; for k in [1..1-C[j][i]] do
rx:= x[i]*rx; ry:= y[i]*ry;
od;
Add( rels, rx ); Add( rels, ry ); fi;
od;
od;
return L/rels;
end );
############################################################################# ## #M JenningsLieAlgebra( <G> ) ## ## The Jennings Lie algebra of the p-group G. ## ##
InstallMethod( JenningsLieAlgebra, "for a p-group",
true,
[IsGroup], 0,
function ( G )
local J, # Jennings series of G
Homs, # Homomorphisms of J[i] onto the quotient J[i]/J[i+1]
grades, # List of the full images of the maps in Homs
gens, # List of the generators of the quotients J[i]/J[i+1], # i.e., a basis of the Lie algebra.
pos, # list of positions: if pos[j] = p, then the element # gens[j] belongs to grades[p]
i,j,k, # loop variables
tempgens,
t, # integer
T, # multiplication table of the Lie algebra
dim, # dimension of the Lie algebra
a,b,c,f, # group elements
e, # ext rep of a group element
co, # entry of the multiplication table
p, # the prime of G
F, # ground field
L, # the Lie algebra to be constructed
pimgs, # pth-power images
B, # Basis of L
vv, x, # elements of L
comp, # homogeneous component
grading, # list of homogeneous components
pcgps, # list of pc groups, isom to the elts of `grades'.
hom_pcg, # list of isomomorphisms of `grades[i]' to `pcgps[i]'.
enum_gens, # List of numbers of elts of `gens' in extrep.
pp, # Position in a list.
hm;
# We do not know the characteristic if `G' is trivial. if IsTrivial( G ) then
Error( "<G> must be a nontrivial p-group" ); fi;
# Construct the homogeneous components of `L':
J:=JenningsSeries ( G );
Homs:= List ( [1..Length(J)-1] , x ->
NaturalHomomorphismByNormalSubgroupNC( J[x], J[x+1] ));
grades := List ( Homs , Range );
hom_pcg:= List( grades, IsomorphismSpecialPcGroup );
pcgps:= List( hom_pcg, Range );
gens := [];
enum_gens:= [ ];
pos := []; for i in [1.. Length(grades)] do
tempgens:= GeneratorsOfGroup( pcgps[i] );
Append ( gens , tempgens);
# Record the number that each generator has in extrep.
Add( enum_gens, List( tempgens, x -> ExtRepOfObj( x )[1] ) );
Append ( pos , List ( tempgens , x-> i ) );
od;
# Construct the field and the multiplication table:
dim:= Length(gens);
p:= PrimePGroup( G );
F:= GF( p );
T:= EmptySCTable( dim , Zero(F) , "antisymmetric" );
pimgs := []; for i in [1..dim] do
a:= PreImagesRepresentative( Homs[pos[i]] ,
PreImagesRepresentative( hom_pcg[pos[i]], gens[i] ) );
# calculate the p-th power image of `a':
if pos[i]*p <= Length(Homs) then
Add( pimgs, Image( hom_pcg[pos[i]*p],
Image( Homs[pos[i]*p], a^p) ) ); else
Add( pimgs, "zero" ); fi;
for j in [i+1.. dim] do if pos[i]+pos[j] <= Length( Homs ) then
# Calculate the commutator [a,b], and map the result into # the correct homogeneous component.
b:= PreImagesRepresentative( Homs[pos[j]],
PreImagesRepresentative( hom_pcg[pos[j]], gens[j] ));
c:= Image( hom_pcg[pos[i] + pos[j]],
Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) );
e:= ExtRepOfObj(c);
co:=[]; for k in [1,3..Length(e)-1] do
pp:= Position( enum_gens[pos[i]+pos[j]], e[k] );
t:= Sum( enum_gens{[1..pos[i]+pos[j]-1]}, Length )+pp;
Add( co, One( F )*e[k+1] );
Add( co, t );
od;
SetEntrySCTable( T, i, j, co ); fi;
od;
od;
L:= LieAlgebraByStructureConstants( F, T );
B:= Basis( L );
# Now we compute the natural grading of `L'.
grading:= [ ];
k:= 1; for i in [1..Length(enum_gens)] do
comp:= [ ]; for j in [1..Length(enum_gens[i])] do
Add( comp, B[k] );
k:= k+1;
od;
Add( grading, Subspace( L, comp ) );
od;
Add( grading, Subspace( L, [ ] ) );
SetGrading( L, rec( min_degree:= 1,
max_degree:= Length( grading ) - 1,
source:= Integers,
hom_components:= function( d ) if d in [1..Length(grading)] then
return grading[d]; else
return Last(grading); fi; end
)
);
vv:= BasisVectors( B );
# Set the pth-power images of the basis elements of `B':
for i in [1..Length(pimgs)] do if pimgs[i] = "zero"then
pimgs[i]:= Zero( L ); else
e:= ExtRepOfObj( pimgs[i] );
x:= Zero( L ); for k in [1,3..Length(e)-1] do
pp:= Position( enum_gens[pos[i]*p], e[k] );
t:= Sum( enum_gens{[1..pos[i]*p-1]}, Length )+pp;
x:= x+ One( F )*e[k+1]*vv[t];
od;
pimgs[i]:= x; fi;
od;
SetPthPowerImages( B, pimgs );
SetIsRestrictedLieAlgebra( L, true );
FamilyObj(Representative(L))!.pMapping := pimgs;
SetIsLieNilpotent( L, true );
hm:= function( g, i )
local h, e, x, k, pp, f, t;
if not g in J[i] then
Error("<g> is not an element of the i-th term of the series used to define <L>"); fi;
h:= Image( hom_pcg[i], Image(Homs[i], g ));
e:= ExtRepOfObj(h);
x:= Zero(L); for k in [1,3..Length(e)-1] do
pp:= Position( enum_gens[i], e[k] );
f:= GeneratorsOfGroup( pcgps[i] )[pp];
t:= Position( gens, f );
x:= x + e[k+1]*Basis(L)[t];
od;
return x; end ;
############################################################################# ## #M PCentralLieAlgebra( <G> ) ## ## The p-central Lie algebra of the p-group G. ## ##
InstallMethod( PCentralLieAlgebra, "for a p-group",
true,
[IsGroup], 0,
function ( G )
local J, # p-central series of G
Homs, # Homomorphisms of J[i] onto the quotient J[i]/J[i+1]
grades, # List of the full images of the maps in Homs
gens, # List of the generators of the quotients J[i]/J[i+1], # i.e., a basis of the Lie algebra.
pos, # list of positions: if pos[j] = p, then the element # gens[j] belongs to grades[p]
i,j,k, # loop variables
tempgens,
t, # integer
T, # multiplication table of the Lie algebra
dim, # dimension of the Lie algebra
a,b,c,f, # group elements
e, # ext rep of a group element
co, # entry of the multiplication table
p, # the prime of G
F, # ground field
L, # the Lie algebra to be constructed
B, # Basis of L
vv, x, # elements of L
comp, # homogeneous component
grading, # list of homogeneous components
pcgps, # list of pc groups, isom to the elts of `grades'.
hom_pcg, # list of isomomorphisms of `grades[i]' to `pcgps[i]'.
enum_gens, # List of numbers of elts of `gens' in extrep.
pp, # Position in a list.
pimgs, # pth power images
hm;
# We do not know the characteristic if `G' is trivial. if IsTrivial( G ) then
Error( "<G> must be a nontrivial p-group" ); fi;
# Construct the homogeneous components of `L':
p:= PrimePGroup( G );
J:= PCentralSeries( G, p );
Homs:= List ( [1..Length(J)-1] , x ->
NaturalHomomorphismByNormalSubgroupNC( J[x], J[x+1] ));
grades := List ( Homs , Range );
hom_pcg:= List( grades, IsomorphismSpecialPcGroup );
pcgps:= List( hom_pcg, Range );
gens := [];
enum_gens:= [ ];
pos := []; for i in [1.. Length(grades)] do
tempgens:= GeneratorsOfGroup( pcgps[i] );
Append ( gens , tempgens);
# Record the number that each generator has in extrep.
Add( enum_gens, List( tempgens, x -> ExtRepOfObj( x )[1] ) );
Append ( pos , List ( tempgens , x-> i ) );
od;
# Construct the field and the multiplication table:
dim:= Length(gens);
F:= GF( p );
T:= EmptySCTable( dim , Zero(F) , "antisymmetric" );
pimgs := []; for i in [1..dim] do
a:= PreImagesRepresentative( Homs[pos[i]] ,
PreImagesRepresentative( hom_pcg[pos[i]], gens[i] ) );
# calculate the p-th power image of `a':
if pos[i]+1 <= Length(Homs) then
Add( pimgs, Image( hom_pcg[pos[i]+1],
Image( Homs[pos[i]+1], a^p) ) ); else
Add( pimgs, "zero" ); fi;
for j in [i+1.. dim] do if pos[i]+pos[j] <= Length( Homs ) then
# Calculate the commutator [a,b], and map the result into # the correct homogeneous component.
b:= PreImagesRepresentative( Homs[pos[j]],
PreImagesRepresentative( hom_pcg[pos[j]], gens[j] ));
c:= Image( hom_pcg[pos[i] + pos[j]],
Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) );
e:= ExtRepOfObj(c);
co:=[]; for k in [1,3..Length(e)-1] do
pp:= Position( enum_gens[pos[i]+pos[j]], e[k] );
t:= Sum( enum_gens{[1..pos[i]+pos[j]-1]}, Length )+pp;
Add( co, One( F )*e[k+1] );
Add( co, t );
od;
SetEntrySCTable( T, i, j, co ); fi;
od;
od;
L:= LieAlgebraByStructureConstants( F, T );
B:= Basis( L );
# Now we compute the natural grading of `L'.
grading:= [ ];
k:= 1;
for i in [1..Length(enum_gens)] do
comp:= [ ]; for j in [1..Length(enum_gens[i])] do
Add( comp, B[k] );
k:= k+1;
od;
Add( grading, Subspace( L, comp ) );
od;
Add( grading, Subspace( L, [ ] ) );
SetGrading( L, rec( min_degree:= 1,
max_degree:= Length( grading ) - 1,
source:= Integers,
hom_components:= function( d ) if d in [1..Length(grading)] then
return grading[d]; else
return Last(grading); fi; end
)
);
vv:= BasisVectors( B );
# Set the pth-power images of the basis elements of `B':## in <Cite Key="Maas2010"/>. Methods for <Ref Attr="EpimorphismSchurCover"/> are
## spin (projective) representation of the symmetric group of degree <A>n</A> "zero"then
pimgs[i]:= Zero( L )s# default. If no <A>p</A> is specified, 3 is used by default.
e:= ExtRepOfObj##
x:= Zero( L ); for k in [1,3..Length(e)-1] do
pp:= Position( enum_gens[pos[i]+1], e[k] );
t:= Sum( enum_gens{[1..pos[i]]}, Length )+pp;
x:= x+ One( F )*e[k+1]*vv[t];
od;
pimgs[i]:= x; fi;
od;
SetPthPowerImages( B, pimgs );
SetIsRestrictedLieAlgebra( L, true );
SetIsLieNilpotent( L, true );
hm:= function( g, i )
local h, e, x, k, pp, f, t;
if not g in J[i] then
Error("<g> is not an element of the i-th term of the series used to define <L>"); fi;
h:= Image( hom_pcg[i], Image(Homs[i], g ));
e:= ExtRepOfObj(h);
x:= Zero(L); for k in [1,3..Length(e)-1] do
pp:= Position( enum_gens[i], e[k] );
f:= GeneratorsOfGroup( pcgps[i] )[pp];
t:= Position( gens, f );
x:= x + e[k+1]*Basis(L)[t];
od;
return x; end ;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.313Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.