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


SSL qea.gi   Sprache: unbekannt

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

#############################################################################
##
#W  qea.gi                  QuaGroup                           Willem de Graaf
##
##
##  Constructors for quantized enveloping algebras, and highest
##  weight modules.
##

############################################################################
##
## Some functions for dealing with "generalised binomials" as they 
## appear in the basis of the Lusztig Z-form of the quea. These functions
## rewrite elements as linear combinations of basis elements.
## 
## A binomial as the one below is expressed as [ delta, s ], where
## delta = 0,1 according to whether we multiply by K or not.
## An expression is a linear combination of such things.
##
QGPrivateFunctions.Multiply_Bin_Expr:= function( s, exx )

     # expresses
     #
     #    / K \ 
     #    |   | * exx
     #    \ s / 
     #
     # as a linear combination of such things...
     # The algorithm is simply based on the definition of the binomial,
     # and om some relations found in Lusztig, J. Amer math Soc. 1990
     # 278.

     local add_elm, expr, i, j, newexp, m, n, cf;

     add_elm:= function( ee, elm, cf )

          local pos;

          pos:= Position( ee, elm );
          if pos = fail then
             Add( ee, elm ); Add( ee, cf );
          else
             ee[pos+1]:= ee[pos+1]+ cf;
             if ee[pos+1]=0*ee[pos+1] then
                Unbind( ee[pos] ); Unbind( ee[pos+1] );
                ee:= Filtered( ee, x -> IsBound(x) );
             fi;
          fi;
          return ee;
     end;

     expr:= exx;
     for i in [1..s] do
         # multiply expr by q^(-i+1)K-q^(i-1)K^-1:
         
         newexp:= [ ];
         for j in [1,3..Length(expr)-1] do
             m:= expr[j];
             if m[1] = 0 then
                n:= ShallowCopy( m );
                n[1]:= 1;
                newexp:= add_elm( newexp, n, expr[j+1]*_q^(-i+1) );
             else
                n:= ShallowCopy( m );
                n[2]:= n[2]+1;
                newexp:= add_elm( newexp, n,
                    expr[j+1]*_q^(-i+1)*_q^m[2]*(_q^n[2]-_q^-n[2]) );
                n:= ShallowCopy( m );
                n[1]:= 0;
                newexp:= add_elm( newexp, n,
                    expr[j+1]*_q^(-i+1)*_q^(2*m[2]) );
             fi;
             
             if m[1]=0 then
                n:= ShallowCopy( m );
                n[2]:= n[2]+1;
                newexp:= add_elm( newexp, n,
                    expr[j+1]*_q^(i-1)*_q^-m[2]*(_q^n[2]-_q^-n[2]) );
                n:= ShallowCopy( m );
                n[1]:= 1;
                newexp:= add_elm( newexp, n,
                    -expr[j+1]*_q^(i-1)*_q^(-2*m[2]) );
             else   
                n:= ShallowCopy( m );
                n[1]:= 0;
                newexp:= add_elm( newexp, n, -expr[j+1]*_q^(i-1) );
             fi;
         od;
         expr:= newexp;
     od;

     cf:= (_q-_q^-1)^s*GaussianFactorial( s, _q );
     for i in [2,4..Length(expr)] do
         expr[i]:= expr[i]/cf;
     od;
     return expr;
end;    

QGPrivateFunctions.Multiply_K_Expr:= function( exx )

     # multiply exx by K...

     local add_elm, expr, i, m;

     add_elm:= function( ee, elm, cf )

          local pos;

          pos:= Position( ee, elm );
          if pos = fail then
             Add( ee, elm ); Add( ee, cf );
          else
             ee[pos+1]:= ee[pos+1]+ cf;
             if ee[pos+1]=0*ee[pos+1] then
                Unbind( ee[pos] ); Unbind( ee[pos+1] );
                ee:= Filtered( ee, x -> IsBound(x) );
             fi;
          fi;
          return ee;
     end;

     expr:= [ ];
     for i in [1,3..Length(exx)-1] do
         m:= ShallowCopy( exx[i] );
         if m[1] = 0 then
            m[1]:= 1;
            expr:= add_elm( expr, m, exx[i+1] );
         else
            m[2]:= m[2]+1;
            expr:= add_elm( expr, m, exx[i+1]*_q^(m[2]-1)*(_q^m[2]-_q^-m[2]) );
            m:= ShallowCopy( exx[i] );
            m[1]:= 0;
            expr:= add_elm( expr, m, exx[i+1]*_q^(2*m[2]) );
         fi;
     od;

     return expr;
end;

QGPrivateFunctions.Multiply_Exp_Exp:= function( ex1, ex2 )

      # multiply the two expressions ex1, ex2.

     local add_elm, res, expr, i, j, m;

     add_elm:= function( ee, elm, cf )

          local pos;

          pos:= Position( ee, elm );
          if pos = fail then
             Add( ee, elm ); Add( ee, cf );
          else
             ee[pos+1]:= ee[pos+1]+ cf;
             if ee[pos+1]=0*ee[pos+1] then
                Unbind( ee[pos] ); Unbind( ee[pos+1] );
                ee:= Filtered( ee, x -> IsBound(x) );
             fi;
          fi;
          return ee;
     end;

     res:= [ ];
     for i in [ 1, 3 .. Length(ex1)-1] do
         expr:= ex2;
         m:= ex1[i];
         if m[1] <> 0 then
            expr:= QGPrivateFunctions.Multiply_K_Expr( expr );
         fi;
         expr:= QGPrivateFunctions.Multiply_Bin_Expr( m[2], expr );
         for j in [1,3..Length(expr)-1] do
            res:= add_elm( res, expr[j], expr[j+1]*ex1[i+1] );
         od;
     od;

     return res;
end;


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

############################################################################
##
#M   PrintObj( <wr> )
##
##   We need a new PrintObj method for weight rep elements because in the one
##   in the library there is a statement e[k+1] > 0, which will fail for
##   q-elements. 
##
InstallMethod( PrintObj,
        "for weight rep element",
        true,
       [ IsWeightRepElement and IsPackedElementDefaultRep ], 0,
       function( v )

    local e,k;

    e:= v![1];
    if e = [] then
        Print( "0*v0" );
    else
        for k in [1,3..Length(e)-1] do
            if k>1 and not (IsRat(e[k+1]) and e[k+1]<0) then
                Print("+" );
            fi;
            Print( e[k+1]*e[k][2], "*v0" );
        od;
    fi;

end );



############################################################################
##
#M  ObjByExtRep( <fam>, <list> )
#M  ExtRepOfObj( <obj> )
##
InstallMethod( ObjByExtRep,
   "for family of QEA elements, and list",
   true, [ IsQEAElementFamily, IsList ], 0,
   function( fam, list )
#+
    return Objectify( fam!.packedQEAElementDefaultType,
                    [ Immutable(list) ] );
end );

InstallMethod( ExtRepOfObj,
   "for an QEA element",
   true, [ IsQEAElement ], 0,
   function( obj )
#+
   return obj![1];

end );

###########################################################################
##
#M  PrintObj( <m> ) . . . . . . . . . . . . . . . . for an QEA element
##
InstallMethod( PrintObj,
        "for QEA element",
        true, [IsQEAElement and IsPackedElementDefaultRep], 0,
        function( x )

    local   lst,  k, i, n, rank;

    # This function prints an element of a quantized enveloping algebra.

    lst:= x![1];
    n:= FamilyObj( x )!.noPosRoots;
    rank:= FamilyObj( x )!.rank;
    if lst=[] then
        Print("0");
    else
        for k in [1,3..Length(lst)-1] do
            if k>1 then
                Print("+");
            fi;
            if lst[k+1] <> lst[k+1]^0 then
                Print( "(",lst[k+1],")*");
            fi;
            if lst[k] = [] then
                Print("1");
            else

                for i in [1,3..Length(lst[k])-1] do
                    if IsList( lst[k][i] ) then
                       if lst[k][i][2] > 0 then
                          Print( "K", lst[k][i][1]-n );
                       fi;
                       if lst[k][i+1] > 0 then
                          Print( "[ K",lst[k][i][1]-n," ; ", 
                                              lst[k][i+1], " ]");
                       fi;
                    elif lst[k][i] <=n then
                        Print("F",lst[k][i]);
                        if lst[k][i+1]>1 then
                            Print("^(",lst[k][i+1],")");
                        fi;
                    else
                        Print("E",lst[k][i]-n-rank);
                        if lst[k][i+1]>1 then
                            Print("^(",lst[k][i+1],")");
                        fi;
                    fi;
                    if i <> Length(lst[k])-1 then
                        Print("*");
                    fi;
                od;
            fi;

        od;

    fi;

end );

#############################################################################
##
#M  OneOp( <m> ) . . . . . . . . . . . . . . . . for a QEA element
#M  ZeroOp( <m> ) . . . . . . . . . . . . . . .  for a QEA element
#M  \<( <m1>, <m2> ) . . . . . . . . . . . . . . for two QEA elements
#M  \=( <m1>, <m2> ) . . . . . . . . . . . . . . for two QEA elements
#M  \+( <m1>, <m2> ) . . . . . . . . . . . . . . for two QEA elements
#M  \-( <m> )     . . . . . . . . . . . . . . for a QEA element
#M  \in( <U>, <u> )  . . . . . . . . . . . . . . for QEA, and element
##
InstallMethod( OneOp,
        "for QEA element",
        true, [ IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x )

    return ObjByExtRep( FamilyObj( x ), [ [], FamilyObj(x)!.quantumPar^0 ] );

end );

InstallMethod( ZeroOp,
        "for QEA element",
        true, [ IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x )

    return ObjByExtRep( FamilyObj( x ), [ ] );

end );


InstallMethod( \<,
                "for two QEA elements",
        IsIdenticalObj, [ IsQEAElement and IsPackedElementDefaultRep,
                IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x, y )
    return x![1]< y![1];
end );

InstallMethod( \=,
                "for two QEA elements",
        IsIdenticalObj, [ IsQEAElement and IsPackedElementDefaultRep,
                IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x, y )


    return x![1] = y![1];
end );


InstallMethod( \+,
        "for two QEA elements",
        true, [ IsQEAElement and IsPackedElementDefaultRep,
                IsQEAElement and IsPackedElementDefaultRep], 0,
        function( x, y )

    local   ex,  ey,  mons,  cfs,  i,  lst, len;
    
    # Insert one sorted list in the second one; 
    # can be done much more efficiently!
    
    ex:= x![1]; ey:= y![1];
    mons:= [ ]; cfs:= [ ];
    for i in [1,3..Length(ex)-1] do
        Add( mons, ex[i] ); Add( cfs, ex[i+1] );
    od;

    for i in [1,3..Length(ey)-1] do
        Add( mons, ey[i] ); Add( cfs, ey[i+1] );
    od;
    SortParallel( mons, cfs );
    lst:= [ ];
    for i in [1..Length( mons )] do
        len:= Length(lst);
        if len > 0 and lst[len-1] = mons[i] then
            lst[len]:= lst[len]+cfs[i];
            if lst[len] = 0*lst[len] then
                Unbind( lst[len-1] ); Unbind( lst[len] );
                lst:= Filtered( lst, x -> IsBound(x) );
            fi;

        else
            Add( lst, mons[i] ); Add( lst, cfs[i] );
        fi;
    od;
    return ObjByExtRep( FamilyObj(x), lst );
end );


InstallMethod( AdditiveInverseSameMutability,
        "for QEA element",
        true, [ IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x )

    local   ex,  i;

    ex:= ShallowCopy(x![1]);
    for i in [2,4..Length(ex)] do
        ex[i]:= -ex[i];
    od;
    return ObjByExtRep( FamilyObj(x), ex );
end );

InstallMethod( AdditiveInverseMutable,
        "for QEA element",
        true, [ IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x )

    local   ex,  i;

    ex:= ShallowCopy(x![1]);
    for i in [2,4..Length(ex)] do
        ex[i]:= -ex[i];
    od;
    return ObjByExtRep( FamilyObj(x), ex );
end );

#############################################################################
##
#M  \*( <scal>, <m> ) . . . . . . . . .for a scalar and a QEA element
#M  \*( <m>, <scal> ) . . . . . . . . .for a scalar and a QEA element
##
InstallMethod( \*,
        "for scalar and QEA element",
        true, [ IsScalar, IsQEAElement and
                IsPackedElementDefaultRep ], 0,
        function( scal, x )

    local   ex,  i;
    
    if IsZero( scal ) then return Zero(x); fi;
    ex:= ShallowCopy( x![1] );
    for i in [2,4..Length(ex)] do
        ex[i]:= scal*ex[i];
    od;
    return ObjByExtRep( FamilyObj(x), ex );
end);

InstallMethod( \*,
        "for QEA element and scalar",
        true, [ IsQEAElement and IsPackedElementDefaultRep,
                IsScalar ], 0,
        function( x, scal )

    local   ex,  i;
    
    if IsZero( scal ) then return Zero(x); fi;
    ex:= ShallowCopy( x![1] );
    for i in [2,4..Length(ex)] do
        ex[i]:= scal*ex[i];
    od;
    return ObjByExtRep( FamilyObj(x), ex );
end);

InstallMethod( \in,
        "for QEA element and QEA",
        true, [ IsQEAElement, IsQuantumUEA ], 0,
        function( u, U )
    
    return IsIdenticalObj( ElementsFamily( FamilyObj(U) ), FamilyObj(u) );
end );

#############################################################################
##
#F  IsSpaceOfQEAElements( <V> )
##
##  If <V> is a space of elements of a quantized universal enveloping algebra,
##  then the `NiceFreeLeftModuleInfo' value of <V> is a record with the
##  following components.
##  \beginitems
##  `family' &
##     the elements family of <V>,
##
##  `monomials' &
##     a list of monomials occurring in the generators of <V>,
##
##  `zerocoeff' &
##     the zero coefficient of elements in <V>,
##
##  `zerovector' &
##     the zero row vector in the nice free left module,
##
##  \enditems
##  The `NiceVector' value of $v \in <V>$ is defined as the row vector of
##  coefficients of $v$ w.r.t. the list `monomials'.
##
##
##  This code is based on code by Thomas Breuer for the similar case
##  of vector spaces spanned by polynomials.
##
DeclareHandlingByNiceBasis( "IsSpaceOfQEAElements",
    "for free left modules of elements of a quantized uea" );

#############################################################################
##
#M  NiceFreeLeftModuleInfo( <V> )
#M  NiceVector( <V>, <v> )
#M  UglyVector( <V>, <r> )
##
InstallHandlingByNiceBasis( "IsSpaceOfQEAElements", rec(
        detect := function( F, gens, V, zero )
                  return IsQEAElementCollection( V );
        end,

          NiceFreeLeftModuleInfo := function( V )
            local gens,
                  monomials,
                  gen,
                  list,
                  zero,
                  info;

            gens:= GeneratorsOfLeftModule( V );

            monomials:= [];

            for gen in gens do
                list:= ExtRepOfObj( gen );
                UniteSet( monomials, list{ [ 1, 3 .. Length( list ) - 1 ] } );
            od;
            
            zero:= Zero( LeftActingDomain( V ) );
            info:= rec( monomials := monomials,
                        zerocoeff := zero,
                        family    := ElementsFamily( FamilyObj( V ) ) );
            
        # For the zero row vector, catch the case of empty `monomials' list.
            if IsEmpty( monomials ) then
                info.zerovector := [ zero ];
            else
                info.zerovector := ListWithIdenticalEntries( 
                                           Length( monomials ), zero );
            fi;
            
            return info;
        end,
          
        NiceVector := function( V, v )
            local info, c, monomials, i, pos;
            info:= NiceFreeLeftModuleInfo( V );
            c:= ShallowCopy( info.zerovector );
            v:= ExtRepOfObj( v );
            monomials:= info.monomials;
            for i in [ 2, 4 .. Length( v ) ] do
                pos:= Position( monomials, v[ i-1 ] );
                if pos = fail then
                    return fail;
                fi;
                c[ pos ]:= v[i];
            od;
            return c;
        end,
          
        UglyVector := function( V, r )
            local info, list, i;
            info:= NiceFreeLeftModuleInfo( V );
            if Length( r ) <> Length( info.zerovector ) then
                return fail;
            elif IsEmpty( info.monomials ) then
                if IsZero( r ) then
                    return Zero( V );
                else
                    return fail;
                fi;
            fi;
            list:= [];
            for i in [ 1 .. Length( r ) ] do
                if r[i] <> info.zerocoeff then
                    Add( list, info.monomials[i] );
                    Add( list, r[i] );
                fi;
            od;
            return ObjByExtRep( info.family, list );
        end ) );


#############################################################################
##
#F  CollectQEAElement( <sim>, <rts>, <B>, <s>, <rank>, <Mtab>, <expr> )
##
##
InstallGlobalFunction( CollectQEAElement,
        
        function( fam, expr )

    # `sim' are the simple roots.
    # `rts' are the roots in convex order.
    # `B' is the matrix of the bilinear form.
    # `s' is the number of positive roots.
    # `rank' is the rank of the root system.
    # `Mtab' is the multiplication table.
    # `qpar' is the quantum parameter.
    # `expr' is the thing that needs to be collected.
    
    local   comm_rule,  todo,  res,  m,  cf,  k,  found,  pos,  k1,  
            k2,  r,  rel,  start,  tail,  i,  mn,  m1,  j, qp, coef, 
            list1, list2, binomial_with_cst, kbit, k_normal, ee, store,
            R, sim, rts, B, s, rank, Mtab, qpar, isgeneric;

    comm_rule:= function( rel, j, i, m, n, r )
        
        # commutation rule for x_j^mx_i^n, where x_jx_i=qpar^rx_ix_j+rel
  
        # We use the following formula (easily proved by induction):
        #
        # x_j^mx_i^n = q^{nmr}x_i^nx_j^m + \sum_{l=0}^{n-1} \sum_{k=0}^{m-1}
        #     q^{(lm+k)r} xi^l xj^{m-1-k}Rx_j^kx_i^{n-1-l}, where R = rel.
        
        local   rule,  l,  k,  cf,  u,  mn, start, tail, qi, qj, den, t;
        
        if j > s + rank then
            qj:= _q^( rts[j-s-rank]*( B*rts[j-s-rank] )/2 );
        else
            qj:= _q^( rts[j]*( B*rts[j] )/2 );
        fi;
        if i > s +rank then
            qi:= _q^( rts[i-s-rank]*( B*rts[i-s-rank] )/2 );
        else
            qi:= _q^( rts[i]*( B*rts[i] )/2 );
        fi;
        
        den:= GaussianFactorial( m, qj )*GaussianFactorial( n, qi );

        rule:= [ [ i, n, j, m], qpar^(n*m*r) ];
        for l in [0..n-1] do
            for k in [0..m-1] do
                cf:= _q^((l*m+k)*r)/den;
                start:= [ ];
                if l <> 0 then
                    Add( start, i ); Add( start, l );
                    cf:= cf*GaussianFactorial( l, qi );
                fi;
                if m-1-k <> 0 then
                    Add( start, j ); Add( start, m-1-k );
                    cf:= cf*GaussianFactorial( m-1-k, qj );
                fi;
                tail:= [];
                if k <> 0 then
                    Add( tail, j ); Add( tail, k );
                    cf:= cf*GaussianFactorial( k, qj );
                fi;
                if n-1-l <> 0 then
                    Add( tail, i ); Add( tail, n-1-l );
                    cf:= cf*GaussianFactorial( n-1-l, qi );
                fi;

                for u in [1,3..Length(rel)-1] do
                    mn:= ShallowCopy( start );
                    Append( mn, rel[u] );
                    Append( mn, tail );
                    Add( rule, mn ); Add( rule, cf*rel[u+1] );
                od;
            od;
        od;

        return rule;
    end;
    
    binomial_with_cst:= function( c, t )

     # The binomial
     #
     #     / K; c \
     #     |      |
     #     \  t   /
     #
     # expressed in the integral basis. We use relations from Lusztig's 
     # paper.

     local add_elm, i, j, res, Kmin, expr;

     add_elm:= function( ee, elm, cf )

          local pos;

          if cf = 0*cf then return ee; fi;

          pos:= Position( ee, elm );
          if pos = fail then
             Add( ee, elm ); Add( ee, cf );
          else
             ee[pos+1]:= ee[pos+1]+ cf;
             if ee[pos+1]=0*ee[pos+1] then
                Unbind( ee[pos] ); Unbind( ee[pos+1] );
                ee:= Filtered( ee, x -> IsBound(x) );
             fi;
          fi;
          return ee;
     end;


     res:= [ ];
     if c <= -1 then
        c:= -c;
        for j in [0..t] do
            expr:= [ [ 0, t-j ], (-1)^j*_q^( c*(t-j) )*
                        GaussianBinomial(  c+j-1, j, _q ) ];
            for i in [1..j] do
                expr:= QGPrivateFunctions.Multiply_K_Expr( expr );
            od;
            for i in [1,3..Length(expr)-1] do
                res:= add_elm( res, expr[i], expr[i+1] );
            od;
        od;
     else
        Kmin:= [ [ 1, 0 ], _q^0, [ 0, 1], _q^-1-_q ];
        for j in [0..t] do
            expr:= [ [ 0, t-j ],  _q^( c*(t-j) )*
                        GaussianBinomial(  c, j, _q ) ];
            for i in [1..j] do
                expr:= QGPrivateFunctions.Multiply_Exp_Exp( Kmin, expr );
            od;
            for i in [1,3..Length(expr)-1] do
                res:= add_elm( res, expr[i], expr[i+1] );
            od;
        od;
      fi;
      return res;
    end;

    R:= fam!.rootSystem;
    sim:= SimpleSystemNF(R);
    rts:= fam!.convexRoots;
    B:= BilinearFormMatNF(R);
    s:= fam!.noPosRoots;
    rank:= fam!.rank;
    Mtab:= fam!.multTab;
    qpar:= fam!.quantumPar;

    if qpar = _q then 
        isgeneric:= true;
    else
        isgeneric:= false;
    fi;

    # In the program we use ... [ i, d, a ], s ... for
    #
    #       / Ki; a \
    #  Ki^d |       |
    #       \   s   /
    #

    todo:= expr;

    for k in [1,3..Length(todo)-1] do
        for i in [1,3..Length(todo[k])-1] do
            if IsList( todo[k][i] ) and Length( todo[k][i] ) = 2 then
               todo[k][i]:= ShallowCopy( todo[k][i] );
               Add( todo[k][i], 0 );
            fi;
        od;
    od;

    res:= [ ];
    while todo <> [] do

        m:= todo[1];
        cf:= todo[2];

        for i in [1,3..Length(m)-1] do
            if IsList( m[i] ) and Length( m[i] ) = 2 then
               m[i]:= ShallowCopy( m[i] );
               Add( m[i], 0 );
            fi;
        od;

        # We try to find indices in the `wrong' order.

        k:= 1; found:= false;
        while k < Length(m)-2 do

            if IsList( m[k] ) then
               k1:= m[k][1];
               list1:= true;
            else
               k1:= m[k];
               list1:= false;
            fi;
            if IsList( m[k+2] ) then
               k2:= m[k+2][1];
               list2:= true;
            else
               k2:= m[k+2];
               list2:= false;
            fi;

            if k1 > k2 then
                found:= true;
                break;
            elif k1 = k2 then

                if not list1 then
                
                   if m[k] <= s then
                       qp:= qpar^( rts[m[k]]*(B*rts[m[k]])/2 );
                       cf:= cf*GaussianBinomial( m[k+1]+m[k+3], m[k+1], qp );
                   fi;
                
                   if m[k] > s + rank then
                       qp:= qpar^( rts[m[k]-s-rank]*(B*rts[m[k]-s-rank])/2 );
                       cf:= cf*GaussianBinomial( m[k+1]+m[k+3], m[k+1], qp );
                   fi; 
                
                   m[k+1]:= m[k+1]+m[k+3];
                
                   if m[k+1] = 0*m[k+1] then
                       Unbind( m[k] ); Unbind( m[k+1] );
                       Unbind( m[k+2] ); Unbind( m[k+3] );
                       m:= Filtered( m, x -> IsBound(x) );
                       if k > 1 then
                        
                           # there is a new elt on pos k, we have to check
                           # whether it is in the correct order with 
                           # the previous element.
                           k:= k-2;
                       fi;
                   else
                       Unbind( m[k+2] ); Unbind( m[k+3] );
                       m:= Filtered( m, x -> IsBound(x) );
                   fi;
                else
                   # both are K-elements, coming from the same K_{\alpha}
                   # we do nothing (for the moment).
                   k:= k+2;
                fi;
            else
                k:= k+2;
            fi;
            
        od;

        if not found then

            # We add the monomial to `res'. However, we must still 
            # normalise the K-part...

            start:= [ ];
            k:= 1;
            while k < Length( m ) and not IsList( m[k] ) do
               Add( start, m[k] );
               Add( start, m[k+1] );
               k:= k+2;
            od;

            kbit:= [ ];
            while k < Length( m ) and IsList( m[k] ) do 
               Add( kbit, m[k] );
               Add( kbit, m[k+1] );
               k:= k+2;
            od; 

            tail:= [ ];
            while k < Length( m ) do
               Add( tail, m[k] );
               Add( tail, m[k+1] );
               k:= k+2;
            od;  

            k_normal:= [ [], qpar^0];
            ee:= [ ];
            k:= 1;
            while k < Length( kbit ) do

               rel:= binomial_with_cst( kbit[k][3], kbit[k+1] );
               if kbit[k][2] > 0 then 
                  rel:= QGPrivateFunctions.Multiply_K_Expr( rel );
               fi;
               if ee <> [ ] then
                  ee:= QGPrivateFunctions.Multiply_Exp_Exp( ee, rel );
               else
                  ee:= rel;
               fi;
               
               if k = Length(kbit)-1 or kbit[k][1] <> kbit[k+2][1] then
                  # add everything in `ee' to `k_normal',
                  # and start a new `ee':

                  qp:= qpar^( B[kbit[k][1]-s][kbit[k][1]-s]/2 );
                  store:= [ ];
                  for i in [1,3..Length(k_normal)-1] do
                      for j in [1,3..Length(ee)-1] do
                          mn:= ShallowCopy( k_normal[i] );
                          if ee[j] <> [ 0, 0 ] then
                             # Otherwise we multiply by one....
                             Add( mn, [ kbit[k][1], ee[j][1] ] );
                             Add( mn, ee[j][2] );
                          fi;
                          Add( store, mn );
                          Add( store, k_normal[i+1]*Value( ee[j+1], qp ) );
                      od;
                   od;
                   k_normal:= store;
                   ee:= [ ];
               fi;
               k:= k+2;
            od;   

            for k in [1,3..Length(k_normal)-1] do
                
                m:= ShallowCopy( start );
                Append( m, k_normal[k] );
                Append( m, tail );
                coef:= cf*k_normal[k+1];

                pos:= Position( res, m );
                if pos <> fail then
                   res[pos+1]:= res[pos+1]+coef;
                   if res[pos+1] = 0*coef then
                      Unbind( res[pos] ); Unbind( res[pos+1] );
                      res:= Filtered( res, x -> IsBound(x) );
                   fi;
                else    
                   Add( res, m );
                   Add( res, coef );
                fi;
            od; 
            
            Unbind( todo[1] );
            Unbind( todo[2] );
            todo:= Filtered( todo, x -> IsBound(x) );
        else
            
            # we know k1 > k2...
            
            if k1 > s+rank then
                
                # i.e., k1 is an E
                
                if k2 > s+rank then
                    
                    # i.e., k2 is also an E, commutation from Mtab
                    
                    if isgeneric then
                       r:= rts[k1-s-rank]*( B*rts[k2-s-rank]);                 
                       rel:= comm_rule( Mtab[k1][k2], m[k], m[k+2], 
                                    m[k+1], m[k+3], -r );
                    else
                       rel:= CollectQEAElement( ElementsFamily( 
                                    FamilyObj( fam!.genericQUEA ) ), 
                                    [ m{[k..k+3]}, _q^0 ] );
                       for i in [2,4..Length(rel)] do
                           rel[i]:= Value( rel[i], qpar );
                       od;
                    fi;

                    start:= m{[1..k-1]};
                    tail:= m{[k+4..Length(m)]};

                    for i in [1,3..Length(rel)-1] do
                        mn:= ShallowCopy( start );
                        Append( mn, rel[i] ); Append( mn, tail );
                        if i = 1 then
                            todo[1]:= mn;
                            todo[2]:= cf*rel[i+1];
                        else
                            Add( todo, mn ); Add( todo, cf*rel[i+1] );
                        fi;

                    od;
                    
                elif k2 > s then

                    # i.e., k2 is a K:
                    r:= -2*rts[k1-s-rank]*( B*sim[k2-s] )/B[k2-s][k2-s];
                    r:= r*m[k+1];
                    qp:= qpar^(B[k2-s][k2-s]/2);
                    coef:= qp^(r*m[k+2][2]);
                    mn:= m{[1..k-1]};
                    Add( mn, ShallowCopy(m[k+2]) );
                    mn[k][3]:= mn[k][3] + r; 
                    Add( mn, m[k+3] );
                    Add( mn, m[k] ); Add( mn, m[k+1] );
                    Append( mn,m{[k+4..Length(m)]} );
                    todo[1]:= mn;
                    todo[2]:= cf*coef;

                else
                    # k2 is an F, commutation from Mtab
                    
                    if isgeneric then
                       rel:= comm_rule( Mtab[k1][k2], m[k], m[k+2], 
                                     m[k+1], m[k+3], 0 );
                    else
                       rel:= CollectQEAElement( ElementsFamily( 
                                    FamilyObj( fam!.genericQUEA ) ), 
                                    [ m{[k..k+3]}, _q^0 ] );
                       for i in [2,4..Length(rel)] do
                           rel[i]:= Value( rel[i], qpar );
                       od;
                       # change the K-elements back to slightly strange form...
                       for j in [1,3..Length(rel)-1] do
                           for i in [1,3..Length(rel[j])-1] do
          
                    if IsList( rel[j][i] ) and Length( rel[j][i] ) = 2 then
                       Add( rel[j][i], 0 );
                    fi;
                            od;
                       od;
                    fi;
      
                    start:= m{[1..k-1]};
                    tail:= m{[k+4..Length(m)]};
                    
                    for i in [1,3..Length(rel)-1] do
                        mn:= ShallowCopy( start );
                        Append( mn, rel[i] ); Append( mn, tail );
                        if i = 1 then
                            todo[1]:= mn;
                            todo[2]:= cf;
                        else
                            Add( todo, mn ); Add( todo, cf*rel[i+1] );
                        fi;
                        
                    od;                        
                    
                fi;
            elif k1 > s then
                    
                # i.e., k1 is a K, 
                
                if k2 > s then
                    
                    # i.e., k2 is also a K; they commute
                    
                    mn:= m{[1..k-1]};
                    Add( mn, m[k+2] ); Add( mn, m[k+3] );
                    Add( mn, m[k] ); Add( mn, m[k+1] );
                    Append( mn,m{[k+4..Length(m)]} );
                    todo[1]:= mn;
                    todo[2]:= cf;
                else
                    
                    # i.e., k2 is an F:

                    r:= -2*rts[k2]*( B*sim[k1-s] )/B[k1-s][k1-s];
                    r:= r*m[k+3];
                    qp:= qpar^(B[k1-s][k1-s]/2);
                    coef:= qp^(r*m[k][2]);
                    mn:= m{[1..k-1]};
                    Add( mn, m[k+2] );
                    Add( mn, m[k+3] );
                    Add( mn, ShallowCopy(m[k]) );
                    mn[k+2][3]:= mn[k+2][3] + r; 
                    Add( mn, m[k+1] );
                    Append( mn,m{[k+4..Length(m)]} );
                    todo[1]:= mn;
                    todo[2]:= cf*coef;

                fi;
            else
                # i.e., k1, k2 are both F's. 
                # commutation from Mtab

                if isgeneric then

                   r:= rts[k1]*( B*rts[k2]);
                
                   rel:= comm_rule( Mtab[k1][k2], m[k], m[k+2], 
                                     m[k+1], m[k+3], -r );
                else
                   rel:= CollectQEAElement( ElementsFamily( 
                                 FamilyObj( fam!.genericQUEA ) ), 
                                    [ m{[k..k+3]}, _q^0 ] );
                   for i in [2,4..Length(rel)] do
                       rel[i]:= Value( rel[i], qpar );
                   od;
                fi;
                
                start:= m{[1..k-1]};
                tail:= m{[k+4..Length(m)]};
                        
                for i in [1,3..Length(rel)-1] do
                    mn:= ShallowCopy( start );
                    Append( mn, rel[i] ); Append( mn, tail );
                    if i = 1 then
                        todo[1]:= mn; todo[2]:= cf*rel[i+1];
                    else
                        Add( todo, mn ); Add( todo, cf*rel[i+1] );
                    fi;
                    
                od;
                
                
            fi;
            
        fi;
    od;

    return res;
end);


#############################################################################
##
#M  \*( <x>, <y> ) . . . . . . . . . . . . . . for two QEA elements
##
##
InstallMethod( \*,
        "for two QEA elements",
        IsIdenticalObj, [ IsQEAElement and IsPackedElementDefaultRep,
                IsQEAElement and IsPackedElementDefaultRep ], 0,
        function( x, y )
    
    local   ex,  ey,  expr,  i,  j,  m,  mons,  cfs,  len;    
   
    ex:= ExtRepOfObj(x);
    ey:= ExtRepOfObj(y);

    # We build the expression that needs to be collected.

    expr:= [ ];
    for i in [1,3..Length(ex)-1] do
        for j in [1,3..Length(ey)-1] do
            m:= ShallowCopy( ex[i] );
            Append( m, ey[j] );
            Add( expr, m );
            Add( expr, ex[i+1]*ey[j+1] );
        od;
    od;    
    
    # We collect it.
    
    expr:= CollectQEAElement( FamilyObj( x ), expr );
    
    mons:= [ ]; cfs:= [ ];
    for i in [1,3..Length(expr)-1] do
        if not IsZero( expr[i+1] ) then
           Add( mons, expr[i] ); Add( cfs, expr[i+1] );
        fi;
    od;

    # Sort everything, take equal things together, wrap it up and return.

    SortParallel( mons, cfs );

    expr:= [ ];
    len:= 0;
    for i in [1..Length( mons )] do
        if len > 0 and expr[len-1] = mons[i] then
            expr[len]:= expr[len]+cfs[i];
            if expr[len] = 0*expr[len] then
                Unbind( expr[len-1] ); Unbind( expr[len] );
                expr:= Filtered( expr, x -> IsBound(x) );
                len:= len-2;
            fi;

        else
            Add( expr, mons[i] ); Add( expr, cfs[i] );
            len:= len+2;
        fi;
    od;

    return ObjByExtRep( FamilyObj(x), expr );
end );

#########################################################################
##
#M  QuantizedUEA( <R> )
##
InstallMethod( QuantizedUEA,
        "for a root system",
        true, [ IsRootSystem ], 0,
        function( R )
    
    local   n,  rank,  B,  fam,  mm,  Ftab,  FEtab,  tt,  k,  rel,  i,  
            j,  qp,  ii,  gens,  A, normalise_rel;    

     # This function returns the quantized uea with respect to the root
     # system R. This algebra is generated by F1...Fn, K1, K1^-1,
     # ... Kr, Kr^-1, E1...En, where 
     #    Fk = T_{i_1}...T_{i_{k-1}}(F_{\alpha_{ik}})
     #    Ek = T_{i_1}...T_{i_{k-1}}(E_{\alpha_{ik}}),
     # where [ i_1,....,i_n ] is a redcued expression for the longest element
     # in the Weyl group. 

     # The elements are represented as elements of the Lusztig
     # Z-form of the quantized uea. The elements of this basis have the form
     #
     #   F1^(k1)...Fn^(kn) K1^d1 [K1;m1] ... Kr^dr [Kr;mr] E1^(p1)..En^(pn)
     #
     # where di=0,1 and [Ki;mi] is the "binomial"
     #
     #   / Ki; 0 \
     #   |       |
     #   \  mi   /
     #
     # Internally, such a monomial is represented as a list of indices
     # and exponents: the F-s have indices 1,..,n and the E-s have indices
     # n+r+1...2*n+r. Furthermore, an element Ki^di [Ki;mi] is represented as
     # .... , [ i, di ], mi .... So, for example the monomial 
     # F2^(3) K2 [ K2;4 ] E6^(8) (in type G2) is represented as 
     # [ 2, 3, [ 2, 1 ], 4, 14, 8 ].
     # Finally, a general element is represented as a list of monomials
     # and coefficients.

     normalise_rel:= function( s, rank, B, rel )

     # writes the relation rel using the generalised binomials in Lusztig's
     # Z-form of the quea.

     local add_elm, i, j, k, l, res, m, mon, e, f, ks, k_piece,
           new_piece, elm, ee, qp;

     add_elm:= function( ee, elm, cf )

          local pos;

          pos:= Position( ee, elm );
          if pos = fail then
             Add( ee, elm ); Add( ee, cf );
          else
             ee[pos+1]:= ee[pos+1]+ cf;
             if ee[pos+1]=0*ee[pos+1] then
                Unbind( ee[pos] ); Unbind( ee[pos+1] );
                ee:= Filtered( ee, x -> IsBound(x) );
             fi;
          fi;
          return ee;
     end;
      
     res:= [ ];
     for i in [1,3..Length(rel)-1] do
         m:= rel[i];
         k:= 1;
         f:= [ ];
         while k <= Length( m ) and m[k] <= s do 
            Add( f, m[k] );
            Add( f, m[k+1] );
            k:= k+2;
         od;
         ks:= [ ];
         while k <= Length( m ) and m[k] <= s+rank do 
            Add( ks, m[k] );
            Add( ks, m[k+1] );
            k:= k+2;
         od;
         e:= [ ];
         while k <= Length( m ) do
            Add( e, m[k] );
            Add( e, m[k+1] );
            k:= k+2;
         od;

         k_piece:= [ [], _q^0 ];
         for j in [1,3..Length(ks)-1] do
             if ks[j+1] > 0 then
                elm:= [ [1,0], _q^0 ];
                ee:= elm;
                for k in [2..ks[j+1]] do
                    ee:= QGPrivateFunctions.Multiply_Exp_Exp( ee, elm );
                od;
             else
                elm:= [ [1,0], _q^0, [0,1], _q^-1-_q ];
                ee:= elm;
                for k in [2..-ks[j+1]] do
                    ee:= QGPrivateFunctions.Multiply_Exp_Exp( ee, elm );
                od;
             fi;

             qp:= _q^( B[ks[j]-s][ks[j]-s]/2 );
             for k in [2,4..Length(ee)] do
                 ee[k]:= Value( ee[k], qp );
             od;
             new_piece:= [ ];
             for k in [1,3..Length(ee)-1] do
                 if ee[k] <> [ 0, 0 ] then 
                    m:= [ ks[j], ee[k][1] ];
                    for l in [1,3..Length(k_piece)-1] do 
                        mon:= ShallowCopy( k_piece[l] );
                        Add( mon, m );
                        Add( mon, ee[k][2] );
                        Add( new_piece, mon );
                        Add( new_piece, ee[k+1]*k_piece[l+1] );
                    od; 
                 else
                    # we multiply by a scalar, effectively
                    for l in [1,3..Length(k_piece)-1] do 
                        mon:= ShallowCopy( k_piece[l] );
                        Add( new_piece, mon );
                        Add( new_piece, ee[k+1]*k_piece[l+1] );
                    od; 
                 fi;
             od;
             k_piece:= new_piece;
         od;

         for j in [1,3..Length(k_piece)-1] do
             m:= ShallowCopy( f );
             Append( m, k_piece[j] );
             Append( m, e );
             res:= add_elm( res, m, k_piece[j+1]*rel[i+1] );
         od;

     od;
     return res;
    end;
    
    # First we produce the PBW generators of the quantized enveloping 
    # algebra corresponding to R. It mainly boils down to installing a 
    # lot of data in the family.

    n:= Length(PositiveRoots(R));
    rank:= Length( CartanMatrix(R) );
    B:= BilinearFormMatNF( R );
    
    fam:= NewFamily( "QEAEltFam", IsQEAElement );
    fam!.packedQEAElementDefaultType:=
                  NewType( fam, IsPackedElementDefaultRep );
    fam!.noPosRoots:= Length( PositiveRoots(R) );
    fam!.rank:= Length( CartanMatrix(R) );
    fam!.rootSystem:= R;
    
    mm:= QGPrivateFunctions.E_Tab( R );
    
    fam!.convexRoots:= mm[1]; # i.e., pos roots in convex order...
    
    Ftab:= QGPrivateFunctions.F_tab( R, mm[2], mm[1] );
    FEtab:= QGPrivateFunctions.FE_table( R, mm[2], Ftab, mm[1] );
    
    # `tt' will contain all commutation relations (Etab, Ftab, FEtab) 
    tt:= List([1..n], x -> [] );  
    for k in [1..n] do
        tt[k+rank+n]:= [];
    od;
    
    # We normalise the relations in the tables (by using 
    # E_a^{(k)} = E_a^n/[k]_a!
    
    for k in [1..Length(mm[2])] do
        rel:= List( mm[2][k][2], ShallowCopy );
        for i in [1,3..Length(rel)-1] do
            for j in [1,3..Length(rel[i])-1] do
                qp:= _q^( mm[1][ rel[i][j] ]*(B*mm[1][rel[i][j]])/2);
                rel[i][j]:= rel[i][j] + n + rank; 
                rel[i+1]:= rel[i+1]*
                           GaussianFactorial(rel[i][j+1],qp);
            od;
        od; 

        ii:= mm[2][k][1];
        tt[ii[1]+rank+n][ii[2]+rank+n]:= rel;
    od;
    
    for k in [1..Length(Ftab)] do
        rel:= List( Ftab[k][2], ShallowCopy );
        for i in [1,3..Length(rel)-1] do
            for j in [1,3..Length(rel[i])-1] do
                qp:= _q^( mm[1][ rel[i][j] ]*(B*mm[1][rel[i][j]])/2); 
                rel[i+1]:= rel[i+1]*
                           GaussianFactorial(rel[i][j+1],qp);
            od;
        od; 
        tt[Ftab[k][1][1]][Ftab[k][1][2]]:= rel;
    od;
    
    for k in [1..Length(FEtab)] do
        rel:= List( FEtab[k][2], ShallowCopy );
        for i in [1,3..Length(rel)-1] do
            for j in [1,3..Length(rel[i])-1] do
                if rel[i][j] <= n then
                    qp:= _q^( mm[1][ rel[i][j] ]*
                             (B*mm[1][rel[i][j]])/2); 
                    rel[i+1]:= rel[i+1]*
                               GaussianFactorial(rel[i][j+1],qp);
                fi;
                
                if rel[i][j] > n+rank then
                    qp:= _q^( mm[1][ rel[i][j]-n-rank ]*
                             (B*mm[1][rel[i][j]-n-rank])/2); 
                    rel[i+1]:= rel[i+1]*
                               GaussianFactorial(rel[i][j+1],qp);
                fi;                         
            od;
        od;                    
        tt[FEtab[k][1][1]][FEtab[k][1][2]]:= 
                    normalise_rel( n, rank, B, rel );
    od;              
        
    fam!.multTab:= tt;

    fam!.quantumPar:= _q;
    
    # Finally construct the generators.

    gens:= [ ];
    for i in [1..n] do
        gens[i]:= ObjByExtRep( fam, [ [ i, 1 ], _q^0 ] );
    od;
    for i in [1..Length( CartanMatrix(R) )] do
        Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 1 ], 0 ], _q^0 ] ) );
        qp:= _q^(B[i][i]/2);
        
        # we need to sort the monomials in K^-1, to accomodate
        # for changes in the sorting algorithm, which may lead to
        # surprises otherwise...
        if [ [n+i,1], 0 ] < [ [ n+i, 0 ], 1 ] then
            Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 1 ], 0 ], _q^0, 
                    [ [ n+i, 0 ], 1 ], qp^-1-qp ] ) );
        else
            Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 0 ], 1 ], qp^-1-qp, 
                    [ [ n+i, 1 ], 0 ], _q^0 ] ) );
        fi;
        
    od;
    for i in [1..n] do
        Add( gens, ObjByExtRep( fam, 
                [ [ n+Length(CartanMatrix(R)) +i, 1 ], _q^0 ] ) );
    od;
    
    A:= Objectify( NewType( CollectionsFamily( FamilyObj( gens[1] ) ),
                                IsMagmaRingModuloRelations
                            and IsQuantumUEA
                            and IsGenericQUEA
                            and IsAttributeStoringRep ),
                   rec() );
    SetIsAssociative( A, true );
    SetLeftActingDomain( A, QuantumField );
    SetGeneratorsOfLeftOperatorRing( A, gens );
    SetGeneratorsOfLeftOperatorRingWithOne( A, gens );
    SetOne( A, gens[1]^0 );
    SetRootSystem( A, R );
    SetQuantumParameter( A, _q );

    # add a pointer to `A' to the family of the generators:
    fam!.qAlgebra:= A;
    
    return A;
end);

#########################################################################
##
#M  QuantizedUEA( <R> )
##
InstallOtherMethod( QuantizedUEA,
        "for a root system a ring, and a parameter",
        true, [ IsRootSystem, IsField, IsObject ], 0,
        function( R, F, v )
    
    local   n,  rank,  B,  fam,  tt,  tt_new,  k,  rel,  i,  
            j,  qp,  gens,  A,  uu;    


    n:= Length(PositiveRoots(R));
    rank:= Length( CartanMatrix(R) );
    B:= BilinearFormMatNF( R );
    
    fam:= NewFamily( "QEAEltFam", IsQEAElement );
    fam!.packedQEAElementDefaultType:=
                  NewType( fam, IsPackedElementDefaultRep );
    fam!.noPosRoots:= Length( PositiveRoots(R) );
    fam!.rank:= Length( CartanMatrix(R) );
    fam!.rootSystem:= R;
    
    uu:= QuantizedUEA( R );

    fam!.genericQUEA:= uu;

    tt:= ElementsFamily( FamilyObj( uu ) )!.multTab;
    # copy tt and substitute v for q:
    tt_new:= List([1..n], x -> [] );  
    for k in [1..n] do
        tt_new[k+rank+n]:= [];
    od;
    for i in [1..Length(tt)] do
        if IsBound( tt[i] ) then
           for j in [1..Length(tt[i]) ] do
               if IsBound( tt[i][j] ) then
                  rel:= List( tt[i][j], ShallowCopy );
                  for k in [2,4..Length(rel)] do
                      rel[k]:= Value( rel[k], v );
                  od;
                  tt_new[i][j]:= rel;
               fi;
           od;
        fi;
    od;

    fam!.multTab:= tt_new;

    # some more data:
    fam!.convexRoots:= ElementsFamily( FamilyObj( uu ) )!.convexRoots;
    fam!.quantumPar:= v;
 
    # Finally construct the generators.

    gens:= [ ];
    for i in [1..n] do
        gens[i]:= ObjByExtRep( fam, [ [ i, 1 ], v^0 ] );
    od;
    for i in [1..Length( CartanMatrix(R) )] do
        Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 1 ], 0 ], v^0 ] ) );
        qp:= v^(B[i][i]/2);
        if IsZero( qp^-1-qp ) then
           Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 1 ], 0 ], qp^0 ] ) );
       else
           # we need to sort the monomials in K^-1, to accomodate
            # for changes in the sorting algorithm, which may lead to
            # surprises otherwise...
           if [ [n+i,1], 0 ] < [ [ n+i, 0 ], 1 ] then
               Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 1 ], 0 ], qp^0, 
                       [ [ n+i, 0 ], 1 ], qp^-1-qp ] ) );
           else
               Add( gens,  ObjByExtRep( fam, [ [ [ n+i, 0 ], 1 ], qp^-1-qp, 
                       [ [ n+i, 1 ], 0 ], qp^0 ] ) );
           fi;
        fi;
    od;
    for i in [1..n] do
        Add( gens, ObjByExtRep( fam, 
                [ [ n+Length(CartanMatrix(R)) +i, 1 ], v^0 ] ) );
    od;
    
    A:= Objectify( NewType( CollectionsFamily( FamilyObj( gens[1] ) ),
                                IsMagmaRingModuloRelations
                            and IsQuantumUEA
                            and IsAttributeStoringRep ),
                   rec() );
    SetIsAssociative( A, true );
    SetLeftActingDomain( A, F );
    SetGeneratorsOfLeftOperatorRing( A, gens );
    SetGeneratorsOfLeftOperatorRingWithOne( A, gens );
    SetOne( A, gens[1]^0 );
    SetRootSystem( A, R );
    SetQuantumParameter( A, v );
    
    # add a pointer to `A' to the family of the generators:
    fam!.qAlgebra:= A;
    
    return A;
end);

#########################################################################
##
#M  QuantizedUEA( <L> )
##
InstallOtherMethod( QuantizedUEA,
        "for a semisimple Lie algebra",
        true, [ IsLieAlgebra ], 0,
        function( L )
    return QuantizedUEA( RootSystem(L) );
end );

#########################################################################
##
#M  QuantizedUEA( <L> )
##
InstallOtherMethod( QuantizedUEA,
        "for a semisimple Lie algebra, a ring and a parameter",
        true, [ IsLieAlgebra, IsField, IsObject ], 0,
        function( L, F, qp )
    return QuantizedUEA( RootSystem(L), F, qp );
end );

############################################################################
##
#M  PrintObj( <QA> )
#M  ViewObj( <QA> )
##
InstallMethod( PrintObj,
        "for a QuantumUEA",
        true, [ IsQuantumUEA ], 0,
        
        function( A )
    
    Print("QuantumUEA( ",RootSystem(A),", Qpar = ",QuantumParameter(A)," )" );
end );

InstallMethod( ViewObj,
        "for a QuantumUEA",
        true, [ IsQuantumUEA ], 0,
        
        function( A )
    
    PrintObj( A );
end );

#############################################################################
##
#M  LeadingUEALatticeMonomial( <novar>, <f> )
##
##
InstallMethod( LeadingQEAMonomial,
        "for an integer and a QEA element",
        true, [ IS_INT, IsQEAElement ], 0,

        function ( novar, p )

    local e,max,cf,m,n,j,k,o,pos,deg,ind, degn;

    # Reverse lexicographical ordering...

    e:= p![1];
    max:= e[1];
    ind:= 1;
    cf:= e[2];
    m:= ListWithIdenticalEntries( novar, 0 );
    for k in [1,3..Length(max)-1] do
        m[max[k]]:= max[k+1];
    od;

    for k in [3,5..Length(e)-1] do

        n:= ListWithIdenticalEntries( novar, 0 );
        for j in [1,3..Length(e[k])-1] do
            n[e[k][j]]:= e[k][j+1];
        od;

        o:= n-m;
        
        # pos will be the last nonzero position
        pos:= PositionProperty( Reversed(o), x -> x <> 0 );
        pos:= novar-pos+1;
        if o[pos] > 0 then
            max:= e[k];
            ind := k;
            cf:= e[k+1];
            m:= n;
        fi;
    od;

    return [max, m, cf, ind];
end );


#############################################################################
##
#F  LeftReduceQEEALatticeElement( <novar>, <G>, <lms>, <lmtab>, <p> )
##
##
##
InstallGlobalFunction( LeftReduceQEAElement,
        function( novar, G, lms, lmtab, p )

    local   fam,  reduced,  rem,  res,  m1,  k,  g,  diff,  cme,  mon,  
            cflmg,  j,  fac,  fac1,  cf,  lm;

    # We left-reduce the QUEA element `p' modulo the elements in `G'.
    # Here `lms' is a list of leading monomial-indices; if the index `k'
    # occurs somewhere in `lms', then g![1][k] is the leading monomial
    # of `g', where `g' is the corresponding element of `G'. `novar'
    # is the number of variables.

    fam:= FamilyObj( p );
    reduced:= false;
    rem:= p;
    res:= 0*p;

    while rem <> 0*rem do

        m1:= LeadingQEAMonomial( novar, rem );
        k:= 1;
            
        k:= Search( lmtab, m1[2] );
        if k <> fail then
            
            g:= G[k];
            diff:= ShallowCopy( m1[2] );
            cme:= g![1];
            mon:= cme[ lms[k] ];
            cflmg:= cme[ lms[k]+1 ];
            for j in [1,3..Length(mon)-1] do
                diff[mon[j]]:= diff[mon[j]] - mon[j+1];
            od;

            fac:= [ ];
            for j in [1..novar] do
                if diff[j] <> 0 then
                    Add( fac, j ); Add( fac, diff[j] );
                fi;
            od;
            fac1:= ObjByExtRep( fam, [ fac, _q^0 ] )*g;
            cf:= LeadingQEAMonomial( novar, fac1 )[3];
            rem:= rem - (m1[3]/cf)*fac1;
            
        else
            lm:= ObjByExtRep( fam, [ m1[1], m1[3] ] );
            res:= res + lm;
            rem:= rem-lm; 
        fi;
        
            
    od;

    return res;

end );


QGPrivateFunctions.ActionCollect:=
        function( sim, rts, B, s, rank, Mtab, qpar, expr )

    # `sim' are the simple roots.
    # `rts' are the roots in convex order.
    # `B' is the matrix of the bilinear form.
    # `s' is the number of positive roots.
    # `rank' is the rank of the root system.
    # `Mtab' is the multiplication table.
    # `qpar' is the quantum parameter.
    # `expr' is the thing that needs to be collected.

    # Does the same as normal collection, except that monomials
    # ending on an E are immediately discarded, and K-elements are
    # not normalised...
    
    local   comm_rule,  todo,  res,  m,  cf,  k,  found,  pos,  k1,  
            k2,  r,  rel,  start,  tail,  i,  mn,  m1,  j, qp, coef, 
            list1, list2;

    comm_rule:= function( rel, j, i, m, n, r )
        
        # commutation rule for x_j^mx_i^n, where x_jx_i=qpar^rx_ix_j+rel
        
        local   rule,  l,  k,  cf,  u,  mn, start, tail, qi, qj, den, t;
        
        if j > s + rank then
            qj:= qpar^( rts[j-s-rank]*( B*rts[j-s-rank] )/2 );
        else
            qj:= qpar^( rts[j]*( B*rts[j] )/2 );
        fi;
        if i > s +rank then
            qi:= qpar^( rts[i-s-rank]*( B*rts[i-s-rank] )/2 );
        else
            qi:= qpar^( rts[i]*( B*rts[i] )/2 );
        fi;
        
        den:= GaussianFactorial( m, qj )*GaussianFactorial( n, qi );

        rule:= [ [ i, n, j, m], qpar^(n*m*r) ];
        for l in [0..n-1] do
            for k in [0..m-1] do
                cf:= qpar^((l*m+k)*r)/den;
                start:= [ ];
                if l <> 0 then
                    Add( start, i ); Add( start, l );
                    cf:= cf*GaussianFactorial( l, qi );
                fi;
                if m-1-k <> 0 then
                    Add( start, j ); Add( start, m-1-k );
                    cf:= cf*GaussianFactorial( m-1-k, qj );
                fi;
                tail:= [];
                if k <> 0 then
                    Add( tail, j ); Add( tail, k );
                    cf:= cf*GaussianFactorial( k, qj );
                fi;
                if n-1-l <> 0 then
                    Add( tail, i ); Add( tail, n-1-l );
                    cf:= cf*GaussianFactorial( n-1-l, qi );
                fi;

                for u in [1,3..Length(rel)-1] do
                    mn:= ShallowCopy( start );
                    Append( mn, rel[u] );
                    Append( mn, tail );
                    Add( rule, mn ); Add( rule, cf*rel[u+1] );
                od;
            od;
        od;

        return rule;
    end;
    
    # In the program we use ... [ i, d, a ], s ... for
    #
    #       / Ki; a \
    #  Ki^d |       |
    #       \   s   /
    #

    todo:= expr;

    for k in [1,3..Length(todo)-1] do
        for i in [1,3..Length(todo[k])-1] do
            if IsList( todo[k][i] ) and Length( todo[k][i] ) = 2 then
               todo[k][i]:= ShallowCopy( todo[k][i] );
               Add( todo[k][i], 0 );
            fi;
        od;
    od;

    res:= [ ];
    while todo <> [] do

        found:= false;
        while todo <> [] and not found do
           m:= todo[1];
           cf:= todo[2];
           if m = [ ] then
              found:= true;
              break;
           fi;
           k:= m[Length(m)-1];
           if IsList( k ) or k <= s then
              # m ends with K or F:
              found:= true;
           else
              Unbind( todo[1] ); Unbind( todo[2] );
              todo:= Filtered( todo, x -> IsBound(x) );
           fi;
        od;
        if todo = [ ] then break; fi;

        for i in [1,3..Length(m)-1] do
            if IsList( m[i] ) and Length( m[i] ) = 2 then
               m[i]:= ShallowCopy( m[i] );
               Add( m[i], 0 );
            fi;
        od;

        # We try to find indices in the `wrong' order.

        k:= 1; found:= false;
        while k < Length(m)-2 do

            if IsList( m[k] ) then
               k1:= m[k][1];
               list1:= true;
            else
               k1:= m[k];
               list1:= false;
            fi;
            if IsList( m[k+2] ) then
               k2:= m[k+2][1];
               list2:= true;
            else
               k2:= m[k+2];
               list2:= false;
            fi;

            if k1 > k2 then
                found:= true;
                break;
            elif k1 = k2 then

                if not list1 then
                
                   if m[k] <= s then
                       qp:= qpar^( rts[m[k]]*(B*rts[m[k]])/2 );
                       cf:= cf*GaussianBinomial( m[k+1]+m[k+3], m[k+1], qp );
                   fi;
                
                   if m[k] > s + rank then
                       qp:= qpar^( rts[m[k]-s-rank]*(B*rts[m[k]-s-rank])/2 );
                       cf:= cf*GaussianBinomial( m[k+1]+m[k+3], m[k+1], qp );
                   fi; 
                
                   m[k+1]:= m[k+1]+m[k+3];
                
                   if m[k+1] = 0*m[k+1] then
                       Unbind( m[k] ); Unbind( m[k+1] );
                       Unbind( m[k+2] ); Unbind( m[k+3] );
                       m:= Filtered( m, x -> IsBound(x) );
                       if k > 1 then
                        
                           # there is a new elt on pos k, we have to check
                           # whether it is in the correct order with 
                           # the previous element.
                           k:= k-2;
                       fi;
                   else
                       Unbind( m[k+2] ); Unbind( m[k+3] );
                       m:= Filtered( m, x -> IsBound(x) );
                   fi;
                else
                   # both are K-elements, coming from the same K_{\alpha}
                   # we do nothing (for the moment).
                   k:= k+2;
                fi;
            else
                k:= k+2;
            fi;
            
        od;

        if not found then

            # We add the monomial to `res'. 

            pos:= Position( res, m );
            if pos <> fail then
               res[pos+1]:= res[pos+1]+cf;
               if res[pos+1] = 0*cf then
                  Unbind( res[pos] ); Unbind( res[pos+1] );
                  res:= Filtered( res, x -> IsBound(x) );
               fi;
            else    
               Add( res, m );
               Add( res, cf );
            fi;

            Unbind( todo[1] );
            Unbind( todo[2] );
            todo:= Filtered( todo, x -> IsBound(x) );
        else
            
            # we know k1 > k2...
            
            if k1 > s+rank then
                
                # i.e., k1 is an E
                
                if k2 > s+rank then
                    
                    # i.e., k2 is also an E, commutation from Mtab
                    
                    r:= rts[k1-s-rank]*( B*rts[k2-s-rank]);
                    
                    rel:= comm_rule( Mtab[k1][k2], m[k], m[k+2], 
                                  m[k+1], m[k+3], -r );
                    start:= m{[1..k-1]};
                    tail:= m{[k+4..Length(m)]};

                    for i in [1,3..Length(rel)-1] do
                        mn:= ShallowCopy( start );
                        Append( mn, rel[i] ); Append( mn, tail );
                        if i = 1 then
                            todo[1]:= mn;
                            todo[2]:= cf*rel[i+1];
                        else
                            Add( todo, mn ); Add( todo, cf*rel[i+1] );
                        fi;

                    od;
                    
                elif k2 > s then

                    # i.e., k2 is a K:
                    r:= -2*rts[k1-s-rank]*( B*sim[k2-s] )/B[k2-s][k2-s];
                    r:= r*m[k+1];
                    qp:= qpar^(B[k2-s][k2-s]/2);
                    coef:= qp^(r*m[k+2][2]);
                    mn:= m{[1..k-1]};
                    Add( mn, ShallowCopy(m[k+2]) );
                    mn[k][3]:= mn[k][3] + r; 
                    Add( mn, m[k+3] );
                    Add( mn, m[k] ); Add( mn, m[k+1] );
                    Append( mn,m{[k+4..Length(m)]} );
                    todo[1]:= mn;
                    todo[2]:= cf*coef;

                else
                    # k2 is an F, commutation from Mtab
                    
                    rel:= comm_rule( Mtab[k1][k2], m[k], m[k+2], 
                                  m[k+1], m[k+3], 0 );
                    start:= m{[1..k-1]};
                    tail:= m{[k+4..Length(m)]};
                    
                    for i in [1,3..Length(rel)-1] do
                        mn:= ShallowCopy( start );
                        Append( mn, rel[i] ); Append( mn, tail );
                        if i = 1 then
                            todo[1]:= mn;
                            todo[2]:= cf;
                        else
                            Add( todo, mn ); Add( todo, cf*rel[i+1] );
                        fi;
                        
                    od;                        
                    
                fi;
            elif k1 > s then
                    
                # i.e., k1 is a K, 
                
                if k2 > s then
                    
                    # i.e., k2 is also a K; they commute
                    
                    mn:= m{[1..k-1]};
                    Add( mn, m[k+2] ); Add( mn, m[k+3] );
                    Add( mn, m[k] ); Add( mn, m[k+1] );
                    Append( mn,m{[k+4..Length(m)]} );
                    todo[1]:= mn;
                    todo[2]:= cf;
                else
                    
                    # i.e., k2 is an F:

                    r:= -2*rts[k2]*( B*sim[k1-s] )/B[k1-s][k1-s];
                    r:= r*m[k+3];
                    qp:= qpar^(B[k1-s][k1-s]/2);
                    coef:= qp^(r*m[k][2]);
                    mn:= m{[1..k-1]};
                    Add( mn, m[k+2] );
                    Add( mn, m[k+3] );
                    Add( mn, ShallowCopy(m[k]) );
                    mn[k+2][3]:= mn[k+2][3] + r; 
                    Add( mn, m[k+1] );
                    Append( mn,m{[k+4..Length(m)]} );
                    todo[1]:= mn;
                    todo[2]:= cf*coef;

                fi;
            else
                # i.e., k1, k2 are both F's. 
                # commutation from Mtab
                
                r:= rts[k1]*( B*rts[k2]);
                
                rel:= comm_rule( Mtab[k1][k2], m[k], m[k+2], 
                                  m[k+1], m[k+3], -r );
                start:= m{[1..k-1]};
                tail:= m{[k+4..Length(m)]};
                        
                for i in [1,3..Length(rel)-1] do
                    mn:= ShallowCopy( start );
                    Append( mn, rel[i] ); Append( mn, tail );
                    if i = 1 then
                        todo[1]:= mn; todo[2]:= cf*rel[i+1];
                    else
                        Add( todo, mn ); Add( todo, cf*rel[i+1] );
                    fi;
                    
                od;
                
                
            fi;
            
        fi;
    od;

    return res;
end;


QGPrivateFunctions.Calc_Image:=  function( qpar, x, v )

        # a function for calculating the image of v under x. This is used
        # at the end for calculating a list of images of the generators,
        # if the dimension of the module is not too big. 
        # If the dimension is higher,
        # then this function is also called from the method for \^.

         local   rank,  s,  hw,  ev,  qelm,  ee,  eres,  k,  i,  cf,  pos,  
                 gb,  p,  wvecs,  mons,  cfts,  ep,  im, B, ind, qp,
                 ex, fam, R, m, j;
    
         if IsZero( v ) then return v; fi;
         rank:= FamilyObj( x )!.rank;
         s:= FamilyObj( x )!.noPosRoots;
         hw:= FamilyObj( v )!.highestWeight;
    
         B:= BilinearFormMatNF( FamilyObj( x )!.rootSystem );
    
         # qelm will be x*v1, where v1 is the corresponding element in U^-
         # (corresponding to v). We reduce this element modulo the Groebner
         # basis.
         ev:= ExtRepOfObj( v );    
         qelm:= Sum( [1,3..Length(ev)-1], ii -> ev[ii+1]*ev[ii][2] );
         qelm:= ExtRepOfObj( qelm );
         ex:= ExtRepOfObj( x );

         # We build the expression that needs to be collected.

         ee:= [ ];
         for i in [1,3..Length(ex)-1] do
            for j in [1,3..Length(qelm)-1] do
               m:= ShallowCopy( ex[i] );
               Append( m, qelm[j] );
               Add( ee, m );
               Add( ee, ex[i+1]*qelm[j+1] );
           od;
         od;    

         fam:= FamilyObj(x);
         R:= fam!.rootSystem;

         # We collect it.

         ee:= QGPrivateFunctions.ActionCollect(SimpleSystemNF(R), 
                   fam!.convexRoots, 
                   BilinearFormMatNF(R), fam!.noPosRoots, fam!.rank, 
                   fam!.multTab, fam!.quantumPar, ee );

         eres:= [ ];
         for k in [1,3..Length(ee)-1] do
        
            if ee[k] = [] then
            
               # i.e., the monomial is 1, can go straight to eres
               pos:= Position( eres, ee[k] );
               if pos = fail then
                  Add( eres, ee[k] ); Add( eres, ee[k+1] );
               else
                  eres[pos+1]:= eres[pos+1]+ee[k+1];
--> --------------------

--> maximum size reached

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

[ Verzeichnis aufwärts0.94unsichere Verbindung  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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