|
############################################################################
##
#W tensor.gi QuaGroup Willem de Graaf
##
##
## Tensor products of quantized enveloping algebras and their modules.
##
##############################################################################
##
#M ConvertToNormalFormMonomialElement( <te> ) . . for a tensor qeaPow element
##
InstallMethod( ConvertToNormalFormMonomialElement,
"for a tensor qeaPow element",
true, [ IsQEATensorPowElement ], 0,
function( u )
local eu, fam, famqea, tensors, cfts, i, le, k, tt, ei,
c, j, tt1, res, len;
# We expand every component of every tensor in `u' wrt the
# PBW-type basis.
if u![2] then return u; fi;
eu:= ExtRepOfObj( u );
fam:= FamilyObj( u );
famqea:= fam!.qeaElementsFam;
# `tensors' will be a list of tensors, i.e., a list of lists
# of algebra module elements. `cfts' will be the list of their
# coefficients.
tensors:= [ ];
cfts:= [ ];
for i in [1,3..Length(eu)-1] do
if eu[i] <> [ ] then #i.e., if it is not the zero tensor
Add( tensors, eu[i] );
Add( cfts, eu[i+1] );
fi;
od;
if tensors = [ ] then
# the thing is zero...
res:= ObjByExtRep( fam, [ [], fam!.zeroCoefficient ] );
res![2]:= true;
return res;
fi;
for i in [1..fam!.degree] do
# in all tensors expand the i-th component
le:= Length( tensors );
for k in [1..le] do
tt:= ShallowCopy( tensors[k] );
ei:= tensors[k][i]![1];
c:= cfts[k];
# we replace the tensor on position `k', and add the rest
# to the end of the list.
for j in [1,3..Length(ei)-1] do
tt1:= ShallowCopy( tt );
tt1[i]:= ObjByExtRep( famqea, [ ei[j], ei[j+1]^0 ] );
if j = 1 then
tensors[k]:= tt1;
cfts[k]:= c*ei[j+1];
else
Add( tensors, tt1 );
Add( cfts, c*ei[j+1] );
fi;
od;
if Length( ei ) = 0 then
# i.e., the tensor is zero, erase it
Unbind( tensors[k] );
Unbind( cfts[k] );
fi;
od;
tensors:= Filtered( tensors, x -> IsBound( x ) );
cfts:= Filtered( cfts, x -> IsBound( x ) );
od;
# Merge tensors and coefficients, take equal tensors together.
SortParallel( tensors, cfts );
res:= [ ];
len:= 0;
for i in [1..Length(tensors)] do
if len > 0 and tensors[i] = res[len-1] then
res[len]:= res[len]+cfts[i];
if res[len] = 0*res[len] then
Unbind( res[len-1] );
Unbind( res[len] );
len:= len-2;
fi;
else
Add( res, tensors[i] );
Add( res, cfts[i] );
len:= len+2;
fi;
od;
if res = [] then res:= [ [], fam!.zeroCoefficient ]; fi;
res:= ObjByExtRep( fam, res );
res![2]:= true;
return res;
end );
############################################################################
##
#M \*( <qt1>, <qt2> )
#M OneOp( <qt> )
##
InstallMethod( \*,
"for qea tensor power elements",
IsIdenticalObj, [ IsQEATensorPowElement, IsQEATensorPowElement ], 0,
function( qt1, qt2 )
local res, e1, e2, i, j, mon, k;
res:= [ ];
e1:= qt1![1]; e2:= qt2![1];
for i in [1,3..Length(e1)-1] do
for j in [1,3..Length(e2)-1] do
mon:= [ ];
for k in [1..FamilyObj(qt1)!.degree] do
Add( mon, e1[i][k]*e2[j][k] );
od;
Add( res, mon );
Add( res, e1[i+1]*e2[j+1] );
od;
od;
res:= ObjByExtRep( FamilyObj( qt1 ), res );
res![2]:= false;
return ConvertToNormalFormMonomialElement( res );
end);
InstallMethod( OneOp,
"for a qea tensor Power element",
true, [ IsQEATensorPowElement ], 0,
function( qt )
local one, res;
one:= One(
GeneratorsOfAlgebra( FamilyObj( qt )!.qeaElementsFam!.qAlgebra )[1]
);
res:= ObjByExtRep( FamilyObj( qt ),
[ List( [1..FamilyObj(qt)!.degree], x -> one ),
One( FamilyObj( qt )!.zeroCoefficient ) ] );
res![2]:= true;
return res;
end );
############################################################################
##
#M TensorPower( <U>, <d> )
##
## returns the d-fold tensor product of U with itself.
##
InstallMethod( TensorPower,
"for a quantized enveloping algebra and integer",
true, [ IsQuantumUEA, IsInt ], 0,
function( QA, deg )
local qfam, F, fam, type, gg, one, gens, i, j, g, T;
# In order to avoid constructing the same tensor powers twice
# we store them in the elements family of the family of the
# quantized enveloping algebra.
qfam:= ElementsFamily( FamilyObj( QA ) );
if IsBound( qfam!.tensorPowers ) then
if IsBound( qfam!.tensorPowers[deg] ) then
return qfam!.tensorPowers[deg];
fi;
else
qfam!.tensorPowers:=[];
fi;
# We first make the family of the tensor elements,
F:= LeftActingDomain( QA );
fam:= NewFamily( "TensorElementsFam", IsQEATensorPowElement );
type:= NewType( fam, IsMonomialElementRep );
fam!.monomialElementDefaultType:= type;
fam!.zeroCoefficient:= Zero( F );
fam!.qeaElementsFam:= ElementsFamily( FamilyObj( QA ) );
fam!.degree:= deg;
gg:= GeneratorsOfAlgebra( QA );
one:= One( gg[1] );
gens:= [ ];
for i in [1..deg] do
for j in [1..Length(gg)] do
g:= List( [1..deg], x -> one );
g[i]:= gg[j];
Add( gens, g );
od;
od;
Sort( gens );
gens:= List( gens, x -> ObjByExtRep( fam, [ x , One(F) ] ) );
for i in [1..Length(gens)] do
gens[i]![2]:= true;
od;
T:= AlgebraByGenerators( F, gens );
SetOne( T, gens[1]^0 );
qfam!.tensorPowers[deg]:= T;
return T;
end );
###########################################################################
##
## DeltaTable( <U>, <d> )
##
## returns a list of length 2*s+r, where s is the number of positive
## roots, and r the rank. This function constructs the d-fold co-products
## of the generators of <U> (that is, for the F's, and the E's). The first
## s elements are the co-products of the F-elements, then there are r
## unbound entries, and then s co-products of the E-elements.
##
QGPrivateFunctions.DeltaTable:= function( QA, deg, gentab )
local T, tensorfam, R, B, g, fam, sim, posR, convR,
deltatab, one, rank, s, i, pp, k, k1, k2, pair,
rel, pos, cf, qa, tens, onet, t1, j;
T:= TensorPower( QA, deg );
# We store the table in the family of tensor elements:
tensorfam:= ElementsFamily( FamilyObj( T ) );
if IsBound( tensorfam!.deltaTable ) then
return tensorfam!.deltaTable;
fi;
R:= RootSystem( QA );
B:= BilinearFormMatNF( R );
g:= GeneratorsOfAlgebra( QA );
fam:= ElementsFamily( FamilyObj( QA ) );
sim:= SimpleSystemNF( R );
posR:= PositiveRootsNF( R );
convR:= fam!.convexRoots;
deltatab:= [ ];
one:= One( tensorfam!.zeroCoefficient );
rank:= Length( CartanMatrix(R) );
s:= Length( posR );
# first we do the F elements
for i in [1..s] do
pp:= Position( sim, posR[i] );
if pp <> fail then
# simple root; copy from gentab
deltatab[ Position( convR, posR[i] ) ]:= gentab[ pp ];
else
# find a `definition' for F_{\alpha}
# find a simple root r such that posR[i]-r is also a root
for k in [1..Length( sim ) ] do
k1:= Position( convR, posR[i] - sim[k] );
if k1 <> fail then
k2:= Position( convR, sim[k] );
if k1 > k2 then
pair:= [ k1, k2 ];
else
pair:= [ k2, k1 ];
fi;
rel:= List( fam!.multTab[pair[1]][pair[2]], ShallowCopy );
# see whether F_i is in there...
pos:= Position( rel, [ Position( convR, posR[i] ), 1 ] );
if pos <> fail then
break;
fi;
fi;
od;
# F_i is in `rel'; we get it out
cf:= rel[ pos+1];
Unbind( rel[pos] ); Unbind( rel[pos+1] );
rel:= Filtered( rel, x -> IsBound(x) );
for k in [2,4..Length(rel)] do
rel[k]:= -(1/cf)*rel[k];
od;
Add( rel, [ pair[1], 1, pair[2], 1 ] );
Add( rel, 1/cf );
qa:= _q^( -convR[k1]*( B*convR[k2] ) );
Add( rel, [ pair[2], 1, pair[1], 1 ] );
Add( rel, -qa/cf );
# Now apply delta to the elements of rel, and add...
tens:= Zero( T );
onet:= One( tens );
for k in [1,3..Length(rel)-1] do
t1:= onet;
for j in [1,3..Length(rel[k])-1] do
qa:= GaussianFactorial( rel[k][j+1],
_q^(convR[rel[k][j]]*( B*convR[rel[k][j]] )/2) );
t1:=(1/qa)*t1*( deltatab[rel[k][j]]^rel[k][j+1] );
od;
tens:= tens+rel[k+1]*t1;
od;
deltatab[ Position( convR, posR[i] ) ]:= tens;
fi;
od;
# Add K-elements from gentab:
Append( deltatab, gentab{[rank+1..3*rank]} );
# then we do the E elements
for i in [1..s] do
pp:= Position( sim, posR[i] );
if pp <> fail then
# simple root; copy from gentab
deltatab[s+2*rank+Position( convR, posR[i] )]:=
gentab[ 3*rank+pp ];
else
# find a `definition' for E_{\alpha}
# find a simple root r such that posR[i]-r is also a root
for k in [1..Length( sim ) ] do
k1:= Position( convR, posR[i] - sim[k] );
if k1 <> fail then
k2:= Position( convR, sim[k] );
if k1 > k2 then
pair:= [ s+rank+k1, s+rank+k2 ];
else
pair:= [ s+rank+k2, s+rank+k1 ];
fi;
rel:= List( fam!.multTab[pair[1]][pair[2]], ShallowCopy );
# See whether E_i is in rel:
pos:= Position( rel, [ Position( convR, posR[i] )+s+rank,
1 ] );
if pos <> fail then
break;
fi;
fi;
od;
# E_i is in `rel'; we get it out
cf:= rel[ pos+1];
Unbind( rel[pos] ); Unbind( rel[pos+1] );
rel:= Filtered( rel, x -> IsBound(x) );
for k in [2,4..Length(rel)] do
rel[k]:= -(1/cf)*rel[k];
od;
Add( rel, [ pair[1], 1, pair[2], 1 ] );
Add( rel, 1/cf );
qa:= _q^( -convR[k1]*( B*convR[k2] ) );
Add( rel, [ pair[2], 1, pair[1], 1 ] );
Add( rel, -qa/cf );
# Apply delta to rel...
tens:= Zero( T );
onet:= One( tens );
for k in [1,3..Length(rel)-1] do
t1:= onet;
for j in [1,3..Length(rel[k])-1] do
qa:= GaussianFactorial( rel[k][j+1],
_q^(convR[rel[k][j]-s-rank]*( B*convR[rel[k][j]-s-rank] )/2) );
t1:=(1/qa)*t1*( deltatab[rel[k][j]+rank]^rel[k][j+1] );
od;
tens:= tens+rel[k+1]*t1;
od;
deltatab[ s+2*rank+Position( convR, posR[i] ) ]:= tens;
fi;
od;
tensorfam!.deltaTable:= deltatab;
return deltatab;
end;
QGPrivateFunctions.make_generic_comulmap:= function( arg )
local U, d, twisting, f, finv, T, tfam, one, R, rank,
s, posR, g, gens, i, p, fgens, nice, x, tens, j,
ten, dt, map, images, noPosR, tendeg, imgs;
U:= arg[1];
d:= arg[2];
if Length( arg ) = 2 then
twisting:= false;
else
twisting:= true;
f:= arg[3];
finv:= arg[4];
fi;
T:= TensorPower( U, d );
tfam:= ElementsFamily( FamilyObj( T ) );
one:= One( tfam!.zeroCoefficient );
R:= RootSystem( U );
rank:= Length( CartanMatrix(R) );
s:= Length( PositiveRoots(R) );
posR:= PositiveRootsInConvexOrder( R );
g:= GeneratorsOfAlgebra( U );
gens:= [ ];
for i in [1..rank] do
p:= Position( posR, SimpleSystemNF( R )[i] );
gens[i]:= g[ p ];
gens[ rank+i ]:= g[ s + 2*i -1 ];
gens[ 2*rank + i ]:= g[ s+2*i ];
gens[ 3*rank + i ]:= g[ s+2*rank + p ];
od;
if twisting then
# we check whether f maps generators to generators;
# in that case we can make the table directly,
# otherwise we need to make a standard table first,
# and then map it with f.
fgens:= [ ];
nice:= true;
for i in gens do
x:= Image( f, i );
p:= Position( gens, x );
if p = fail then
nice:= false;
break;
else
if p <= rank then
# an F
tens:= [ ];
for j in [1..d] do
ten:= List( [1..j], x -> One(g[1]) );
Append( ten, List( [j+1..d], x -> g[s+2*p] ) );
ten[j]:= x;
Add( tens, ten ); Add( tens, one );
od;
elif p <= 2*rank then
# a K
p:= p-rank;
tens:= [ List([1..d], ii -> g[s+2*p-1] ),
QuantumParameter(U)^0 ];
elif p <= 3*rank then
# a K^-1
p:= p-2*rank;
tens:= [ List([1..d], ii -> g[s+2*p] ),
QuantumParameter(U)^0 ];
else
# an E
p:= p-3*rank;
tens:= [ ];
for j in [1..d] do
ten:= List( [1..j], x -> g[s+2*p-1] );
Append( ten, List( [j+1..d], x -> One(g[1]) ) );
ten[j]:= x;
Add( tens, ten ); Add( tens, one );
od;
fi;
Add( fgens, tens );
fi;
od;
if nice then
# apply f<x>f<x>...<x>f
for i in [1..Length(fgens)] do
for j in [1,3..Length(fgens[i])-1] do
fgens[i][j]:= List( fgens[i][j], uu -> Image( f, uu ) );
od;
fgens[i]:= ObjByExtRep( tfam, fgens[i] );
fgens[i]![2]:= false;
fgens[i]:= ConvertToNormalFormMonomialElement(fgens[i]);
od;
fi;
fi;
if not twisting or not nice then
# we make the `standard' table.
fgens:= [ ];
for p in [1..rank] do
tens:= [ ];
for j in [1..d] do
ten:= List( [1..j], x -> One(g[1]) );
Append( ten, List( [j+1..d], x -> g[s+2*p] ) );
ten[j]:= g[ Position( posR, SimpleSystemNF(R)[p] ) ];
Add( tens, ten ); Add( tens, one );
od;
Add( fgens, tens );
od;
for p in [1..rank] do
tens:= [ List([1..d], ii -> g[s+2*p-1] ),
QuantumParameter(U)^0 ];
Add( fgens, tens );
od;
for p in [1..rank] do
tens:= [ List([1..d], ii -> g[s+2*p] ),
QuantumParameter(U)^0 ];
Add( fgens, tens );
od;
for p in [1..rank] do
tens:= [ ];
for j in [1..d] do
ten:= List( [1..j], x -> g[s+2*p-1] );
Append( ten, List( [j+1..d], x -> One(g[1]) ) );
ten[j]:= g[ s+2*rank + Position( posR, SimpleSystemNF(R)[p] ) ];
Add( tens, ten ); Add( tens, one );
od;
Add( fgens, tens );
od;
for i in [1..Length(fgens)] do
fgens[i]:= ObjByExtRep( tfam, fgens[i] );
fgens[i]![2]:= false;
fgens[i]:= ConvertToNormalFormMonomialElement(fgens[i]);
od;
fi;
dt:= QGPrivateFunctions.DeltaTable( U, d, fgens );
map:= Objectify( TypeOfDefaultGeneralMapping( U, T,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsGenericCoMultMap
and IsAlgebraHomomorphism),
rec(
images := dt,
rank:= rank,
noPosR:= s,
tendeg:= d
) );
if twisting and not nice then
imgs:= [ ];
for i in [1..s] do
Add( imgs, Image( map, Image( finv, g[i] ) ) );
od;
for i in [1..rank] do
Add( imgs, Image( map, Image( finv, g[s+2*i-1] ) ) );
od;
for i in [1..rank] do
Add( imgs, Image( map, Image( finv, g[s+2*i] ) ) );
od;
for i in [1..s] do
Add( imgs, Image( map, Image( finv, g[s+2*rank+i] ) ) );
od;
for i in [1..Length(imgs)] do
# apply f<x>f...<x>f (d-factors).
x:= ShallowCopy( imgs[i]![1] );
ten:= [ ];
for j in [1,3..Length(x)-1] do
Add( ten, List( x[j], e -> Image( f, e ) ) );
Add( ten, x[j+1] );
od;
ten:= ObjByExtRep( tfam, ten );
ten![2]:= false;
imgs[i]:=ConvertToNormalFormMonomialElement(ten);
od;
map:= Objectify( TypeOfDefaultGeneralMapping( U, T,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsGenericCoMultMap
and IsAlgebraHomomorphism),
rec(
images := imgs,
rank:= rank,
noPosR:= s,
tendeg:= d
) );
fi;
return map;
end;
InstallOtherMethod( ComultiplicationMap,
"for a quea, and degree", true, [IsGenericQUEA,IsInt], 0,
function( U, d )
local fam, map;
fam:= FamilyObj( U );
if not IsBound( fam!.coMaps ) then fam!.coMaps:= [ ]; fi;
if IsBound( fam!.coMaps[d] ) then return fam!.coMaps[d]; fi;
if HasHopfStructureTwist( U ) then
map:= QGPrivateFunctions.make_generic_comulmap( U, d,
HopfStructureTwist( U )[1],
HopfStructureTwist( U )[2] );
else
map:= QGPrivateFunctions.make_generic_comulmap( U, d );
fi;
fam!.coMaps[d]:= map;
return map;
end );
InstallOtherMethod( ComultiplicationMap,
"for a quea, and degree", true, [IsQuantumUEA,IsInt], 0,
function( U, d )
local T, fam, U0, f, map;
if IsGenericQUEA( U ) then TryNextMethod(); fi;
fam:= FamilyObj( U );
if not IsBound( fam!.coMaps ) then fam!.coMaps:= [ ]; fi;
if IsBound( fam!.coMaps[d] ) then return fam!.coMaps[d]; fi;
U0:= QuantizedUEA( RootSystem(U) );
if HasHopfStructureTwist( U ) then
f:= QGPrivateFunctions.make_generic_comulmap( U0, d,
HopfStructureTwist( U )[1]!.origMap,
HopfStructureTwist( U )[2]!.origMap );
else
f:= QGPrivateFunctions.make_generic_comulmap( U0, d );
fi;
T:= TensorPower( U, d );
map:= Objectify( TypeOfDefaultGeneralMapping( U, T,
IsSPGeneralMapping
and IsAlgebraGeneralMapping
and IsInducedCoMultMap
and IsAlgebraHomomorphism),
rec(
origMap:= f,
canMap:= CanonicalMapping( U ),
tendeg:= d
) );
fam!.coMaps[d]:= map;
return map;
end );
InstallMethod( PrintObj,
"for a comultmap", true, [ IsCoMultMap ], 0,
function( map )
Print("<Comultiplication of ",Source(map),", degree ",map!.tendeg,">");
end );
# The code below is literally taken from isom.gi. It turned out to
# be rather tricky to change the code for automorphisms, so as to allow
# more general homomorphisms, such as \Delta : U ---> U<x>...<x>U.
# This was basically caused by the fact that elements of U have a
# special format, which is used heavily throughout the programs.
# Therefore we redo it for this special case (comult).
InstallMethod( ImageElm,
"for comult map, and elm",
true, [ IsGenericCoMultMap, IsQEAElement ], 0,
function( map, x )
local rew_K, ex, U, B, R, posR, sim, noposR, rank, i, j, im, u, qp, T;
rew_K:= function( a, b, delta, s, qpar )
local res, i;
res:= a^delta;
for i in [1..s] do
res:= res*( qpar^(-i+1)*a-qpar^(i-1)*b )/( qpar^i-qpar^-i );
od;
return res;
end;
ex:= ExtRepOfObj( x );
U:= Source( map );
T:= Range( map );
R:= RootSystem( U );
B:= BilinearFormMatNF( R );
posR:= PositiveRootsInConvexOrder( R );
sim:= SimpleSystemNF( R );
noposR:= map!.noPosR;
rank:= map!.rank;
im:= Zero( T );
for i in [1,3..Length(ex)-1] do
u:= ex[i+1]*One( T );
for j in [1,3..Length(ex[i])-1] do
if IsList( ex[i][j] ) then
#it is a K...; more difficult.
qp:= _q^( sim[ ex[i][j][1]-noposR ]*( B*sim[ ex[i][j][1]-noposR ] )/2);
u:= u*rew_K( map!.images[ ex[i][j][1] ],
map!.images[ ex[i][j][1]+map!.rank ], ex[i][j][2],
ex[i][j+1], qp );
elif ex[i][j] <= map!.noPosR then
#it is an F...
qp:= _q^( posR[ ex[i][j] ]*( B*posR[ ex[i][j] ] )/2 );
u:= u*( map!.images[ ex[i][j] ]^ex[i][j+1] )/
GaussianFactorial( ex[i][j+1], qp );
else
#it is an E...
qp:= _q^( posR[ ex[i][j]-noposR-rank ]*(
B*posR[ ex[i][j]-noposR-rank ] )/2 );
u:= u*( map!.images[ ex[i][j]+rank ]^ex[i][j+1] )/
GaussianFactorial( ex[i][j+1], qp );
fi;
od;
im:= im+u;
od;
return im;
end );
InstallMethod( ImageElm,
"for induced comult map, and elm",
true, [ IsInducedCoMultMap, IsQEAElement ], 0,
function( map, x )
local U, T, qp, U0, f0, im, ex, canmap, i, j, y, tn;
U:= Source( map );
T:= Range( map );
qp:= QuantumParameter( U );
U0:= QuantizedUEA( RootSystem( U ) );
f0:= map!.origMap;
im:= Zero( T );
ex:= ExtRepOfObj( x );
canmap:= map!.canMap;
for i in [1,3..Length(ex)-1] do
y:= ObjByExtRep( ElementsFamily(FamilyObj(U0)), [ ShallowCopy(ex[i]),
QuantumParameter(U0)^0 ] );
tn:= ShallowCopy( ExtRepOfObj( Image( f0, y ) ) );
for j in [2,4..Length(tn)] do
tn[j]:= Value( tn[j], qp )*ex[i+1];
if IsZero( tn[j] ) then
Unbind( tn[j] ); Unbind(tn[j-1]);
else
tn[j-1]:= List( tn[j-1], x -> Image( canmap, x ) );
fi;
od;
tn:= Filtered( tn, x -> IsBound(x) );
im:= im + ObjByExtRep( ElementsFamily(FamilyObj(T)), tn );
od;
return im;
end );
##############################################################################
##
#M TensorProductOfAlgebraModules( <list> )
##
## constructs the tensor product of left modules over quantized uea.
##
InstallMethod( TensorProductOfAlgebraModules,
"for a list of quantum algebra modules",
true, [ IsDenseList ], 100,
function( list )
#+
#+ constructs the tensor product of left modules over quantized uea.
#+ <list> must be a list of left modules over the same quantized
#+ enveloping algebra. `TensorProductOfAlgebraModules( <V>, <W> )'
#+ is short for `TensorProductOfAlgebraModules( [ <V>, <W> ] )'.
local left_quantum_action_generic, A, VT, dtab, delta, s, rank,
g, i, Tprod, wlist, wts, vecs, ei, wt, j, pos,
left_quantum_action_induced;
# The following is a function that takes an element from the qea, and an
# element from the tensor product. It returns the result of letting
# x act on tn.
left_quantum_action_generic:= function( x, tn )
# When everyting is defined over Q(q). `x' is the algebra elt, tn is an element
# of the tensor product of modules.
local R, noPosR, rank, B, deg, delta, res, ex, etn, i,
vec, len, j, rule, k, vec1, u, v, ind, cf, ka,
tv, pos, d;
if tn = 0*tn then
return tn;
fi;
R:= FamilyObj(x)!.rootSystem;
noPosR:= Length( PositiveRoots(R) );
rank:= Length( CartanMatrix(R) );
B:= BilinearFormMatNF( R );
deg:= FamilyObj( tn )!.degree;
delta:= FamilyObj( tn )!.deltaTab;
d:= FamilyObj( tn )!.deltaMap;
res:= [ ]; # result
ex:= ExtRepOfObj( x );
etn:= ExtRepOfObj( tn );
for i in [1,3..Length(ex)-1] do
# apply ex[i] to etn
vec:= List( etn, ShallowCopy );
len:= Length( ex[i] );
for j in [len-1,len-3..1] do
if not IsList( ex[i][j] ) then
# It is an E or an F...
rule:= delta[ ex[i][j] ];
for k in [1..ex[i][j+1]] do
# we apply rule to all tensors in vec, and collect
# everything in vec1
vec1:= [ ];
for u in [1,3..Length(vec)-1] do
for v in [1,3..Length(rule)-1] do
Add(vec1,
List( [1..Length(vec[u])], x -> rule[v][x]^vec[u][x]) );
Add( vec1, vec[u+1]*rule[v+1] );
od;
od;
vec:= vec1;
od;
# take into account that F_1^(k) = F_i^k/[k]!
if ex[i][j] <= noPosR then
ind:= LongestWeylWord(R)[ ex[i][j] ];
else
ind:= LongestWeylWord(R)[ ex[i][j]-noPosR-rank ];
fi;
cf:= GaussianFactorial( ex[i][j+1], _q^(B[ind][ind]/2) );
for k in [2,4..Length(vec)] do
vec[k]:= vec[k]/cf;
od;
else
# it is a `K'; we take the image under d... (I know nothing better).
ka:= ObjByExtRep( FamilyObj(x), [
[ ex[i][j], ex[i][j+1] ], ex[i+1]^0] );
rule:= ExtRepOfObj( Image( d, ka ) );
# we apply rule to all tensors in vec, and collect
# everything in vec1
vec1:= [ ];
for u in [1,3..Length(vec)-1] do
for v in [1,3..Length(rule)-1] do
Add(vec1,
List( [1..Length(vec[u])], x -> rule[v][x]^vec[u][x]) );
Add( vec1, vec[u+1]*rule[v+1] );
od;
od;
vec:= vec1;
fi;
# intermediate normalization...
tv:= ObjByExtRep( FamilyObj(tn), vec );
tv![2]:= false;
tv:= ConvertToNormalFormMonomialElement(tv);
vec:= ShallowCopy( tv![1] );
od;
vec:= ShallowCopy( vec );
for k in [2,4..Length(vec)] do
vec[k]:= ex[i+1]*vec[k];
od;
# add vec to `res'
for k in [1,3..Length(vec)-1] do
pos:= Position( res, vec[k] );
if pos = fail then
Add( res, vec[k] ); Add( res, vec[k+1] );
else
res[pos+1]:= res[pos+1]+vec[k+1];
if res[pos+1] = 0*res[pos+1] then
Unbind( res[pos] ); Unbind( res[pos+1] );
res:= Filtered( res, x -> IsBound(x) );
fi;
fi;
od;
od;
tv:= ObjByExtRep( FamilyObj(tn), res );
tv![2]:= false;
tv:= ConvertToNormalFormMonomialElement(tv);
return tv;
end;
left_quantum_action_induced:= function( x, tn )
# When the quantum parameter is not `q'. `x' is the algebra elt, tn is an element
# of the tensor product of modules.
local res, ex, etn, i,
vec, len, j, rule, k, vec1, u, v, ind, cf,
tv, pos, d;
if tn = 0*tn then
return tn;
fi;
d:= FamilyObj( tn )!.deltaMap;
res:= [ ]; # result
ex:= ExtRepOfObj( x );
etn:= ExtRepOfObj( tn );
for i in [1,3..Length(ex)-1] do
# apply ex[i] to etn
vec:= List( etn, ShallowCopy );
len:= Length( ex[i] );
for j in [len-1,len-3..1] do
rule:= ExtRepOfObj( Image( d, ObjByExtRep( FamilyObj(x),
[ [ ex[i][j], ex[i][j+1] ], ex[i+1]^0] ) ) );
# we apply rule to all tensors in vec, and collect
# everything in vec1
vec1:= [ ];
for u in [1,3..Length(vec)-1] do
for v in [1,3..Length(rule)-1] do
Add(vec1,
List( [1..Length(vec[u])], x -> rule[v][x]^vec[u][x]) );
Add( vec1, vec[u+1]*rule[v+1] );
od;
od;
vec:= vec1;
# intermediate normalization...
tv:= ObjByExtRep( FamilyObj(tn), vec );
tv![2]:= false;
tv:= ConvertToNormalFormMonomialElement(tv);
vec:= ShallowCopy( tv![1] );
od;
vec:= ShallowCopy( vec );
for k in [2,4..Length(vec)] do
vec[k]:= ex[i+1]*vec[k];
od;
# add vec to `res'
for k in [1,3..Length(vec)-1] do
pos:= Position( res, vec[k] );
if pos = fail then
Add( res, vec[k] ); Add( res, vec[k+1] );
else
res[pos+1]:= res[pos+1]+vec[k+1];
if res[pos+1] = 0*res[pos+1] then
Unbind( res[pos] ); Unbind( res[pos+1] );
res:= Filtered( res, x -> IsBound(x) );
fi;
fi;
od;
od;
tv:= ObjByExtRep( FamilyObj(tn), res );
tv![2]:= false;
tv:= ConvertToNormalFormMonomialElement(tv);
return tv;
end;
# Now we make the tensor module.
if not HasLeftActingAlgebra( list[1] ) then
TryNextMethod();
fi;
A:= LeftActingAlgebra( list[1] );
if not ForAll( [2..Length(list)], x -> LeftActingAlgebra(list[x])=A) then
Error( "All modules must have the same acting algebra");
fi;
if not IsQuantumUEA(A) then
TryNextMethod();
fi;
VT:= TensorProduct( list );
ElementsFamily( FamilyObj(VT) )!.degree:= Length(list);
dtab:= ComultiplicationMap( A, Length(list) );
ElementsFamily( FamilyObj( VT ) )!.deltaMap:= dtab;
if IsGenericCoMultMap( dtab ) then
delta:= [ ];
s:= dtab!.noPosR;
rank:= dtab!.rank;
g:= GeneratorsOfAlgebra( A );
for i in [1..s] do
delta[i]:= ExtRepOfObj( Image( dtab, g[i] ) );
delta[s+rank+i]:= ExtRepOfObj( Image( dtab, g[s+2*rank+i] ) );
od;
ElementsFamily( FamilyObj( VT ) )!.deltaTab:= delta;
Tprod:= LeftAlgebraModule( A, left_quantum_action_generic, VT );
else
Tprod:= LeftAlgebraModule( A, left_quantum_action_induced, VT );
fi;
# Set the attribute `WeightsAndVectors', if each element
# in the list has this attribute set.
if ForAll( list, HasWeightsAndVectors ) then
rank:= Length( CartanMatrix( RootSystem(
LeftActingAlgebra(list[1]) ) ) );
wlist:= List( list, x -> WeightsAndVectors(x) );
wts:= [ ];
vecs:= [ ];
for i in Basis(Tprod) do
ei:= ExtRepOfObj( ExtRepOfObj( i ) )[1];
wt:= [1..rank]*0;
for j in [1..Length(ei)] do
pos:= PositionProperty( wlist[j][2], x -> ei[j] in x );
wt:= wt + wlist[j][1][pos];
od;
pos:= Position( wts, wt );
if pos = fail then
Add( wts, wt );
Add( vecs, [ i ] );
else
Add( vecs[pos], i );
fi;
od;
SetWeightsAndVectors( Tprod, [ wts, vecs ] );
fi;
return Tprod;
end );
InstallMethod( UseTwistedHopfStructure,
"for a quea, and an (anti-)automorphism", true,
[ IsQuantumUEA, IsAlgebraHomomorphism, IsAlgebraHomomorphism ], 0,
function( U, f, finv )
if (not IsQUEAAutomorphism( f )) and (not IsQUEAAntiAutomorphism( f )) then
Error("<f> must be an (anti-)automorphism");
fi;
if not IsIdenticalObj( U, Source(f) ) then
Error("<f> is a homomorphism of the wrong algebra");
fi;
SetHopfStructureTwist( U, [ f, finv ] );
end );
InstallMethod( AntipodeMap,
"for a qea", true, [ IsQuantumUEA ], 0,
function( U )
local U0, g, R, sim, posR, s, rank, imgs, i, pos, S, antiaut;
# Here we use the anti-automorphism S defined by
# S(E) = -K^-1E, S(F) = -FK, S(K) = K^-1. Its inverse is given by
# S^-1(E) = -EK^-1, S^-1(F) = -KF, S^-1(K) = K^-1.
#
# If the Hopf structure is non-twisted the antipode is S.
# Otherwise, if it is twisted by an automorphism f, the antipode is
# f*S*f^-1, and if it is twisted by an antiautomorphism f, then
# the antipode is f*S^-1*f^-1.
# We first construct the antipode of the corresponding generic
# quea:
if IsGenericQUEA( U ) then
U0:= U;
else
U0:= QuantizedUEA( RootSystem( U ) );
fi;
if HasHopfStructureTwist( U ) then
if IsQUEAAutomorphism( HopfStructureTwist( U )[1] ) then
antiaut:= false;
else
antiaut:= true;
fi;
else
antiaut:= false;
fi;
g:= GeneratorsOfAlgebra( U0 );
R:= RootSystem( U0 );
sim:= SimpleSystemNF( R );
posR:= PositiveRootsInConvexOrder( R );
s:= Length( posR );
rank:= Length( sim );
imgs:= [ ];
if not antiaut then
# We construct S:
for i in [1..rank] do
pos:= Position( posR, sim[i] );
imgs[i]:= -g[pos]*g[s+2*i-1];
imgs[3*rank+i]:= -g[s+2*i]*g[s+2*rank+pos];
imgs[rank+i]:= g[s+2*i];
imgs[2*rank+i]:= g[s+2*i-1];
od;
S:= QEAAntiAutomorphism( U0, imgs );
if not IsGenericQUEA( U ) then
S:= QEAAntiAutomorphism( U, S );
fi;
else
# We construct S^-1 (which we also call S):
for i in [1..rank] do
pos:= Position( posR, sim[i] );
imgs[i]:= -g[s+2*i-1]*g[pos];
imgs[3*rank+i]:= -g[s+2*rank+pos]*g[s+2*i];
imgs[rank+i]:= g[s+2*i];
imgs[2*rank+i]:= g[s+2*i-1];
od;
S:= QEAAntiAutomorphism( U0, imgs );
if not IsGenericQUEA( U ) then
S:= QEAAntiAutomorphism( U, S );
fi;
fi;
if HasHopfStructureTwist( U ) then
return HopfStructureTwist( U )[1]*S*HopfStructureTwist( U )[2];
else
return S;
fi;
end );
InstallMethod( CounitMap,
"for a qea", true, [ IsQuantumUEA ], 0,
function( U )
local F, e;
F:= LeftActingDomain( U );
e:= function( u )
local eu, res, i, a, j;
eu:= ExtRepOfObj( u );
res:= Zero(F);
for i in [1,3..Length(eu)-1] do
if IsList( eu[i][1] ) and IsList( eu[i][ Length(eu[i])-1 ] ) then
# begins and ends with K; possibly nonzero image.
a:= One( F );
for j in [1,3..Length(eu[i])-1] do
if eu[i][j+1] > 0 then
a:= 0*a;
break;
fi;
od;
res:= eu[i+1]*a+res;
fi;
od;
return res;
end;
if HasHopfStructureTwist( U ) then
return function( u ) return e(
Image( HopfStructureTwist( U )[2], u ) );
end;
else
return e;
fi;
end );
# linear functionals know two things: a list of vecs, cfs giving the
# function as a lin comb of indicator functions, and a basis, stuck in
# the family; all evcs appearing in the list *must* be basis vecs.
InstallMethod( ObjByExtRep,
"make a dual element", true,
[ IsDualElementFamily, IsList ], 0,
function( fam, list )
local m;
m:= Objectify( fam!.packedType, rec( val:=Immutable(list) ) );
SetSource( m, fam!.source );
SetRange( m, fam!.range );
return m;
end );
InstallMethod( ExtRepOfObj,
"for a dual element", true,
[ IsDualElement ], 0,
function( d )
return d!.val;
end );
InstallMethod( PrintObj,
"for dual elements", true, [ IsDualElement ], 0,
function( df )
local ed, i;
ed:= ExtRepOfObj( df );
if ed = [ ] then Print( "<zero function>" ); fi;
for i in [1,3..Length(ed)-1] do
if i > 1 then Print(" + "); fi;
Print("(",ed[i],")*F@",ed[i+1]);
od;
end );
#############################################################################
##
## Spaces of elements of a dual space are handled by nice bases;
## we use sparse vectors for that.
##
InstallHandlingByNiceBasis( "IsDualElementsSpace", rec(
detect:= function( R, gens, V, zero )
return IsDualElementCollection( V );
end,
NiceFreeLeftModuleInfo := ReturnFalse,
NiceVector := function( V, v )
local ev, nums, cfs, B, i, vec;
ev:= ExtRepOfObj( v );
nums:= [ ]; cfs:= [ ];
B:= FamilyObj( v )!.basisV;
for i in [1,3..Length(ev)-1] do
Add( nums, Position( B, ev[i+1] ) );
Add( cfs, ev[i] );
od;
SortParallel( nums, cfs );
vec:= [ ];
for i in [1..Length(nums)] do
Add( vec, nums[i] ); Add( vec, cfs[i] );
od;
return ObjByExtRep( FamilyObj( v )!.niceVectorFam, vec );
end,
UglyVector := function( V, vec )
local ev, vv, cfs, B, i, m;
# We do the inverse of `NiceVector'.
ev:= ShallowCopy( vec![1] );
vv:= [ ]; cfs:= [ ];
B:= ElementsFamily( FamilyObj( V ) )!.basisV;
for i in [1,3..Length(ev)-1] do
Add( cfs, ev[i+1] );
Add( vv, B[ ev[i] ] );
od;
SortParallel( vv, cfs );
m:= [ ];
for i in [1..Length(vv)] do
Add( m, cfs[i] );
Add( m, vv[i] );
od;
return ObjByExtRep( ElementsFamily( FamilyObj( V ) ), m );
end ) );
InstallMethod( DualSpace,
"for a vector space", true, [ IsLeftModule ], 0,
function( V )
local fam, type, niceVF, B, vecs, one, v;
fam:= NewFamily( "DualEltsFam", IsDualElement );
type:= NewType( fam, IsAttributeStoringRep );
fam!.packedType:= type;
fam!.source:= V;
fam!.range:= LeftActingDomain( V );
SetFamilySource( fam, ElementsFamily( FamilyObj( V ) ) );
niceVF:= NewFamily( "NiceVectorFam", IsSparseRowSpaceElement );
niceVF!.zeroCoefficient:= Zero( LeftActingDomain(V) );
niceVF!.sparseRowSpaceElementDefaultType:=
NewType( niceVF, IsPackedElementDefaultRep );
fam!.niceVectorFam:= niceVF;
B:= Basis( V );
fam!.basisV:= B;
vecs:= [ ];
one:= One( LeftActingDomain( V ) );
for v in B do
Add( vecs, ObjByExtRep( fam, [ one, v ] ) );
od;
fam!.basisVdual:= vecs;
return VectorSpace( LeftActingDomain(V), vecs, "basis" );
end );
InstallMethod( \+,
"for two dual elements", IsIdenticalObj,
[ IsDualElement, IsDualElement ], 0,
function( d1, d2 )
local e1, e2, m1, c1, m2, c2, i, pos, e;
e1:= ExtRepOfObj( d1 );
# Catch trivial case:
if e1=[] then return d2; fi;
e2:= ExtRepOfObj( d2 );
m1:= e1{[2,4..Length(e1)]};
c1:= e1{[1,3..Length(e1)-1]};
m2:= e2{[2,4..Length(e2)]};
c2:= e2{[1,3..Length(e2)-1]};
for i in [1..Length( m2 )] do
pos:= PositionSorted( m1, m2[i] );
if pos > Length( m1 ) then
Add( m1, m2[i] );
Add( c1, c2[i] );
else
if m1[pos] = m2[i] then
c1[pos]:= c1[pos]+c2[i];
if c1[pos] = 0*c1[pos] then
Unbind( c1[pos] );
Unbind( m1[pos] );
m1:= Filtered( m1, x -> IsBound(x) );
c1:= Filtered( c1, x -> IsBound(x) );
fi;
else
InsertElmList( m1, pos, m2[i] );
InsertElmList( c1, pos, c2[i] );
fi;
fi;
od;
e:= [ ];
for i in [1..Length(m1)] do
Add( e, c1[i] );
Add( e, m1[i] );
od;
return ObjByExtRep( FamilyObj( d1 ), e );
end );
InstallMethod( \*,
"for a scalar and a dual elt", true,
[ IsScalar, IsDualElement ], 0,
function( a, d )
local ed, i;
if IsZero( a ) then return Zero( d ); fi;
ed:= ShallowCopy( ExtRepOfObj( d ) );
for i in [1,3..Length(ed)-1] do
ed[i]:= a*ed[i];
od;
return ObjByExtRep( FamilyObj( d ), ed );
end );
InstallMethod( \*,
"for a dual elt and a scalar", true,
[ IsDualElement, IsScalar ], 0,
function( d, a )
local ed, i;
if IsZero( a ) then return Zero( d ); fi;
ed:= ShallowCopy( ExtRepOfObj( d ) );
for i in [1,3..Length(ed)-1] do
ed[i]:= ed[i]*a;
od;
return ObjByExtRep( FamilyObj( d ), ed );
end );
InstallMethod( AdditiveInverseSameMutability,
"for a dual element", true,
[ IsDualElement ], 0,
function( d )
local ed, i;
ed:= ShallowCopy( ExtRepOfObj( d ) );
for i in [1,3..Length(ed)-1] do
ed[i]:= -ed[i];
od;
return ObjByExtRep( FamilyObj( d ), ed );
end );
InstallMethod( AdditiveInverseMutable,
"for a dual element", true,
[ IsDualElement ], 0,
function( d )
local ed, i;
ed:= ShallowCopy( ExtRepOfObj( d ) );
for i in [1,3..Length(ed)-1] do
ed[i]:= -ed[i];
od;
return ObjByExtRep( FamilyObj( d ), ed );
end );
InstallMethod( ZeroOp,
"for a dual element", true,
[ IsDualElement ], 0,
function( d )
return ObjByExtRep( FamilyObj( d ), [] );
end );
InstallMethod( IsZero,
"for a dual element", true,
[ IsDualElement ], 0,
function( d )
return d = Zero(d);
end );
InstallMethod( \<,
"for dual elements", true,
[ IsDualElement, IsDualElement ], 0,
function( d1, d2 )
return ExtRepOfObj(d1) < ExtRepOfObj(d2);
end );
InstallMethod( \=,
"for dual elements", true,
[ IsDualElement, IsDualElement ], 0,
function( d1, d2 )
return ExtRepOfObj(d1) = ExtRepOfObj(d2);
end );
InstallMethod( ImageElm,
"for dual element and element from the underlying space",
true, [ IsDualElement, IsObject ], 0,
function( d, x )
local B, cf, res, ed, i, pos;
B:= FamilyObj(d)!.basisV;
cf:= Coefficients( B, x );
if cf = fail then return fail; fi;
res:= Zero( cf[1] );
ed:= ExtRepOfObj( d );
for i in [1,3..Length(ed)-1] do
pos:= Position( B, ed[i+1] );
res:= res+ed[i]*cf[pos];
od;
return res;
end );
InstallMethod( DualAlgebraModule,
"for a left module over a quantized uea", true,
[ IsAlgebraModule and IsLeftAlgebraModuleElementCollection ], 0,
function( M )
local U, Mstr, apode, action, gens, R, posR, s, sim,
rank, g, i, ff, vv, imgs, k, u, imu, im, j, cf;
U:= LeftActingAlgebra( M );
if not IsQuantumUEA( U ) then TryNextMethod(); fi;
Mstr:= DualSpace( M );
apode:= AntipodeMap( U );
if not IsGenericQUEA( U ) then
# We cannot use DIYModule, so we just construct the dual module
# with the action given by apode...
action:= function( u, f )
local x, cfs;
x:= Image( apode, u );
cfs:= List( FamilyObj( f )!.basisV, v -> Image( f, x^v ) );
return cfs*FamilyObj( f )!.basisVdual;
end;
return LeftAlgebraModule( U, action, Mstr );
fi;
# Otherwise (in the generic case) we construct the action of the
# generators, and then construct the module by DIYModule; this gives
# a module where the action can be calculated much faster.
gens:= GeneratorsOfAlgebra( U );
R:= RootSystem( U );
posR:= PositiveRootsInConvexOrder( R );
s:= Length( posR );
sim:= SimpleSystemNF( R );
rank:= Length( sim );
g:= [ ];
for i in [1..rank] do
g[i]:= gens[ Position( posR, sim[i] ) ];
g[rank+i]:= gens[ s+2*i-1 ];
g[2*rank+i]:= gens[ s+2*i ];
g[3*rank+i]:= gens[ s+2*rank+Position( posR, sim[i] ) ];
od;
ff:= BasisVectors( Basis( Mstr ) );
vv:= List( ff, x -> ExtRepOfObj(x)[2] ); # i.e., corresponding basis vecs
# of M.
imgs:= [ ];
for k in [1..Length(g)] do
u:= Image( apode, g[k] );
imu:= List( vv, v -> u^v );
im:= [ ];
for j in [1..Length(ff)] do
# calculate the image g[k]^ff[j]
cf:= List( [1..Length(vv)], i -> # j-th cft of imu[i]
Image( ff[j], imu[i] ) );
Add( im, cf*ff );
od;
Add( imgs, im );
od;
return DIYModule( U, Mstr, imgs );
end );
InstallMethod( TrivialAlgebraModule,
"for a quantized uea", true, [ IsQuantumUEA ], 0,
function( U )
local F, V;
F:= LeftActingDomain(U);
V:= F^1;
return LeftAlgebraModule( U, function( u, v )
return CounitMap(U)( u )*v; end, V );
end );
[ zur Elbe Produktseite wechseln0.48Quellennavigators
Analyse erneut starten
]
|