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


Quelle  unipot.gi   Sprache: unbekannt

 
################################################################################
##
#W  unipot.gi                   Unipot package                     Sergei Haller
##
#Y  Copyright (C) 2000-2004, Sergei Haller
#Y  Arbeitsgruppe Algebra, Justus-Liebig-Universitaet Giessen
##
##  This is the implementation part of the package
##


################################################################################
##
#R  IsUnipotChevRepByRootNumbers
#R  IsUnipotChevRepByFundamentalCoeffs
#R  IsUnipotChevRepByRoots
##
##  Different representations for elements of unipotent subgroups.  
##
##  Roots of elements with representation `IsUnipotChevRepByRootNumbers' are
##  represented by their numbers (positions) in `RootSystem(<U>).posroots'.
##
##  Roots of elements with representation `IsUnipotChevRepByFundamentalCoeffs'
##  are represented by coefficients of linear combinations of fundamental roots
##  `RootSystem(<U>).fundroots'.
##
##  Roots of elements with representation `IsUnipotChevRepByRoots' are
##  represented by roots themself.
##

DeclareRepresentation( "IsUnipotChevRepByRootNumbers",
                         IsAttributeStoringRep,
                         [ "roots", "felems"  ] );
DeclareRepresentation( "IsUnipotChevRepByFundamentalCoeffs",
                         IsAttributeStoringRep,
                         [ "roots", "felems"  ] );
DeclareRepresentation( "IsUnipotChevRepByRoots",
                         IsAttributeStoringRep,
                         [ "roots", "felems"  ] );


UNIPOT_DEFAULT_REP := IsUnipotChevRepByRootNumbers;

################################################################################
##
#F  UnipotChevFamily( <type>, <n>, <F> )
##
##  This function creates a UnipotChevFamily of type <type> and of rank <n>
##  over the ring <F>.
##
##  <type> must be one of "A", "B", "C", "D", "E", "F", "G"
##  For the type  "A", <n> must be a positive integer.
##  For the types "B" and "C", <n> must be a positive integer >= 2.
##  For the type  "D", <n> must be a positive integer >= 4.
##  For the type  "E", <n> must be one of 6, 7, 8.
##  For the type  "F", <n> must be 4.
##  For the type  "G", <n> must be 2.
##

InstallGlobalFunction(  UnipotChevFamily,
function( type, n, F )

     local Fam,     # The new Family
           L,       # The SimpleLieAlgebra of the given Type
           R,       # The RootSystem of L
           V,       # Vectorspace used to compute the posrootsFC
           B,       # The Basis of L resp. V
           T,       # StructureConstantsTable(B), taken from Lie Algebra
           N,       # StructureConstantsTable as we need it.
           H,h,     # ``half-the-Cartan-matrix''
           r,s;     # two roots used in for-loops

     # check the Arguments ...
     if not ( type in ["A", "B", "C", "D", "E", "F", "G"] ) then
          Error( "<type> must be one of ",
                 "\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\" " );
     fi;


     if   ( type = "A" )         and not IsPosInt( n )                then
          Error( "<n> must be a positive integer for type A " );
     elif ( type in ["B", "C"] ) and not (IsPosInt( n ) and n >= 2 )  then
          Error( "<n> must be a positive integer for type ", type, " " );
     elif ( type = "D" )         and not (IsPosInt( n ) and n >= 4 )  then
          Error( "<n> must be a positive integer for type D " );
     elif ( type = "E" )         and not ( n in [6 ..8] )             then
          Error( "<n> must be one of 6, 7, 8 for type E " );
     elif ( type = "F" )         and not ( n = 4 )                    then
          Error( "<n> must be 4 for type F " );
     elif ( type = "G" )         and not ( n = 2 )                    then
          Error( "<n> must be 2 for type G " );
     fi;

     if not ( IsRing( F ) ) then
          Error( "<F> must be a ring." );
     fi;

     # Construct the family of our unipotent element objects.
     Fam:= NewFamily( Concatenation("UnipotChevFam", type, String( n )),
                      IsUnipotChevElem,
                      IsObject,
                      IsUnipotChevFamily );

##
#N  In the following two cases the roots are the same, but we need rational 
#N  structure constants.
#    L := SimpleLieAlgebra( type, n, F );          
     L := SimpleLieAlgebra( type, n, Rationals );  
     R := RootSystem( L );

     # Install the data.
     Fam!.type        := type;
     Fam!.rank        := n;
     Fam!.ring        := F;
     Fam!.rootsystem  := R;
     

     # Compute the structure constants ...
     N := NullMat( Length( PositiveRoots(R) ),
                   Length( PositiveRoots(R) ) );
     
     if   Fam!.type in ["B", "C", "F", "G"] then
#          B := Basis( L, Concatenation( R.rootvecs,
#                                  BasisVectors(Basis(CartanSubalgebra(L)))
#                                ));

          # NC = no check, ChevalleyBasis is a basis!
          # B := BasisNC( L, Flat(ChevalleyBasis( L )) );
          # CanonicalBasis is the Chevalley basis! and the structure
          # constants are already stored for CanonicalBasis.
          B := CanonicalBasis( L );

          T := StructureConstantsTable( B );
          # We only need a part of T,
          # example:  N_{r,s} = T[r][s][2][1]

          for r in [1..Length( PositiveRoots(R) )] do
               for s in [1..Length( PositiveRoots(R) )] do
                    if r < s and 
                       Position( PositiveRoots(R), 
                                 Sum( PositiveRoots(R){[r,s]} )
                               ) <> fail then
                         N[r][s] := T[r][s][2][1];
                         N[s][r] := T[s][r][2][1]; # = - N[r][s]
                    fi;
               od;
          od;
     else # Simple laced types
          H := function( M )
               local h, i, j, l;
               l := Length(M);
               h := IdentityMat(l);
               for i in [1..l-1] do
                    for j in [i+1..l] do
                         h[i][j] := M[i][j];
                    od;
               od;
               return h; # Immutable(h);
          end;
          h := H( CartanMatrix(R) );
          
          for r in [1..Length( PositiveRoots(R) )] do
               for s in [1..Length( PositiveRoots(R) )] do
                    if r < s and 
                       Position( PositiveRoots(R), 
                                 Sum( PositiveRoots(R){[r,s]} )
                               ) <> fail then
                         N[r][s] := (-1)^(  PositiveRootsFC(R)[r]
                                          * h 
                                          * PositiveRootsFC(R)[s] );
                         N[s][r] := - N[r][s];
                    fi;
               od;
          od;
     fi;

     Fam!.structconst := N; # war frueher T

     return  Fam;
end
);


################################################################################
##
#M  PrintObj( <Fam> )  . . . . . . . . . . . . . . . prints a `UnipotChevFamily'
##
##  Special Method for `UnipotChevFamily'
##

InstallMethod( PrintObj,
     "for a UnipotChevFamily",
     [ IsUnipotChevFamily ],
     function( Fam )
          Print( "UnipotChevFamily( \"",
                 Fam!.type, "\", ",
                 Fam!.rank, ", ",
                 Fam!.ring, " )"
               );
     end
);

################################################################################
##
#M  <Fam1> = <Fam2>  . . . . . . . . . . . . equality for two `UnipotChevFamily'
##
##  Returns `true' if both Familys have the same type and equal underlying
##  rings.
##
##  Are using this in Equality for UnipotChevSubGr
##

InstallMethod( \=,
     "for two UnipotChevFamily",
     IsIdenticalObj,
     [ IsUnipotChevFamily,
       IsUnipotChevFamily ],
     function( Fam1, Fam2 )
          return IsIdenticalObj( Fam1, Fam2 )
                 or (     ( Fam1!.type = Fam2!.type )
                      and ( Fam1!.rank = Fam2!.rank )
                      and ( Fam1!.ring = Fam2!.ring )
                    );
     end
);

################################################################################
##
#M  OneOp( <Fam> ) . . . . . . . . . . . the one-element of a `UnipotChevFamily'
##
##  Returns the identity in the family
##

InstallOtherMethod( OneOp,
     "for a UnipotChevFamily",
     [ IsUnipotChevFamily ],
     Fam -> UnipotChevElem( Fam, rec(roots:=[], felems:=[]),
                            UNIPOT_DEFAULT_REP )
);









################################################################################
##
#F  UnipotChevSubGr( <type>, <n>, <F> )
##
##  `UnipotChevSubGr' returns the unipotent subgroup $U$ of the Chevalley group
##  of type <type>, rank <n> over the ring <F>.
##
##  <type> must be one of "A", "B", "C", "D", "E", "F", "G"
##  For the type  "A", <n> must be a positive integer.
##  For the types "B" and "C", <n> must be a positive integer >= 2.
##  For the type  "D", <n> must be a positive integer >= 4.
##  For the type  "E", <n> must be one of 6, 7, 8.
##  For the type  "F", <n> must be 4.
##  For the type  "G", <n> must be 2.
##

InstallGlobalFunction(  UnipotChevSubGr,
function( type, n, F )
     local gr, Fam;

     Fam := UnipotChevFamily( type, n, F );
     
     gr := Objectify( NewType( CollectionsFamily( Fam ),
                               IsUnipotChevSubGr and IsAttributeStoringRep
                             ),
                      rec()
                    );

     SetIsWholeFamily( gr, true );

##
#N  see Theorem 5.3.3(i) in [Car72]
##
     SetIsNilpotentGroup( gr, true );
     
##
##  store the `RootSystem' in the attribute.
##
     SetRootSystem( gr, Fam!.rootsystem );

##
##  Store the property `IsFinite' (if the group is finite or not).
##  This helps choosing better Methods sometimes.
##  This is a ``cheap'' call, whereas calculating the size of the
##  group may require large powers of large integers.
##
     SetIsFinite( gr, IsFinite(F) );

     return gr;
end
);

################################################################################
##
#M  PrintObj( <U> ) . . . . . . . . . . . . . . . . . prints a `UnipotChevSubGr'
##
##  Special Method for `UnipotChevSubGr'
##

InstallMethod( PrintObj,
     "for a UnipotChevSubGr",
     [ IsUnipotChevSubGr ],
     function( U )
          local Fam;
          Fam := ElementsFamily( FamilyObj( U ) );
          
          Print( "UnipotChevSubGr( \"",
                 Fam!.type, "\", ",
                 Fam!.rank, ", ", 
                 Fam!.ring, " )"
               );
     end
);

################################################################################
##
#M  ViewObj( <U> ) . . . . . . . . . . . . . . . . . . . for a `UnipotChevSubGr'
##
##  Special Method for `UnipotChevSubGr'
##

InstallMethod( ViewObj,
     "for a UnipotChevSubGr",
     [ IsUnipotChevSubGr ], 1,
     function( U )
          local  type,
                 Fam;
          Fam := ElementsFamily( FamilyObj( U ) );
          type := Concatenation( Fam!.type, String(Fam!.rank) );
          
          Print("<Unipotent subgroup of a Chevalley group",
                " of type ", type, " over ");
          ViewObj( Fam!.ring ); Print(">");
     end
);

################################################################################
##
#M  <U1> = <U2> . . . . . . . . . . . . . . . equality for two `UnipotChevSubGr'
##
##  Special Method for `UnipotChevSubGr'
##

InstallMethod( \=,
     "for two UnipotChevSubGr",
     IsIdenticalObj,
     [ IsUnipotChevSubGr,
       IsUnipotChevSubGr ],
     function( U1, U2 )
          local Fam1, Fam2;

          Fam1 := ElementsFamily( FamilyObj( U1 ) );
          Fam2 := ElementsFamily( FamilyObj( U2 ) );
          
          return  IsIdenticalObj( U1, U2 ) or Fam1 = Fam2;
     end
);

################################################################################
##
#M  One( <U> )  . . . . . . . . . . . . . the one-element of a `UnipotChevSubGr'
##
##  Special Method for `UnipotChevSubGr'
##

InstallOtherMethod( One,
     "for a UnipotChevSubGr",
     [ IsUnipotChevSubGr ],
     U -> OneOp( U )
);

################################################################################
##
#M  OneOp( <U> )  . . . . . . . . . . . . the one-element of a `UnipotChevSubGr'
##
##  Special Method for `UnipotChevSubGr'
##

InstallOtherMethod( OneOp,
     "for a UnipotChevSubGr",
     [ IsUnipotChevSubGr ],
     U -> One(ElementsFamily( FamilyObj( U ) ))
);

################################################################################
##
#M  Size( <U> ) . . . . . . . . . . . . . the size of a finite `UnipotChevSubGr'
##
##  Special Method for finite `UnipotChevSubGr'
##
##  Are using the result of [Car72], Theorem 5.3.3 (ii) to compute the size.
##

InstallMethod( Size,
     "for a finite UnipotChevSubGr",
     [ IsUnipotChevSubGr and IsFinite ],
     function( U )
          local Fam, R;

          Fam := ElementsFamily( FamilyObj( U ) );
          R   := RootSystem(U);

          Info(UnipotChevInfo, 2, "The order of this group is ",
                                Size(Fam!.ring),"^",Length(PositiveRoots(R)),
                                " which is");
          return Size(Fam!.ring)^Length(PositiveRoots(R));
     end
);

################################################################################
##
#M  GeneratorsOfGroup( <U> )  . . . the generators of a finite `UnipotChevSubGr'
##
##  Special Method for finite `UnipotChevSubGr'
##
##

InstallOtherMethod( GeneratorsOfGroup,
     "for a finite UnipotChevSubGr",
     [ IsUnipotChevSubGr and IsFinite ],
     function( U )
          local Fam;

          Fam := ElementsFamily( FamilyObj( U ) );
          
          return 
          ListX( [1 .. Length(PositiveRoots(RootSystem(U)))], 
                 Difference( AsSet( Fam!.ring ), [Zero( Fam!.ring )] ),
                 function( r, x ) 
                      return UnipotChevElem( U, rec(roots:=[r], felems:=[x]), UNIPOT_DEFAULT_REP );
                 end
               );
     end
);


################################################################################
##
#M  CentralElement( <U> ) . . . . . . . . . . . . . . . for a  `UnipotChevSubGr'
##
##  Returns an arbitrary element from the center of <U>.
##
#T  This one has no proper name now. the declaration part should go into
#T  unipot.gd once it is working.
##

DeclareAttribute( "CentralElement", IsUnipotChevSubGr );

InstallMethod( CentralElement,
     "for a UnipotChevSubGr",
     [ IsUnipotChevSubGr ],
     function( U )
          local z,                 # the central element to be returned...
                t, tnr,            # the indeterminates for z ...
                posrootsFC, r,     # roots
                ring,              # underlying ring
                comm,              # the commutator of z with some elements ...
                ext,               # external rep of a polynom
                i,j;               # some loop variables ...
                
                
                
          posrootsFC := PositiveRootsFC(RootSystem(U));
          ring := ElementsFamily(FamilyObj(U))!.ring;
          
          # generate posroots many indeterminates...
          t := [];
          for r in [1..Length(posrootsFC)] do
               t[r] := Indeterminate( ring, 
                         Concatenation( "t_", String(r) ), t );
          od;
          
          # numbers of indeterminates ...
          tnr := List( t, 
                       s -> IndeterminateNumberOfUnivariateRationalFunction(s));
          
          # now <z> is an arbitrary Element in <U>:
          # (in fact, we could have called Representative(<U>), but
          #  we want to modify the lists <t> and <tnr> later on.)
          z := UnipotChevElemByFC( U, posrootsFC, t );

          # compute the commutator of z with any root elements
          # and draw conclusions
          for r in Reversed(posrootsFC) do
               repeat
                    comm := Comm( z, 
                                  UnipotChevElemByFC( U, r, One(ring) ), 
                                  "canonical" );
#                    Print("#I ");View(comm);Print("\n\n");
                    for i in comm!.felems do
                         ext := ExtRepPolynomialRatFun(i);
                         # if it is NOT a sum
                         if Length( ext ) = 2 then
                              for j in [1..Length(ext[1])] do
                                   if IsOddInt(j) and ext[1][j] in tnr then
                                        j:=Position(tnr, ext[1][j]);
#                                        Print("#I Eliminieren ",t[j],"\n");
                                        t[j] := Zero(ring);
                                        tnr[j] := Zero(ring);
                                        break;
                                   fi;
                              od;
                         fi;
                    od;
                    z := UnipotChevElemByFC( U, posrootsFC, t );
               until IsOne(comm);
          od;
          
          return z;
     end
);


################################################################################
##
#M  IsCentral( <U>, <z> ) . . . . for a `UnipotChevSubGr' and a `UnipotChevElem'
##

InstallMethod( IsCentral,
     "for a UnipotChevSubGr and a UnipotChevElem",
     IsCollsElms,
     [ IsUnipotChevSubGr, IsUnipotChevElem ],
     function( U, z )
          local posrootsFC, ring, r;
          
          # Treat the trivial case.
          if IsOne(z) then
               return true;
          fi;
          
          posrootsFC := PositiveRootsFC(RootSystem(U));
          ring := ElementsFamily(FamilyObj(U))!.ring;

          # The element <z> is central if and only if <z> commutes with all the 
          # elements x_r(1), r a positive root.
          for r in posrootsFC do;
               if not IsOne(Comm(z, UnipotChevElemByFC( U, r, One(ring) ), "canonical")) then
                    return false;
               fi;
          od;
          
          return true;
     end
);



################################################################################
##
#M  Representative( <U> ) . . . . . . . . . . . . . . . . . for `UnipotChevElem'
##
##  this one returns an element with ineterminates over the underlying ring 
##  instead of the ring elements itself. This allows ``symbolic'' computations.
##

InstallMethod( Representative,
     "for a UnipotChevElem",
     [ IsUnipotChevSubGr ],
     function( U )
          local posroots, r, indets;
          posroots := PositiveRoots(RootSystem(U));
          
          indets := [];
          for r in [1..Length(posroots)] do
               Add(indets,
                    Indeterminate( ElementsFamily(FamilyObj(U))!.ring,
                                   Concatenation("t_", String(r)),
                                   indets )
                   );
          od;
          
          return UnipotChevElem( U, rec(roots  := [1..Length(posroots)], 
                                        felems := indets ), UNIPOT_DEFAULT_REP );
     end
);




################################################################################
##
#M  UnipotChevElem( <Fam>, <record>, <rep> )
##
##  This is an `undocumented' function and should not be used at the GAP prompt
##  
##  the <record> must be of the following form:
##      rec( roots:=<roots>, felems:=<felems> )
##  where <roots> is a list of numbers from [1 .. <n>], <n> the number of
##  positive roots of the underlying root system and <felems> a list of the 
##  corresponding ring elements.
##  

InstallOtherMethod(  UnipotChevElem,
     "for UnipotChevFamily, a record and a string.",
     [IsUnipotChevFamily,
      IsRecord,
      IS_OPERATION],
     function( Fam, record, rep )
          local i,          # loop variable
                roots,      
                felems,     
                roots1,     # used for simplifying list
                F,          # the ring
                obj;        # the returned value

          roots  := record.roots;
          felems := record.felems;

          F := Fam!.ring;

          # check the lists
          if not Length( roots ) = Length( felems ) then
               Error( "<roots> and <felems> must have same length" );
          fi;

          for i in [1 .. Length(roots)] do
               if not ( IsBound(  roots[i] )
                    and IsBound( felems[i] ) ) then
                    Error(    
                         "<roots> and <felems> must be dense lists",
                         " of root numbers and ring elements,",
                         " respsctively.\n"
                    );
               fi;
               if not ( felems[i] in F )
                  and 
                  not IsIdenticalObj(ElementsFamily(FamilyObj(F)),
                                     CoefficientsFamily(FamilyObj(felems[i])))
                 then
                    Error( "<felems>[", i, "] must be an element ",
                           "of the ring ", F, "\n",
                           "or an Indeterminate over this ring." );
               fi;
               if not ( roots[i] in [1 .. Length( PositiveRoots(Fam!.rootsystem) )] ) then
                    Error( "<roots>[", i, "] must be an integer",
                           " in [1 .. <number of positive roots>]." );
               fi;
          od;
     
          if not rep in [ IsUnipotChevRepByRootNumbers,
                          IsUnipotChevRepByFundamentalCoeffs,
                          IsUnipotChevRepByRoots] then
               Error( "<rep> must be one of IsUnipotChevRepByRootNumbers,",
                      " IsUnipotChevRepByFundamentalCoeffs,",
                      " IsUnipotChevRepByRoots\n");
          fi;
          
          # use structural copies of the lists, so if one gave us mutable lists,
          # we do not mute them
          
          roots  := StructuralCopy(roots);
          felems := StructuralCopy(felems);

##     
#N  Note: The corresponding repeat-loop somewhere in CanonicalForm( <x> )
#N  MUST be always the same as the following loop here.
##
          # simplifying the element ...
          repeat
               roots1 := StructuralCopy(roots);
               for i in [ 1 .. Length(roots) ] do
                    if felems[i] = Zero(F)
                    or felems[i] = Zero(F)*Indeterminate(F) then
                         Unbind(  roots[i] );
                         Unbind( felems[i] );
                    elif i < Length(roots)
                     and roots[i] = roots[i+1] then
                         felems[i+1] := felems[i] + felems[i+1];
                         Unbind(  roots[i] );
                         Unbind( felems[i] );
                    fi;
               od;
               roots  := Compacted( roots );
               felems := Compacted( felems );
          until roots = roots1;
     
          obj := Objectify( NewType( Fam,
                                     IsUnipotChevElem and 
                                     rep and 
                                     IsCopyable),
                            rec(  roots := roots, 
                                            felems := felems )
                   );
          
     
          # we alredy know the canonical form of the object if the
          # length of <roots> is < 2:
          # it is the object itself:
          if Length(roots) < 2 then
               SetCanonicalForm( obj, obj );
          fi;
     
          # we alredy know that the element is the identity if the
          # length of <roots> is 0:
          if Length(roots) = 0 then
               SetIsOne( obj, true );

          # and we alredy know that the element is not the identity if the
          # length of <roots> is 1:
          elif Length(roots) = 1 then
               SetIsOne( obj, false );
          fi;
     
          return obj;
     end
);



################################################################################
##
#M  UnipotChevElem( <U>, <record>, <rep> )
##
##  This is an `undocumented' function and should not be used at the GAP prompt
##

InstallMethod(  UnipotChevElem,
     "for UnipotChevSubGr, a record and a string",
     [IsUnipotChevSubGr,
      IsRecord,
      IS_OPERATION],
     function( U, record, rep )
          return UnipotChevElem( ElementsFamily(FamilyObj(U)), record, rep );
     end
);


################################################################################
##
#M  UnipotChevElemByRootNumbers( <U>, <roots>, <felems> )
##
##  Returns an element of a unipotent subgroup <U> with representation
##  `IsUnipotChevRepByRootNumbers'.
##
##  <roots> should be a list of numbers of the roots in 
##  `RootSystem(<U>).posroots' and <felems> a list of corresponding ring 
##  elements,
##

InstallMethod(  UnipotChevElemByRootNumbers,
     "for UnipotChevSubGr and a list of positions of roots",
     [IsUnipotChevSubGr,
      IsList,
      IsList],
     function( U, roots, felems )
          return UnipotChevElem( U, rec( roots:=roots, felems:=felems ),
                                 IsUnipotChevRepByRootNumbers );
     end
);

################################################################################
##
#M  UnipotChevElemByRoots( <U>, <roots>, <felems> )
##
##  Returns an element of a unipotent subgroup <U> with representation
##  `IsUnipotChevRepByRoots'. 
##
##  <roots> should be a list of roots in `RootSystem(<U>).posroots' and 
##  <felems> a list of corresponding ring elements,
##

InstallMethod(  UnipotChevElemByRoots,
     "for UnipotChevSubGr and a list of roots",
     [IsUnipotChevSubGr,
      IsList,
      IsList],
     function( U, roots, felems )
          local list_of_positions,
                i,
                Fam,
                F;

          Fam := ElementsFamily(FamilyObj(U));

          F := Fam!.ring;
          list_of_positions := [];
          
          # check the lists
          if not Length( roots ) = Length( felems ) then
               Error( "<roots> and <felems> must have same length" );
          fi;
          for i in [1 .. Length(roots)] do
               if not ( IsBound(  roots[i] )
                    and IsBound( felems[i] ) ) then
                    Error(    
                         "<roots> and <felems> must be dense lists",
                         " of roots and ring elements,",
                         " respsctively.\n"
                    );
               fi;

               if not ( felems[i] in F )
                  and 
                  not IsIdenticalObj(ElementsFamily(FamilyObj(F)),
                                     CoefficientsFamily(FamilyObj(felems[i])))
                 then
                    Error( "<felems>[", i, "] must be an element ",
                           "of the ring ", F, "\n",
                           "or an Indeterminate over this ring." );
               fi;
               
               Add( list_of_positions, Position( PositiveRoots(RootSystem(U)), roots[i] ) );
               
               if list_of_positions[i] = fail then
                    Error( "<roots>[", i, "] must be a root." );
               fi;
          od;
               
          return UnipotChevElem( U, rec(  roots := list_of_positions,
                                         felems := felems ), 
                                IsUnipotChevRepByRoots );
     end
);

################################################################################
##
#M  UnipotChevElemByFundamentalCoeffs( <U>, <roots>, <felems> )
##
##  Returns an element of a unipotent subgroup <U> with representation
##  `IsUnipotChevRepByFundamentalCoeffs'. 
##
##  <roots> should be a list of roots as coefficients of a linear combination
##  of fundamental roots `RootSystem(<U>).fundroots' and <felems> a list of 
##  corresponding ring elements,
##

InstallMethod(  UnipotChevElemByFundamentalCoeffs,
     "for UnipotChevSubGr and a list of coordinates of roots",
     [IsUnipotChevSubGr,
      IsList,
      IsList],
     function( U, roots, felems )
          local list_of_positions,
                i,
                Fam,
                F;

          Fam := ElementsFamily(FamilyObj(U));

          F := Fam!.ring;
          list_of_positions := [];
          

          # check the lists
          if not Length( roots ) = Length( felems ) then
               Error( "<roots> and <felems> must have same length" );
          fi;
          for i in [1 .. Length(roots)] do
               if not ( IsBound(  roots[i] )
                    and IsBound( felems[i] ) ) then
                    Error(    
                         "<roots> and <felems> must be dense lists",
                         " of roots as coefficients of a linear",
                         " combination of fundamental roots",
                         " and ring elements,",
                         " respsctively.\n"
                    );
               fi;

               if not ( felems[i] in F )
                  and 
                  not IsIdenticalObj(ElementsFamily(FamilyObj(F)),
                                     CoefficientsFamily(FamilyObj(felems[i])))
                 then
                    Error( "<felems>[", i, "] must be an element ",
                           "of the ring ", F, "\n",
                           "or an Indeterminate over this ring." );
               fi;
               
               Add( list_of_positions, Position( PositiveRootsFC(RootSystem(U)), roots[i] ) );
               
               if list_of_positions[i] = fail then
                    Error( "<roots>[", i, "] must be a list of coefficients",
                           " representing a root as a linear combination of",
                           " fundamental roots." );
               fi;
          od;
               
          return UnipotChevElem( U, rec(  roots := list_of_positions,
                                         felems := felems ), 
                                IsUnipotChevRepByFundamentalCoeffs );
     end
);

################################################################################
##
#M  UnipotChevElemByRootNumbers( <U>, <root>, <felem> )
#M  UnipotChevElemByRoots( <U>, <root>, <felem> )
#M  UnipotChevElemByFundamentalCoeffs( <U>, <root>, <felem> )
##
##  These are abbreviations for `UnipotChevElemByXX( <U>, [<root>], [<felem>] )'
##

InstallOtherMethod(  UnipotChevElemByRootNumbers,
     "for UnipotChevSubGr, a position of a root and a ring rlement",
     [IsUnipotChevSubGr,
      IsPosInt,
      IsObject], # the third argument must be an element of Fam!.ring
     function( U, root, felem )
          return UnipotChevElemByRootNumbers( U, [root], [felem] );
     end
);

InstallOtherMethod(  UnipotChevElemByRoots,
     "for UnipotChevSubGr, a root and a ring rlement",
     [IsUnipotChevSubGr,
      IsList,
      IsObject], # the third argument must be an element of Fam!.ring
     function( U, root, felem )
          return UnipotChevElemByRoots( U, [root], [felem] );
     end
);

InstallOtherMethod(  UnipotChevElemByFundamentalCoeffs,
     "for UnipotChevSubGr, a lin. comb. of fund. roots and a ring element",
     [IsUnipotChevSubGr,
      IsList,
      IsObject], # the third argument must be an element of Fam!.ring
     function( U, root, felem )
          return UnipotChevElemByFundamentalCoeffs( U, [root], [felem] );
     end
);

################################################################################
##
#M  UnipotChevElemByRootNumbers( <U>, <list> )
#M  UnipotChevElemByRoots( <U>, <list> )
#M  UnipotChevElemByFundamentalCoeffs( <U>, <list> )
##
#N  These are old versions of `UnipotChevElemByXX'.
#N  They are *deprecated* and installed for compatibility only.
#N  They may be removed at any time.
##

InstallOtherMethod(  UnipotChevElemByRootNumbers,
     "for UnipotChevSubGr and a list. ***DEPRECATED***",
     [IsUnipotChevSubGr,
      IsList], 
     function( U, list )
          local roots, felems, i;
          
          Info(InfoWarning, 1, "UnipotChevElemByRootNumbers( <U>, <list> ) is ***DEPRECATED***");
          
          roots  := [];
          felems := [];
          
          # no checking the list at all.
          for i in [1 .. Length(list)] do;
               Add( roots,  list[i].r );
               Add( felems, list[i].x );
          od;
          return UnipotChevElemByRootNumbers( U, roots, felems );
     end
);

InstallOtherMethod(  UnipotChevElemByRoots,
     "for UnipotChevSubGr and a list. ***DEPRECATED***",
     [IsUnipotChevSubGr,
      IsList], 
     function( U, list )
          local roots, felems, i, Fam;
          
          Info(InfoWarning, 1, "UnipotChevElemByRoots( <U>, <list> ) is ***DEPRECATED***");
          
          roots  := [];
          felems := [];
                    
          # no checking the list at all.
          for i in [1 .. Length(list)] do;
               Add( roots,  list[i].r );
               Add( felems, list[i].x );
          od;
          return UnipotChevElemByRoots( U, roots, felems );
     end
);

InstallOtherMethod(  UnipotChevElemByFundamentalCoeffs,
     "for UnipotChevSubGr and a list. ***DEPRECATED***",
     [IsUnipotChevSubGr,
      IsList], 
     function( U, list )
          local roots, felems, i, Fam;
          
          Info(InfoWarning, 1, "UnipotChevElemByFundamentalCoefficions( <U>, <list> ) is ***DEPRECATED***");
          
          roots  := [];
          felems := [];
          
          # no checking the list at all.
          for i in [1 .. Length(list)] do;
               Add( roots,  list[i].coeffs );
               Add( felems, list[i].x );
          od;
          return UnipotChevElemByFundamentalCoeffs( U, roots, felems );
     end
);


################################################################################
##
#M  UnipotChevElemByRootNumbers( <x> )
#M  UnipotChevElemByFundamentalCoeffs( <x> )
#M  UnipotChevElemByRoots( <x> )
##
##  These are provided for converting elements to diferent representations.
##
##  E.g. If <x> has already the representation `IsUnipotChevRepByRoots', 
##       then <x> itself is returned by `UnipotChevElemByRoots( <x> ). 
##       Otherwise a *new* element with given representation is constructed. 
##

DeclareGlobalFunction( "ChangeUnipotChevRep" );
InstallOtherMethod(  UnipotChevElemByRootNumbers,
     "for UnipotChevElem",
     [IsUnipotChevElem],
     function( x )
          if IsUnipotChevRepByRootNumbers(x) then 
               return x;
          else
               return ChangeUnipotChevRep( x, 
                                           IsUnipotChevRepByRootNumbers );
          fi;
     end
);

InstallOtherMethod(  UnipotChevElemByFundamentalCoeffs,
     "for UnipotChevElem",
     [IsUnipotChevElem],
     function( x )
          if IsUnipotChevRepByFundamentalCoeffs(x) then 
               return x;
          else
               return ChangeUnipotChevRep( x, 
                                           IsUnipotChevRepByFundamentalCoeffs );
          fi;
     end
);

InstallOtherMethod(  UnipotChevElemByRoots,
     "for UnipotChevElem",
     [IsUnipotChevElem],
     function( x )
          if IsUnipotChevRepByRoots(x) then 
               return x;
          else
               return ChangeUnipotChevRep( x, 
                                           IsUnipotChevRepByRoots );
          fi;
     end
);


InstallGlobalFunction(  ChangeUnipotChevRep,
     function( x, rep )
          local Fam,
                new_obj,
                new_inv,
                new_canon;

          Fam := FamilyObj(x);
          
          new_obj := UnipotChevElem( Fam, rec(  roots := x!.roots,
                                               felems := x!.felems ), 
                                     rep );

          if HasIsOne(x) then
               SetIsOne( new_obj, IsOne(x) );
          fi;

          if HasInverse(x) then
               if IsIdenticalObj(x, Inverse(x)) then
                    SetInverse( new_obj, new_obj );
               else
                    new_inv := UnipotChevElem( Fam, 
                                          rec(  roots := Inverse(x)!.roots,
                                               felems := Inverse(x)!.felems ),
                                          rep );
                    if HasIsOne(Inverse(x)) then
                         SetIsOne( new_inv, IsOne(x) );
                    fi;
                    SetInverse( new_obj, new_inv );
                    SetInverse( new_inv, new_obj );
                    if HasCanonicalForm(x^-1) then
                         if IsIdenticalObj(x^-1, CanonicalForm(x^-1)) then
                              SetCanonicalForm( new_obj^-1, new_obj^-1 );
                         else
                              new_canon := 
                              UnipotChevElem( 
                                   Fam,
                                   rec( roots := CanonicalForm(x^-1)!.roots,
                                       felems := CanonicalForm(x^-1)!.felems ),
                                   rep );
                              # CanonicalForm always HasIsOne !
                              SetIsOne( new_canon, IsOne(x) );
                              SetCanonicalForm( new_inv,   new_canon );
                              SetCanonicalForm( new_canon, new_canon );
                              SetInverse( new_canon, new_obj );
                         fi;
                         
                    fi;
               fi;
          fi;
          if HasCanonicalForm(x) then
               if IsIdenticalObj( x, CanonicalForm(x) ) then
                    SetCanonicalForm( new_obj, new_obj );
               else
                    new_canon := UnipotChevElem(
                                    Fam,
                                    rec( roots := CanonicalForm(x)!.roots,
                                        felems := CanonicalForm(x)!.felems ),
                                    rep );
                    SetCanonicalForm( new_obj,   new_canon );
                    SetCanonicalForm( new_canon, new_canon );
                    if HasInverse( new_obj ) then
                         SetInverse( new_canon, Inverse(new_obj) );
                    fi;
               fi;
          fi;
          
          
          
          return new_obj;
     end
);


################################################################################
##
#M  PrintObj( <x> )  . . . . . . . . . . . . . . . . . prints a `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##

InstallMethod( PrintObj,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ], 1,
     function( x )
     local Fam;
          Fam := FamilyObj(x);
          
          if Length(x!.roots) = 0 then
               Print("One( ",  "UnipotChevSubGr( \"",
                      Fam!.type, "\", ", 
                      Fam!.rank, ", ", 
                      Fam!.ring, " )");  
          else
               if IsUnipotChevRepByRootNumbers(x) then
                    Print( "UnipotChevElemByRootNumbers" );
               elif IsUnipotChevRepByFundamentalCoeffs(x) then
                    Print( "UnipotChevElemByFundamentalCoeffs" );
               elif IsUnipotChevRepByRoots(x) then
                    Print( "UnipotChevElemByRoots" );
               fi;
               
               Print( "( ", "UnipotChevSubGr( \"",
                      Fam!.type, "\", ", 
                      Fam!.rank, ", ", 
                      Fam!.ring, " )", ", " );
                      
               if IsUnipotChevRepByRootNumbers(x) then
                    Print( x!.roots );
               elif IsUnipotChevRepByFundamentalCoeffs(x) then
                    Print( List(x!.roots, r -> PositiveRootsFC(Fam!.rootsystem)[r] ));
               elif IsUnipotChevRepByRoots(x) then
                    Print( List(x!.roots, r -> PositiveRoots  (Fam!.rootsystem)[r] ));
               fi;
               
               Print( ", ", x!.felems, " )");
               
          fi;
     end
);

################################################################################
##
#M  ViewObj( <x> )  . . . . . . . . . . . . . . . . . . . . for `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
#T  maybe should check for the length of the output and "beautify" the output 
#T  depending on the SizeScreen()
##

InstallMethod( ViewObj,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     function( x )
          local r, R;

          R := FamilyObj(x)!.rootsystem;

          if Length( x!.roots ) = 0 then
             Print( "<identity>" );  
          else
               for r in [ 1 .. Length(x!.roots) ] do
                    if r > 1 then Print(" * "); fi;
                    Print( "x_{" );
                    if IsUnipotChevRepByRootNumbers(x) then
                         ViewObj(                     x!.roots[r]   );
                    elif IsUnipotChevRepByFundamentalCoeffs(x) then
                         ViewObj( PositiveRootsFC(R)[ x!.roots[r] ] );
                    elif IsUnipotChevRepByRoots(x) then
                         ViewObj( PositiveRoots  (R)[ x!.roots[r] ] );
                    fi;
                    Print( "}( " );
                         ViewObj( x!.felems[r] );
                    Print( " )" );
               od;
          fi;
     end
);

################################################################################
##
#M  ShallowCopy( <x> )  . . . . . . . . . . . . . . . . . . for `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
##  should we have different Methods for each Representation? this means much
##  code duplication ...
##

InstallMethod( ShallowCopy,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     function( x )
          local rep, copy;
          
          if IsUnipotChevRepByRootNumbers(x) then
               rep := IsUnipotChevRepByRootNumbers;
          elif IsUnipotChevRepByFundamentalCoeffs(x) then
               rep := IsUnipotChevRepByFundamentalCoeffs(x);
          elif IsUnipotChevRepByRoots(x) then
               rep := IsUnipotChevRepByRoots;
          fi;

          copy := UnipotChevElem( FamilyObj( x ), 
                                 rec( roots := x!.roots,
                                     felems := x!.felems ), 
                                 rep );
         
          if HasInverse(x) then
               SetInverse(copy, Inverse(x));
          fi;
          if HasCanonicalForm(x) then
               SetCanonicalForm(copy, CanonicalForm(x));
          fi;
          if HasIsOne(x) then
               SetIsOne(copy, IsOne(x));
          fi;
          
          return copy;
     end
);

################################################################################
##
#M  <x> = <y>  . . . . . . . . . . . . . . . . equality for two `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
##  If <x> and <y> are identical or are products of the *same* root elements
##  then `true' is returned. Otherwise canonical form of both arguments must be
##  computed (if not already known), which may be expensive. 
##  

InstallMethod( \=,
     "for two UnipotChevElem",
     IsIdenticalObj,
     [ IsUnipotChevElem,
       IsUnipotChevElem ],
     function( x, y )
          if IsIdenticalObj( x,y ) or 
             ( x!.roots = y!.roots and x!.felems = y!.felems ) then
               return true;
          else 

          if not HasCanonicalForm(x) then
               Info(UnipotChevInfo, 3,
                          "CanonicalForm for the 1st argument is not known.");
               Info(UnipotChevInfo, 3,
                          "                  computing it may take a while.");
          fi;
          if not HasCanonicalForm(y) then
               Info(UnipotChevInfo, 3,
                          "CanonicalForm for the 2nd argument is not known.");
               Info(UnipotChevInfo, 3,
                          "                  computing it may take a while.");
          fi;

               return    CanonicalForm(x)!.roots  = CanonicalForm(y)!.roots
                     and CanonicalForm(x)!.felems = CanonicalForm(y)!.felems;
          fi;
     end
);

################################################################################
##
#M  <x> < <y> . . . . . . . . . . . . . . . . less than for two `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
##  This is needed e.g. by `AsSSortetList'.
##
##  The ordering is computed in the following way:
##  Let    x = x_{r_1}(s_1) ... x_{r_n}(s_n)
##  and    y = x_{r_1}(t_1) ... x_{r_n}(t_n), then
##  
##             x < y   <=>  [ s_1, ..., s_n ] < [ t_1, ..., t_n ],
##  
##  where the lists are compared lexicographically.
##  e.g. x = x_1(1)x_2(1) = x_1(1)x_2(1)x_3(0)  --> field elems: [ 1, 1, 0 ]
##       y = x_1(1)x_3(1) = x_1(1)x_2(0)x_3(1)  --> field elems: [ 1, 0, 1 ]
##   --> y < x (above lists ordered lexicographically)
##  

InstallMethod( \<,
     "for two UnipotChevElem",
     IsIdenticalObj,
     [ IsUnipotChevElem,
       IsUnipotChevElem ],
     function( x, y )
          local Fam, R, r, pos, tx, ty, o;
          
          if IsIdenticalObj( x,y ) or 
             ( x!.roots = y!.roots and x!.felems = y!.felems ) then
               return false;
          else 

               if not HasCanonicalForm(x) then
                    Info(UnipotChevInfo, 3,
                               "CanonicalForm for the 1st argument is not known.");
                    Info(UnipotChevInfo, 3,
                               "                  computing it may take a while.");
               fi;
               if not HasCanonicalForm(y) then
                    Info(UnipotChevInfo, 3,
                               "CanonicalForm for the 2nd argument is not known.");
                    Info(UnipotChevInfo, 3,
                               "                  computing it may take a while.");
               fi;

               Fam := FamilyObj(x);
               R   := Fam!.rootsystem;
               o   := Zero(Fam!.ring);
               
               for r in [1 .. Length(PositiveRoots(R))] do;

                    pos := Position( CanonicalForm(x)!.roots, r );
                    if pos = fail then tx := o;
                                  else tx := CanonicalForm(x)!.felems[pos]; 
                    fi;
                    pos := Position( CanonicalForm(y)!.roots, r );
                    if pos = fail then ty := o;
                                  else ty := CanonicalForm(y)!.felems[pos]; 
                    fi;
                    if not tx = ty then
                         return tx < ty;
                    fi;                
               od;

               return false;
          fi;
     end
);

################################################################################
##
#M  <x> * <y>  . . . . . . . . . . . . . multiplication for two `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
#N  The representation of the product will be always the representation of the
#N  first argument.
##

InstallMethod( \*,
     "for two UnipotChevElem",
     IsIdenticalObj,
     [ IsUnipotChevElem,
       IsUnipotChevElem ],
     function( x, y )
          local rep;
          
          if IsUnipotChevRepByRootNumbers(x) then
               rep := IsUnipotChevRepByRootNumbers;
          elif IsUnipotChevRepByFundamentalCoeffs(x) then
               rep := IsUnipotChevRepByFundamentalCoeffs;
          elif IsUnipotChevRepByRoots(x) then
               rep := IsUnipotChevRepByRoots;
          fi;
          
          return UnipotChevElem( 
                    FamilyObj( x ),
                    rec( roots := Concatenation( x!.roots,  y!.roots  ),
                        felems := Concatenation( x!.felems, y!.felems ) ),
                    rep
                 );
     end
);

################################################################################
##
#M  <x>^<i> . . . . . . . . . . . . . . . . . integer powers of `UnipotChevElem'
##
##  Special methods for root elements and for the identity.
##

InstallMethod( \^,
     "for a root element UnipotChevElem and an integer",
     [ IsUnipotChevElem and IsRootElement,
       IsInt ],
     function( x, i )
          local rep;
          
          if IsUnipotChevRepByRootNumbers(x) then
               rep := IsUnipotChevRepByRootNumbers;
          elif IsUnipotChevRepByFundamentalCoeffs(x) then
               rep := IsUnipotChevRepByFundamentalCoeffs;
          elif IsUnipotChevRepByRoots(x) then
               rep := IsUnipotChevRepByRoots;
          fi;
          
          return UnipotChevElem( 
                         FamilyObj( x ),
                         rec( roots := x!.roots,
                             felems := [ i * x!.felems[1] ] ),
                         rep
                 );
     end
);

InstallMethod( \^,
     "for a identity UnipotChevElem and an integer",
     [ IsUnipotChevElem and IsOne,
       IsInt ],
     function( x, i )
          return x;
     end
);

################################################################################
##
#M  OneOp( <x> ) . . . . . . . . . . . . . the one-element of a `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
##  `OneOp' returns the multiplicative neutral element of <x>. This is equal to
##  <x>^0. 
##

InstallMethod( OneOp,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     x -> One( FamilyObj( x ) )
);


################################################################################
##
#M  IsOne( <x> )  . . . . . . . . . . . . the one-property of a `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##

InstallMethod( IsOne,
     "for a UnipotChevElem with known canonical form",
     [ IsUnipotChevElem and HasCanonicalForm ], 1,
     x -> IsOne( CanonicalForm( x ) )
);

InstallMethod( IsOne,
     "for a UnipotChevElem with known inverse",
     [ IsUnipotChevElem and HasInverse ],
     function( x )
          if HasIsOne( Inverse(x) ) then
               return IsOne( Inverse(x) );
          else
               TryNextMethod();
          fi;
     end
);

InstallMethod( IsOne,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     x -> IsOne( CanonicalForm( x ) )
);


################################################################################
##
#M  Inverse( <x> ) . . . . . . . . . . . . . . the inverse of a `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##

InstallMethod( Inverse,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     function( x )
          local inv, rep;
          if HasCanonicalForm( x ) and HasInverse(CanonicalForm( x )) then
               return Inverse(CanonicalForm( x ));
          fi;
          
          if IsUnipotChevRepByRootNumbers(x) then
               rep := IsUnipotChevRepByRootNumbers;
          elif IsUnipotChevRepByFundamentalCoeffs(x) then
               rep := IsUnipotChevRepByFundamentalCoeffs;
          elif IsUnipotChevRepByRoots(x) then
               rep := IsUnipotChevRepByRoots;
          fi;
          
          inv := UnipotChevElem( 
                         FamilyObj( x ),
                         rec( roots :=  Reversed(x!.roots),
                             felems := -Reversed(x!.felems) ),
                         rep
                 );
                            
          # We alredy know the inverse of inv: it's x itself.
          SetInverse( inv, x );
          
          # Unfortunately we don't know the CanonicalForm for inv even
          # if we know it for x. If we would, we would store it here.
          # (Note that ``know'' have to be understood in the sense that
          # it is very cheap to get such a value.)

          # but the inverse of the canonical form of x is the same as
          # the inverse of x:
          if HasCanonicalForm( x ) then
               SetInverse( CanonicalForm(x), inv );
          fi;

          # if the Property IsOne of x is known, so it is also known for
          # the inverse!
          if HasIsOne( x ) then
               SetIsOne( inv, IsOne(x) );
          fi;
          
          return inv;
     end
);



################################################################################
##
#M  InverseOp( <x> ) . . . . . . . . . . . . . the inverse of a `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
#N  Ref, Chapter 28 (?reference:inverse) sais:
#N     The  default  method  of `Inverse'  is  to call `InverseOp' (note that
#N     `InverseOp'  must  *not*  delegate  to  `Inverse');  other  methods to
#N     compute inverses need to be installed only for `InverseOp'.
#N  
#N  In our case computing Inverse may be very time intensive, so
#N  we want to call `Inverse' instead of `InverseOp' because we
#N  want the inverse to be stored as attribute once computed
#N 
#N  In fact, the canonical form of an element is the time intensive
#N  operation. But consider the following example:
#N  x := UnipotChevElem(...);
#N  y := x^-1;
#N  CanonicalForm(y);
#N  z := x^-1;
#N  CanonicalForm(z); # must be computed again if Inverse not stored in x
#N 
#N  Note, that delegating `InverseOp' to `Inverse' *requires*
#N  `Inverse' to be overwritten not to call `InverseOp'.
##  

InstallMethod( InverseOp,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     x -> Inverse(x)
);


################################################################################
##
#F  ChevalleyCommutatorConstant( <i>, <j>, <r>, <s>, <Fam> )
##
##  This is an `undocumented' function and should not be used at the GAP prompt
##
##  The constants occuring in Chevalley's commutator formula. We compute them
##  as Rationals and embed them in the given ring afterwards. (It is known of 
##  them to be in [ 1, -1, 2, -2, 3, -3 ], in Char 2 this would be [ 1, 0 ] =
##  [ 1, 1, 0, 0, 1, 1 ] )
## 
##  The meaning of the arguments comes from the commutator formula, where <r>
##  and <s> are not the roots themself but their indices.
##  (e.g. roots are $r = r1$ and $s = r2$ --> arguments are $r = 1$, $s = 2$)
##

InstallGlobalFunction( ChevalleyCommutatorConstant,
     function( i, j, r, s, Fam)
          local M, N,
                const,
                roots,
                F;
          
          M := function( r, s, i )
               local m,   # the returned value
                     k,p; # used in the for-loop

               m := 1;
               Info( UnipotChevInfo, 6, 
                          "M( ", r, ", ", s, ", ", i, " ) = 1/", Factorial(i) );
               
               for k in [ 0 .. i-1 ] do
                    p := Position( roots, k * roots[r] + roots[s] );
                    Info( UnipotChevInfo, 6, "        * N( ", r, ", ", p, " )",
                                           "  [ = ", N[r][p], " ]" );
                    m := m * N[r][p];
               od;

               return m/Factorial(i);
          end;

          roots := PositiveRoots(Fam!.rootsystem);
          F     := Fam!.ring;
          N     := Fam!.structconst;
                    
          if not (r in [1 .. Length(roots)] and s in [1 .. Length(roots)]) then
               Error( "<r> and <s> must be integers in",
                      " [1 .. <number of positive roots>]." );
          fi;
          if not IsUnipotChevFamily(Fam) then
               Error( "<Fam> must be UnipotChevFamily (not ",
                      FamilyObj(Fam), ")." );
          fi;

          Info(UnipotChevInfo, 6, "C( ", i, ", ", j, ", ", r, ", ", s, " ) = ");

          
          if   j=1 then
               Info( UnipotChevInfo, 6, 
                     "        = M( ", r, ", ", s, ", ", i, " )" );
               const :=          M( r,   s, i );
          elif i=1 then
               Info( UnipotChevInfo, 6, 
                     "        = -1^", j, " * M( ", s, ", ", r, ", ", j, " )" );
               const := (-1)^j * M( s,   r, j );
          elif i=3 and j=2 then
               Info( UnipotChevInfo, 6, 
                     "        = 1/3 * M( ",
                     Position( roots, roots[r]+roots[s] ),
                     ", ", r, ", ", 2, " )" );
               const :=  1/3  * M( Position( roots, roots[r]+roots[s] ), r, 2 );
          elif i=2 and j=3 then
               Info( UnipotChevInfo, 6,
                     "        = -2/3 * M( ", 
                     Position( roots, roots[s]+roots[r] ), 
                     ", ", s,", ", 2, " )" );
               const := -2/3  * M( Position( roots, roots[s]+roots[r] ), s, 2 );
          else
               Error("i=",i, ", j=", j, " are illegal parameters.");
          fi;
          
          if not (const in [ 1, 2, 3, -1, -2, -3 ]) then
               Error("Something's gone wrong: the constant should be in",
                     " [ 1, 2, 3, -1, -2, -3 ]\n",
                     "instead of ", const);
          fi;
          
          return const*One(F);
     end
);

################################################################################
##
#M  <x>^<y>  . . . . . . . . . . . . . . . . . conjugation with `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
##  Doesn't do anything more than the default Method, but it stores the inverse
##  of <y>. And the result has the representation of <x>. (The default method
##  would return an element with representation of <y>.)
##

InstallMethod( \^,
     "for two UnipotChevElem's",
     [ IsUnipotChevElem,
       IsUnipotChevElem ],
     function( x, y )
          local fun;
          
          if IsUnipotChevRepByRootNumbers(x) then
               fun := UnipotChevElemByRN;
          elif IsUnipotChevRepByFundamentalCoeffs(x) then
               fun := UnipotChevElemByFC;
          elif IsUnipotChevRepByRoots(x) then
               fun := UnipotChevElemByR;
          fi;
          
          return fun( y^-1 * x * y );
     end
);

################################################################################
##
#M  Comm( <x>, <y> )  . . . . . . . . . . . . commutator of two `UnipotChevElem'
##
##  Special Method for `UnipotChevElem'
##
##  Doesn't do anything more than the default Method, but it stores the inverse
##  elements of <x> and <y>
##
##  The result has the representation of <x>.
##

InstallMethod( Comm,
     "for two UnipotChevElem",
     IsIdenticalObj,
     [ IsUnipotChevElem,
       IsUnipotChevElem ],
     function( x, y )
          return x^-1 * y^-1 * x * y;
     end
);

################################################################################
##
#M  Comm( <x>, <y>, "canonical" ) . . . . . . . . . commutator in canonical form
#M                                . . . . . . . . . . .  of two `UnipotChevElem'
##
##  Computes CanonicalForm of the Comm
##

InstallOtherMethod( Comm,
     "for two UnipotChevElem and a string",
     IsFamFamX,
     [ IsUnipotChevElem,
       IsUnipotChevElem,
       IsString ],
     function( x, y, canon)
          if canon <> "canonical" then
               Error("3rd argument (if present) must be \"canonical\"");
          fi;
          return CanonicalForm( Comm( x, y ) );
     end
);

################################################################################
##
#M  Comm( <x>, <y>, "canonical" ) . . . . . . . . . commutator in canonical form
#M                                . . .  of two root elements (`UnipotChevElem')
##
##  This Method calls `Comm( <x>, <y>, "as list" )', which uses a theorem,
##  known as Chevalley's commutator formula.
##

InstallOtherMethod( Comm,
     "for two root elements UnipotChevElem and a string",
     IsFamFamX,
     [ IsUnipotChevElem and IsRootElement,
       IsUnipotChevElem and IsRootElement,
       IsString ],
     function( x, y, canon )
          local rep, obj;

          if canon <> "canonical" then
               Error("3rd argument (if present) must be \"canonical\"");
          fi;

          if IsUnipotChevRepByRootNumbers(x) then
               rep := IsUnipotChevRepByRootNumbers;
          elif IsUnipotChevRepByFundamentalCoeffs(x) then
               rep := IsUnipotChevRepByFundamentalCoeffs;
          elif IsUnipotChevRepByRoots(x) then
               rep := IsUnipotChevRepByRoots;
          fi;
     

          obj := UnipotChevElem(
                         FamilyObj(x),
                         Comm( rec(r := x!.roots[1], x := x!.felems[1]),
                               rec(r := y!.roots[1], x := y!.felems[1]),
                               "as list", 
                               FamilyObj(x) ),
                         rep
                      );

          # obj has already the canonical form
          SetCanonicalForm( obj, obj );

          return obj;
     end
);

################################################################################
##
#M  Comm( <x>, <y>, "as list", <Fam> )  . . . . . . commutator in canonical form
#M                              . . . .  of two root elements (`UnipotChevElem')
##
##  This is an `undocumented' function and should not be used at the GAP prompt
##
##  This method uses a theorem, known as Chevalley's commutator formula, 
##        see [Car72], Theorem 5.2.2 (especially Corollar 5.2.3), Pages 76,77
##

InstallOtherMethod( Comm,
     "for two records, a string and a UnipotChevFamily",
     IsFamFamXY,
     [ IsRecord,
       IsRecord,
       IsString,
       IsUnipotChevFamily ],
     function( x, y, str, Fam )
          local comm_roots,
                comm_felems,  # will be returned
                roots,        # Roots
                in12, in21,   # Hilfsvariablen
                add;          # Hilfsfunktion

          if str <> "as list" then
               Error("3rd argument must be \"as list\"");
          fi;
          
          comm_roots  := [];
          comm_felems := [];
          roots := PositiveRoots(Fam!.rootsystem);

          add := function(i,j)
               Add(comm_roots, 
                    Position( roots, j*roots[x.r] + i*roots[y.r] )         );
               Add(comm_felems, 
                    ChevalleyCommutatorConstant( i, j, y.r, x.r, Fam )
                              * (-y.x)^i * (x.x)^j                         );
          end;
          
##
#N  1*r + 1*s  can appear in a group of any type
#N  2*r + 1*s  can appear only in groups of types B_n, C_n, F_4, G_2
#N  3*r + 1*s  \ these both con only appear in a group of type G_2 
#N  3*r + 2*s  / and only together!
#N 
#N  see [Car72], Lemma 3.6.3
## 

          
          if (roots[y.r] + roots[x.r]) in roots then
               add(1,1);
               if Fam!.type in [ "B", "C", "F" ] then
               
                    if   (2*roots[y.r] + roots[x.r]) in roots then
                         add(2,1);
                    elif (roots[y.r] + 2*roots[x.r]) in roots then
                         add(1,2);
                    fi;

               elif (Fam!.type = "G") then
                    in21 := (2*roots[y.r] + roots[x.r]) in roots;
                    in12 := (roots[y.r] + 2*roots[x.r]) in roots;
                    
                    if   in21 and in12 then
                         # which of them is the first inside roots?
                         if   Position(roots, 2*roots[y.r] + roots[x.r])  
                            < Position(roots, roots[y.r] + 2*roots[x.r]) then
                              add(2,1);
                              add(1,2);
                         else
                              add(1,2);
                              add(2,1);
                         fi;
                    elif in21 then
                         add(2,1);
                         if (3*roots[y.r] + roots[x.r]) in roots then
                              add(3,1);
                              add(3,2);
                         fi;
                    elif in12 then
                         add(1,2);
                         if  (roots[y.r] + 3*roots[x.r]) in roots then
                              add(1,3);
                              add(2,3);
                         fi;
                    fi;
               fi;
          fi;
          return rec( roots := comm_roots, 
                     felems := comm_felems );
     end
);



################################################################################
##
#M  IsRootElement( <x> ) . . . . . . . . . is a `UnipotChevElem' a root element?
##
##  `IsRootElement' returns `true' if and only if <x> is a <root element>,
##  i.e $<x>=x_{r_i}(t)$ for some root $r_i$.
##
##  We store this property just after creating objects.
##
#N  *Note:* the canonical form of <x> may be a root element even if <x> isn't
#N  one.
##

InstallImmediateMethod( IsRootElement,
     "for a UnipotChevElem",
     IsUnipotChevElem,
     0,
     x -> ( Length( x!.roots ) = 1 )
);

################################################################################
##
#M  CanonicalForm( <x> )  . . . . . . . . . canonical form of a `UnipotChevElem'
##
##  `CanonicalForm' returns the canonical form of <x>. 
##  For more information on the canonical form see [Car72], Theorem 5.3.3 (ii).
##  

InstallMethod( CanonicalForm,
     "for a UnipotChevElem",
     [ IsUnipotChevElem ],
     function( x )
          local i,                 # used in afor loop
                canonical,         # the return value
                computeCanonical,  # subroutine
                rep,               # here we remember the representation of <x>
                F;                 # the ring

--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge