/****************************************************************************
**
*A  polynom.c                    GAP source                      Frank Celler
**
*H  @(#)$Id: polynom.c,v 3.19 1994/05/06 13:20:03 fceller Rel $
**
*Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
**
*H  $Log: polynom.c,v $
*H  Revision 3.19  1994/05/06  13:20:03  fceller
*H  removed unused variable
*H
*H  Revision 3.18  1994/02/07  14:11:32  fceller
*H  changed interface slightly,  the functions now accept list with
*H  mixed entries and they will not automatically shorten the result
*H
*H  Revision 3.17  1993/10/15  09:09:50  martin
*H  added 'register' to circumvent a MPW C compiler bug
*H
*H  Revision 3.16  1993/06/02  11:37:13  fceller
*H  added 'ProductsCoeffsMod', renamed 'ReduceModCoeffs' to 'ReduceCoeffsMod'
*H
*H  Revision 3.15  1993/05/05  11:11:43  fceller
*H  replace a wrong 'TYPE' by 'XType'
*H
*H  Revision 3.14  1993/03/01  10:33:13  fceller
*H  adapted to new list concept
*H
*H  Revision 3.13  1993/02/11  17:08:55  fceller
*H  removed creation of T_VECTOR of length 4
*H
*H  Revision 3.12  1993/02/04  18:20:32  martin
*H  fixed 'PowerModVecInt' from passing wrong degree to 'MultiplyVector'
*H
*H  Revision 3.11  1993/02/04  10:51:10  martin
*H  changed to use 'plist' interface
*H
*H  Revision 3.10  1993/01/06  17:53:39  fceller
*H  removed creation of T_VECFFE of length 4
*H
*H  Revision 3.9  1992/11/25  11:28:50  fceller
*H  fixed a bug in 'UnifyFFE'
*H
*H  Revision 3.8  1992/11/16  17:49:35  fceller
*H  added 'ReduceCoeffs' and 'ShiftedCoeffs'
*H
*H  Revision 3.7  1992/08/20  10:56:59  fceller
*H  pleased GCC
*H
*H  Revision 3.6  1992/08/17  11:18:46  fceller
*H  fixed handling of empty lists in 'AddCoeffs'
*H
*H  Revision 3.5  1992/07/06  08:09:09  fceller
*H  fixed a typo
*H
*H  Revision 3.4  1992/07/02  11:06:19  fceller
*H  add 'AddCoeffs'
*H
*H  Revision 3.3  1992/07/02  10:09:00  fceller
*H  add 'SumCoeffs'
*H
*H  Revision 3.2  1992/05/25  08:56:08  fceller
*H  Initial GAP 3.2 release
*/
#include        "system.h"              /* system dependent functions      */
#include        "gasman.h"              /* dynamic storage manager         */
#include        "scanner.h"             /* reading of tokens and printing  */
#include        "eval.h"                /* evaluator main dispatcher       */
#include        "integer.h"             /* arbitrary size integers         */
#include        "finfield.h"            /* finite field package            */
#include        "list.h"                /* generic list package            */
#include        "plist.h"               /* plain list package              */
#include        "vector.h"              /* vector package                  */
#include        "vecffe.h"              /* finite field vector package     */

#include        "polynom.h"             /* polynomial package              */


/****************************************************************************
**
*F  UnifiedFieldVecFFE( <hdL>, <hdR> )	. . . unify fields of <hdL> and <hdR>
**
**  Convert two finite field vectors into finite field vectors over  the same
**  finite field.  Signal an error if this conversion fails.
*/
TypHandle UnifiedFieldVecFFE ( hdL,  hdR )
    TypHandle	    hdL;	        /* first finite field vector       */
    TypHandle       hdR;                /* second finite field vector      */
{
    TypHandle           hdFld;          /* handle of the field             */
    unsigned long       p;              /* characteristic                  */
    unsigned long       q;              /* size of common finite field     */
    unsigned long       q1;             /* size of field of row            */
    unsigned long       dl;             /* degree of <hdL>                 */
    unsigned long       dr;             /* degree of <hdR>                 */
    TypHandle           hdElm;          /* one row of the list             */
    TypFFE              v;              /* value of one element            */
    unsigned long       i, k;           /* loop variables                  */

    /* if <hdL> and <hdR> have already the same field return               */
    if ( FLD_VECFFE(hdL) == FLD_VECFFE(hdR) )
	return FLD_VECFFE(hdL);

    /* check the we know a common superfield of <hdL> and <hdR>            */
    p = CharVecFFE(hdL);
    if ( p != CharVecFFE(hdR) )
	return Error( "vectors have different characteristic", 0L, 0L );

    /* compute degree of superfield                                        */
    dl = DegreeVecFFE(hdL);
    dr = DegreeVecFFE(hdR);
    for ( k = dl;  dl % dr != 0;  dl += k )  ;

    /* make sure we can handle this field                                  */
    if ( (  2 <= p && 17 <= dl ) || (   3 <= p && 11 <= dl )
      || (  5 <= p &&  7 <= dl ) || (   7 <= p &&  6 <= dl )
      || ( 11 <= p &&  5 <= dl ) || (  17 <= p &&  4 <= dl )
      || ( 41 <= p &&  3 <= dl ) || ( 257 <= p &&  2 <= dl ) )
    {
	return Error( "common superfield is too large", 0L, 0L );
    }

    /* get a field that contains all elements                              */
    for ( q = 1, k = 1;  k <= dl;  k++ )  q *= p;
    if ( (SIZE_FF(FLD_VECFFE(hdL))-1) % (q-1) == 0 )
	hdFld = FLD_VECFFE(hdL);
    else if ( (SIZE_FF(FLD_VECFFE(hdR))-1) % (q-1) == 0 )
	hdFld = FLD_VECFFE(hdR);
    else
	hdFld = FLD_FFE( RootFiniteField( q ) );
    q = SIZE_FF(hdFld);

    /* convert <hdL> and <hdR>                                             */
    for ( i = 0;  i <= 1;  i++ )
    {
	hdElm = ( i == 0 ) ? hdL : hdR;
	if ( FLD_VECFFE(hdElm) != hdFld )
	{
	    q1 = SIZE_FF( FLD_VECFFE(hdElm) );
	    for ( k = LEN_VECFFE(hdElm);  0 < k;  k-- )
	    {
		v = VAL_VECFFE( hdElm, k );
		SET_VAL_VECFFE( hdElm, k, v==0 ? v : (v-1)*(q-1)/(q1-1)+1 );
	    }
	    SET_FLD_VECFFE( hdElm, hdFld );
	}
    }

    /* and return the common                                               */
    return FLD_VECFFE(hdL);
}


/****************************************************************************
**
*F  FunShiftedCoeffs( <hdCall> )  . . . . . internal function 'ShiftedCoeffs'
**
**  'FunShiftedCoeffs' implements 'ShiftedCoeffs( <l>, <n> )'
*/
TypHandle (*TabShiftedCoeffs[T_VAR]) P(( TypHandle, long ));

TypHandle FunShiftedCoeffs ( hdCall )
    TypHandle       	hdCall;
{
    TypHandle       	hdC;		/* coeffs list                     */
    TypHandle       	hdN;		/* number of shifts                */

    /* check arguments                                                     */
    if ( SIZE(hdCall) != 3 * SIZE_HD )
        return Error( "usage: ShiftedCoeffs( <c>, <nr> )", 0L, 0L );
    hdC = EVAL( PTR(hdCall)[1] );
    hdN = EVAL( PTR(hdCall)[2] );
    if ( TYPE(hdN) != T_INT )
	return Error( "<nr> must be an integer", 0L, 0L );

    /* jump through the table                                              */
    return TabShiftedCoeffs[XType(hdC)]( hdC, HD_TO_INT(hdN) );
}

TypHandle CantShiftedCoeffs ( hdList, n )
    TypHandle           hdList;
    long                n;
{
    return Error( "<list> must be a vector", 0L, 0L );
}

TypHandle ShiftedCoeffsListx ( hdC, n )
    TypHandle		hdC;
    long		n;
{
    TypHandle		hdS;		/* result                          */
    TypHandle		hdZero;		/* zero element                    */
    long                l;		/* length of <hdC>                 */
    long                i;

    /* compute the length of <hdC>                                         */
    l = LEN_LIST(hdC);
    if ( l == 0 )
	hdS = Copy(hdC);

    /* if <n> is negative shrink <hdC>                                     */
    else if ( n < 0 ) {

	/* if <l> is not bigger than <n>,  <hdC> will shrink to nothing    */
	if ( l <= -n ) {
	    hdS = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	    SET_LEN_PLIST( hdS, 0 );
	    return hdS;
	}

	/* allocate a new vector and copy the entries                      */
	hdS = NewBag( T_LIST, SIZE_PLEN_PLIST(l+n) );
	SET_LEN_PLIST( hdS, l+n );
	for ( i = l;  -n < i;  i-- )
	    SET_ELM_PLIST( hdS, i+n, ELM_PLIST(hdC,i) );
    }

    /* if <n> is positive, copy entries and leading zero                   */
    else if ( 0 < n ) {
	hdS = NewBag( T_LIST, SIZE_PLEN_PLIST(l+n) );
	SET_LEN_PLIST( hdS, l+n );
	for ( i = l;  0 < i;  i-- )
	    SET_ELM_PLIST( hdS, i+n, ELM_PLIST(hdC,i) );
	hdZero = PROD( ELML_LIST(hdC,1), INT_TO_HD(0) );
	for ( i = n;  0 < i;  i-- )
	    SET_ELM_PLIST( hdS, i, hdZero );
    }

    /* if <n> is zero, return a copy of <hdC>                              */
    else
	hdS = Copy(hdC);

    /* return <hdS>                                                        */
    return hdS;
}

TypHandle ShiftedCoeffsVecFFE ( hdC, n )
    TypHandle		hdC;
    long		n;
{
    TypHandle		hdS;		/* result                          */
    TypFFE		tmp;		/* temporary                       */
    long                l;		/* length of <hdC>                 */
    long                i;

    /* compute the length of <hdC>                                         */
    l = LEN_VECFFE(hdC);

    /* if <n> is negative shrink <hdL>                                     */
    if ( n < 0 ) {

	/* if <l> is not bigger than <n>, <hdL> will shrink to nothing     */
	if ( l <= -n ) {
	    hdS = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	    SET_LEN_PLIST( hdS, 0 );
	    return hdS;
	}

	/* allocate a new vector and copy the entries                      */
	hdS = NewBag( T_VECFFE, SIZE_PLEN_VECFFE(l+n) );
	SET_FLD_VECFFE( hdS, FLD_VECFFE(hdC) );
	for ( i = l;  -n < i;  i-- ) {
	    tmp = VAL_VECFFE( hdC, i );
	    SET_VAL_VECFFE( hdS, i+n, tmp );
	}
    }

    /* if <n> is positive, copy <hdC> and leading zeros                    */
    else if ( 0 < n )
    {
	hdS = NewBag( T_VECFFE, SIZE_PLEN_VECFFE(l+n) );
	SET_FLD_VECFFE( hdS, FLD_VECFFE(hdC) );
	for ( i = l;  0 < i;  i-- ) {
	    tmp = VAL_VECFFE( hdC, i );
	    SET_VAL_VECFFE( hdS, i+n, tmp );
	}
	for ( i = n;  0 < i;  i-- )
	    SET_VAL_VECFFE( hdS, i, 0 );
    }

    /* if <n> is zero, copy <hdL> and shrink if necessary                  */
    else
	hdS = Copy(hdC);
    return hdS;
}


/****************************************************************************
**
*F  FunNormalizeCoeffs( <hdCall> )  . . . internal function 'NormalizeCoeffs'
**
**  'FunNormalizeCoeffs' implements 'NormalizeCoeffs( <c> )'
*/
TypHandle (*TabNormalizeCoeffs[T_VAR]) P(( TypHandle ));

TypHandle FunNormalizeCoeffs ( hdCall )
    TypHandle       hdCall;
{
    TypHandle       hdC;

    /* check arguments                                                     */
    if ( SIZE( hdCall ) != 2 * SIZE_HD )
        return Error( "usage: NormalizeCoeffs( <c> )", 0L, 0L );
    hdC = EVAL( PTR(hdCall)[1] );

    /* jump through the table                                              */
    return TabNormalizeCoeffs[XType(hdC)]( hdC );
}

TypHandle CantNormalizeCoeffs ( hdList )
    TypHandle           hdList;
{
    return Error( "<list> must be a vector", 0L, 0L );
}

TypHandle NormalizeCoeffsVecFFE ( hdC )
    TypHandle		hdC;
{
    TypFFE		tmp;            /* temporary                       */
    long		len;		/* length of <hdC>                 */
    long		l1;		/* first non zero entry            */
    long		l2;		/* last non zero entry             */
    long		i;		/* loop                            */

    /* check for leading zeros                                             */
    len = LEN_VECFFE(hdC);
    for ( l1 = 1;  l1 <= len;  l1++ )
	if ( VAL_VECFFE( hdC, l1 ) != 0 )
	    break;

    /* check for trailing zero                                             */
    for ( l2 = len;  l1 < l2;  l2-- )
	if ( VAL_VECFFE( hdC, l2 ) != 0 )
	    break;

    /* if it is trivial, return empty list                                 */
    if ( l2 < l1 ) {
	Retype( hdC, T_LIST );
	Resize( hdC, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdC, 0 );
	return INT_TO_HD(0);
    }

    /* remove leadinf zeros                                                */
    if ( 1 < l1 )
	for ( i = l1;  i <= l2;  i++ ) {
	    tmp = VAL_VECFFE( hdC, i );
	    SET_VAL_VECFFE( hdC, i-l1+1, tmp );
	}

    /* shrink vector                                                       */
    Resize( hdC, SIZE_PLEN_VECFFE(l2-l1+1) );

    /* return the number of removed trailing zeros                         */
    return INT_TO_HD(l1-1);
}

TypHandle NormalizeCoeffsListx ( hdC )
    TypHandle		hdC;
{
    TypHandle		hdZero;         /* temporary                       */
    TypHandle		hdTmp;          /* temporary                       */
    long		len;		/* length of <hdC>                 */
    long		l1;		/* first non zero entry            */
    long		l2;		/* last non zero entry             */
    long		i;		/* loop                            */

    /* construct zero                                                      */
    if ( LEN_LIST(hdC) == 0 )
	return INT_TO_HD(0);
    hdZero = PROD( INT_TO_HD(0), ELM_LIST(hdC,1) );

    /* check for leading zeros                                             */
    len = LEN_LIST(hdC);
    for ( l1 = 1;  l1 <= len;  l1++ ) {
	hdTmp = ELML_LIST(hdC,l1);
	if ( EQ( hdTmp, hdZero ) == HdFalse )
	    break;
    }

    /* check for trailing zero                                             */
    for ( l2 = len;  l1 < l2;  l2-- ) {
	hdTmp = ELML_LIST(hdC,l2);
	if ( EQ( hdTmp, hdZero ) == HdFalse )
	    break;
    }

    /* if it is trivial, return empty list                                 */
    if ( l2 < l1 ) {
	Retype( hdC, T_LIST );
	Resize( hdC, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdC, 0 );
	return INT_TO_HD(0);
    }

    /* remove leading zeros                                                */
    if ( 1 < l1 )
	for ( i = l1;  i <= l2;  i++ ) {
	    hdTmp = ELML_LIST( hdC, i );
	    SET_ELM_PLIST( hdC, i-l1+1, hdTmp );
	}

    /* shrink vector                                                       */
    Resize( hdC, SIZE_PLEN_PLIST(l2-l1+1) );
    SET_LEN_PLIST( hdC, l2-l1+1 );

    /* return the number of removed trailing zeros                         */
    return INT_TO_HD(l1-1);
}


/****************************************************************************
**
*F  FunShrinkCoeffs( <hdCall> )  . . . . . . internal function 'ShrinkCoeffs'
**
**  'FunShrinkCoeffs' implements 'ShrinkCoeffs( <c> )'
*/
void (*TabShrinkCoeffs[T_VAR]) P(( TypHandle ));

TypHandle FunShrinkCoeffs ( hdCall )
    TypHandle       hdCall;
{
    TypHandle       hdC;

    /* check arguments                                                     */
    if ( SIZE( hdCall ) != 2 * SIZE_HD )
        return Error( "usage: ShrinkCoeffs( <c> )", 0L, 0L );
    hdC = EVAL( PTR(hdCall)[1] );

    /* jump through the table                                              */
    TabShrinkCoeffs[XType(hdC)]( hdC );
    return HdVoid;
}

void CantShrinkCoeffs ( hdList )
    TypHandle           hdList;
{
    Error( "<list> must be a vector", 0L, 0L );
}

void ShrinkCoeffsVecFFE ( hdC )
    TypHandle		hdC;
{
    long		len;		/* length of <hdC>                 */
    long		i;		/* loop                            */

    /* check for trailing zero                                             */
    len = LEN_VECFFE(hdC);
    for ( i = len;  0 < i;  i-- )
	if ( VAL_VECFFE( hdC, i ) != 0 )
	    break;

    /* if it is trivial, return empty list                                 */
    if ( 0 == i ) {
	Retype( hdC, T_LIST );
	Resize( hdC, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdC, 0 );
	return;
    }

    /* shrink vector                                                       */
    Resize( hdC, SIZE_PLEN_VECFFE(i) );
}

void ShrinkCoeffsListx ( hdC )
    TypHandle		hdC;
{
    TypHandle		hdZero;         /* temporary                       */
    TypHandle		hdTmp;          /* temporary                       */
    long		len;		/* length of <hdC>                 */
    long		i;		/* loop                            */

    /* construct zero                                                      */
    if ( LEN_LIST(hdC) == 0 )
	return;
    hdZero = PROD( INT_TO_HD(0), ELM_LIST(hdC,1) );

    /* check for trailing zero                                             */
    len = LEN_LIST(hdC);
    for ( i = len;  0 < i;  i-- ) {
	hdTmp = ELML_LIST(hdC,i);
	if ( EQ( hdTmp, hdZero ) == HdFalse )
	    break;
    }

    /* if it is trivial, return empty list                                 */
    if ( 0 == i ) {
	Retype( hdC, T_LIST );
	Resize( hdC, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdC, 0 );
	return;
    }

    /* shrink vector                                                       */
    Resize( hdC, SIZE_PLEN_PLIST(i) );
    SET_LEN_PLIST( hdC, i );
}


/****************************************************************************
**
*F  ADD_COEFFS( <hdL>, <hdR>, <hdM> ) . . . . . <hdL>+<hdM>*<hdR> into <hdL>
**
#define ADD_COEFFS( hdL, hdR, hdM ) \
    (TabAddCoeffs[XType(hdL)][XType(hdR)]( hdL, hdR, hdM ))
*/
void (*TabAddCoeffs[T_VAR][T_VAR]) P(( TypHandle, TypHandle, TypHandle ));

void CantAddCoeffs ( hdL, hdR, hdM )
    TypHandle		hdL;
    TypHandle		hdR;
    TypHandle       	hdM;
{
    Error("<l> and <r> must be vectors over a common field", 0L, 0L);
}

void AddCoeffsListxListx ( hdL, hdR, hdM )
    TypHandle		hdL;
    TypHandle		hdR;
    TypHandle       	hdM;
{
    TypHandle           hdLL;       /* one element of <hdL>                */
    TypHandle           hdRR;       /* one element of <hdR>                */
    TypHandle           hdAA;       /* sum of <hdLL> and <hdRR>            */
    long                l;          /* length of <hdL>                     */
    long                r;          /* length of <hdR>                     */
    long                m;          /* minimum of <l> and <r>              */
    long                i;          /* loop variables                      */

    /* compute the length of <hdL> and <hdR>                               */
    l = LEN_LIST(hdL);
    r = LEN_LIST(hdR);

    /* if <l> is less than <r>, enlarge <hdL>                              */
    if ( l < r ) {
	hdLL = PROD( ELML_LIST(hdR,1), INT_TO_HD(0) );
	for ( i = l+1;  i <= r;  i++ )
            ASS_LIST( hdL, i, hdLL );
	l = r;
    }

    /* add <hdR> to <hdL>                                                  */
    m = ( l < r ) ? l : r;
    if ( hdM == INT_TO_HD(1) ) {
	for ( i = 1;  i <= m;  i++ ) {
	    hdLL = ELM_LIST( hdL, i );
	    hdRR = ELM_LIST( hdR, i );
	    hdAA = SUM( hdLL, hdRR );
	    ASS_LIST( hdL, i, hdAA );
	}
	for ( i = m+1;  i <= r;  i++ ) {
	    hdRR = ELM_LIST( hdR, i );
	    ASS_LIST( hdL, i, hdRR );
	}
    }
    else {
	for ( i = 1;  i <= m;  i++ ) {
	    hdLL = ELM_LIST( hdL, i );
	    hdRR = ELM_LIST( hdR, i );
	    hdRR = PROD( hdRR, hdM );
	    hdAA = SUM( hdLL, hdRR );
	    ASS_LIST( hdL, i, hdAA );
	}
	for ( i = m+1;  i <= r;  i++ ) {
	    hdRR = ELM_LIST( hdR, i );
	    hdRR = PROD( hdRR, hdM );
	    ASS_LIST( hdL, i, hdRR );
	}
    }
}

void AddCoeffsVecFFEVecFFE ( hdL, hdR, hdM )
    TypHandle		hdL;
    TypHandle		hdR;
    TypHandle       	hdM;
{
    long            l;          /* degree plus one of left polynomial      */
    long            r;          /* degree plus one of right polynomial     */
    TypFFE          m;          /* multiple of <hdR> to add                */
    TypFFE        * ptL;        /* coeffs vectors of left polynomial       */
    TypFFE        * ptR;        /* coeffs vectors of right polynomial      */
    TypFFE        * ptE;        /* end of coeffs vector of sum             */
    TypFFE        * f;          /* finite field                            */
    TypFFE          t;          /* temp for FFEs                           */

    /* if <hdM> is a finite field element check the field                  */
    if ( TYPE(hdM) == T_FFE ) {
	if ( UnifiedFieldVecFFE(hdL,hdR) == FLD_FFE(hdM) )
	    m = VAL_FFE(hdM);
	else {
	    hdR = PROD( hdR, hdM );
	    m   = 1;
	}
    }

    /* otherwise replace <hdR> by the <hdM> multiple                       */
    else {
	if ( INT_TO_HD(1) != hdM ) {
	    hdR = PROD( hdR, hdM );
	    hdM = INT_TO_HD(1);
	    TabAddCoeffs[XType(hdL)][XType(hdR)]( hdL, hdR, hdM );
	    return;
	}
	else
	    m = 1;
    }

    /* if <m> is trivial there is nothing to add                           */
    if ( m == 0 )
	return;

    /* if <l> is less than <r> enlarge <hdL>                               */
    l = LEN_VECFFE(hdL);
    r = LEN_VECFFE(hdR);
    if ( l < r ) {
	Resize( hdL, SIZE_PLEN_VECFFE(r) );
	SET_VAL_VECFFE( hdL, l+1, 0 );
	l = r;
    }

    /* get the common finite field                                         */
    f = (TypFFE*) PTR( UnifiedFieldVecFFE( hdL, hdR ) );

    /* set up all the pointers                                             */
    ptL = (TypFFE*)( PTR(hdL) + 1 );
    ptR = (TypFFE*)( PTR(hdR) + 1 );
    ptE = ptR + r;

    /* add <hdR> to <hdL>                                                  */
    if ( m == 1 ) {
	while ( ptR < ptE ) {
	    *ptL = SUM_FF( *ptL, *ptR, f );
	    ptL++;
	    ptR++;
	}
    }
    else {
	while ( ptR < ptE ) {
	    t = PROD_FF( *ptR, m, f );
	    *ptL = SUM_FF( *ptL, t, f );
	    ptL++;
	    ptR++;
	}
    }
}

void AddCoeffsListxVecFFE ( hdL, hdR, hdM )
    TypHandle		hdL;
    TypHandle		hdR;
    TypHandle       	hdM;
{
    /* catch the special case that <hdL> is empty                          */
    if ( LEN_LIST(hdL) == 0 ) {
	Retype( hdL, T_VECFFE );
	Resize( hdL, SIZE_PLEN_VECFFE(1) );
	SET_FLD_VECFFE( hdL, FLD_VECFFE(hdR) );
	SET_VAL_VECFFE( hdL, 1, 0 );

	/* use 'AddCoeffsVecFFEVecFFE'                                     */
	AddCoeffsVecFFEVecFFE( hdL, hdR, hdM );
    }

    /* use 'AddCoeffsListxListx'                                           */
    else
	AddCoeffsListxListx( hdL, hdR, hdM );
}


/****************************************************************************
**
*F  FunAddCoeffs( <hdCall> )  . . . . . . . . . internal function 'AddCoeffs'
**
**  'FunAddCoeffs' implements 'AddCoeffs( <l>, <r> )'
*/
TypHandle FunAddCoeffs ( hdCall )
    TypHandle       	hdCall;
{
    TypHandle       	hdL;
    TypHandle       	hdR;
    TypHandle       	hdM;

    /* check arguments                                                     */
    if ( 4 * SIZE_HD < SIZE(hdCall) || SIZE(hdCall) < 3 * SIZE_HD )
        return Error( "usage: AddCoeffs( <l>, <r> )", 0L, 0L );
    hdL = EVAL( PTR(hdCall)[1] );
    hdR = EVAL( PTR(hdCall)[2] );
    if ( 4 * SIZE_HD == SIZE(hdCall) )
	hdM = EVAL( PTR(hdCall)[3] );
    else
	hdM = INT_TO_HD(1);

    /* jump through the table                                              */
    TabAddCoeffs[XType(hdL)][XType(hdR)]( hdL, hdR, hdM );
    return HdVoid;
}


/****************************************************************************
**
*F  FunSumCoeffs( <hdCall> )  . . . . . . . . . internal function 'SumCoeffs'
**
**  'FunSumCoeffs' implements 'SumCoeffs( <l>, <r> )'
*/
TypHandle FunSumCoeffs ( hdCall )
    TypHandle       	hdCall;
{
    TypHandle       	hdL;
    TypHandle       	hdR;
    TypHandle       	hdM;

    /* check arguments                                                     */
    if ( SIZE(hdCall) != 3 * SIZE_HD )
        return Error( "usage: SumCoeffs( <l>, <r> )", 0L, 0L );
    hdL = Copy( EVAL( PTR(hdCall)[1] ) );
    hdR = EVAL( PTR(hdCall)[2] );
    hdM = INT_TO_HD(1);

    /* jump through the table                                              */
    TabAddCoeffs[XType(hdL)][XType(hdR)]( hdL, hdR, hdM );

    /* and return the result stored in <hdL>                               */
    return hdL;
}


/****************************************************************************
**
*F  MULTIPLY_COEFFS( <hdP>, <hdL>, <l>, <hdR>, <r> )   <hdL>*<hdR> into <hdP>
**
#define MULTIPLY_COEFFS(hdP,hdL,l,hdR,r) \
    (TabMultiplyCoeffs[XType(hdL)][XType(hdR)](hdP,hdL,l,hdR,r))
*/
long (*TabMultiplyCoeffs[T_VAR][T_VAR]) P((
    TypHandle, TypHandle, long, TypHandle, long ));

long CantMultiplyCoeffs ( hdP, hdL, l, hdR, r )
    TypHandle	    	hdP;	/* space for result of <hdL> * <hdR>       */
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	l;      /* degree plus one of left polynomial      */
    long            	r;      /* degree plus one of right polynomial     */
{
    Error( "<l> and <r> must be vectors over a common field", 0L, 0L);
    return 0;
}

long MultiplyCoeffsListxListx ( hdP, hdL, l, hdR, r )
    TypHandle	    	hdP;	/* space for result of <hdL> * <hdR>       */
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	l;      /* degree plus one of left polynomial      */
    long            	r;      /* degree plus one of right polynomial     */
{
    TypHandle       	hdLL;   /* one element of <hdL>                    */
    TypHandle       	hdRR;   /* one element of <hdR>                    */
    TypHandle       	hdPP;   /* one element of <hdP>                    */
    TypHandle       	hdTT;   /* temp element                            */
    long            	i,u,k;  /* loop variables                          */

    /* catch the trivial case                                              */
    if ( l == 0 || r == 0 )
	return 0;

    /* fold the product                                                    */
    for ( i = l+r;  1 < i;  i-- )
    {
	hdPP = INT_TO_HD(0);
	u = ( i-1 < l ) ? i-1 : l;
	for ( k = ( i-r < 1 ) ? 1 : i-r;  k <= u;  k++ )
	{
	    hdLL = ELML_LIST( hdL, k   );
	    hdRR = ELMR_LIST( hdR, i-k );
	    hdTT = PROD( hdLL, hdRR );
	    hdPP = SUM( hdPP, hdTT );
	}
	ASS_LIST( hdP, i-1, hdPP );
    }
    return r+l-1;
}

long MultiplyCoeffsVecFFEVecFFE ( hdP, hdL, l, hdR, r )
    TypHandle	    	hdP;	/* space for result of <hdL> * <hdR>       */
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	l;      /* degree plus one of left polynomial      */
    long            	r;      /* degree plus one of right polynomial     */
{
    TypFFE *            ptL;    /* coeffs vectors of left polynomial       */
    TypFFE * 		ptLL;   /* coeffs vectors of left polynomial       */
    TypFFE * 		ptEnd;  /* end of <ptL>                            */
    TypFFE * 		ptR;    /* coeffs vectors of right polynomial      */
    TypFFE * 		ptP;    /* coeffs vectors of product               */
    TypFFE * 		ptPP;   /* coeffs vectors of product               */
    TypFFE * 		f;      /* finite field                            */
    TypFFE              t;      /* temp for FFEs                           */
    long                i;      /* loop variable                           */

    /* if the one of the polynomials is trivial, return the zero poly      */
    if ( l == 0 || r == 0 )
	return 0;

    /* get a common field of <hdL> and <hdR>                               */
    f = (TypFFE*) PTR( UnifiedFieldVecFFE( hdL, hdR ) );

    /* set common field in <hdP>                                           */
    SET_FLD_VECFFE( hdP, FLD_VECFFE(hdL) );

    /* chose larger vector as multiplicator                                */
    if ( l < r ) {
	ptL = (TypFFE*)( PTR(hdL) + 1 );
	ptR = (TypFFE*)( PTR(hdR) + 1 );
    }
    else {
	ptR = (TypFFE*)( PTR(hdL) + 1 );
	ptL = (TypFFE*)( PTR(hdR) + 1 );
	i = l;  l = r;  r = i;
    }

    /* clear <hdP>                                                         */
    ptP = (TypFFE*)( PTR(hdP) + 1 );
    for ( ptPP = ptP, ptEnd = ptP + (l+r-1);  ptPP < ptEnd;  ptPP++ )
	*ptPP = 0;

    /* add <hdL> to <hdP> multiplied by the elements of <hdR>              */
    ptEnd = ptL + l;
    for ( i = 0;  i < r;  i++, ptR++, ptP++ ) {
	if ( *ptR != 0 ) {
	    for ( ptLL = ptL, ptPP = ptP;  ptLL < ptEnd;  ptLL++, ptPP++ )
		if ( *ptLL != 0 ) {
		    t = PROD_FF( *ptLL, *ptR, f );
		    *ptPP = SUM_FF( *ptPP, t, f );
		}
	}
    }
    return l+r-1;
}


/****************************************************************************
**
*F  FunProductCoeffs( <hdCall> )  . . . . . internal function 'ProductCoeffs'
**
**  'FunProductCoeffs' implements 'ProductCoeffs( <l>, <r> )'
*/
TypHandle (*TabProductCoeffs[T_VAR][T_VAR]) P(( TypHandle, TypHandle ));

TypHandle FunProductCoeffs ( hdCall )
    TypHandle       	hdCall;
{
    TypHandle       	hdL;
    TypHandle       	hdR;

    /* check arguments                                                     */
    if ( SIZE(hdCall) != 3 * SIZE_HD )
        return Error( "usage: ProductCoeffs( <l>, <r> )", 0L, 0L );
    hdL = EVAL( PTR(hdCall)[1] );
    hdR = EVAL( PTR(hdCall)[2] );

    /* jump through the table                                              */
    return TabProductCoeffs[XType(hdL)][XType(hdR)]( hdL, hdR );
}

TypHandle CantProductCoeffs ( hdL, hdR )
    TypHandle		hdL;
    TypHandle		hdR;
{
    return Error("<l> and <r> must be vectors over a common field", 0L, 0L);
}

TypHandle ProductCoeffsListxListx ( hdL, hdR )
    TypHandle		hdL;
    TypHandle		hdR;
{
    TypHandle		hdP;		/* result                          */
    long		l;		/* length of <hdL>                 */
    long		r;		/* length of <hdR>                 */

    /* get the length of <hdL> and hd <hdR>                                */
    l = LEN_LIST(hdL);
    r = LEN_LIST(hdR);

    /* if <hdL> or <hdR> is trivial,  return the trivial polynomial        */
    if ( l == 0 || r == 0 ) {
	hdP = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdP, 0 );
	return hdP;
    }

    /* create a bag for the result                                         */
    hdP = NewBag( T_LIST, SIZE_PLEN_PLIST(l+r-1) );
    SET_LEN_PLIST( hdP, l+r-1 );

    /* fold the product                                                    */
    TabMultiplyCoeffs[T_LISTX][T_LISTX]( hdP, hdL, l, hdR, r );

    /* and return the result                                               */
    return hdP;
}

TypHandle ProductCoeffsVecFFEVecFFE ( hdL, hdR )
    TypHandle		hdL;
    TypHandle		hdR;
{
    TypHandle		hdP;		/* result                          */
    long		l;		/* length of <hdL>                 */
    long		r;		/* length of <hdR>                 */

    /* get the length of <hdL> and hd <hdR>                                */
    l = LEN_VECFFE(hdL);
    r = LEN_VECFFE(hdR);

    /* if <hdL> or <hdR> is trivial,  return the trivial polynomial        */
    if ( l == 0 || r == 0 ) {
	hdP = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdP, 0 );
	return hdP;
    }

    /* create a bag for the result                                         */
    hdP = NewBag( T_VECFFE, SIZE_PLEN_VECFFE(l+r-1) );

    /* fold the product                                                    */
    TabMultiplyCoeffs[T_VECFFE][T_VECFFE]( hdP, hdL, l, hdR, r );
    SET_FLD_VECFFE( hdP, FLD_VECFFE(hdL) );

    /* and return the result                                               */
    return hdP;
}


/****************************************************************************
**
*F  FunProductCoeffsMod( <hdCall> ) . .  internal function 'ProductCoeffsMod'
**
**  'FunProductCoeffsMod' implements 'ProductCoeffsMod( <l>, <r>, <p> )'
*/
TypHandle (*TabProductCoeffsMod[T_VAR][T_VAR]) P((
    TypHandle, TypHandle, TypHandle ));

TypHandle FunProductCoeffsMod ( hdCall )
    TypHandle       	hdCall;
{
    TypHandle       	hdL;
    TypHandle       	hdR;
    TypHandle       	hdN;

    /* check arguments                                                     */
    if ( SIZE(hdCall) != 4 * SIZE_HD )
        return Error( "usage: ProductCoeffsMod( <l>, <r>, <p> )", 0L, 0L );
    hdL = EVAL( PTR(hdCall)[1] );
    hdR = EVAL( PTR(hdCall)[2] );
    hdN = EVAL( PTR(hdCall)[3] );

    /* jump through the table                                              */
    return TabProductCoeffsMod[XType(hdL)][XType(hdR)]( hdL, hdR, hdN );
}

TypHandle CantProductCoeffsMod ( hdL, hdR, hdN )
    TypHandle		hdL;
    TypHandle		hdR;
    TypHandle		hdN;
{
    return Error("<l> and <r> must be vectors over a common field", 0L, 0L);
}

TypHandle ProductCoeffsModListxListx ( hdL, hdR, hdN )
    TypHandle		hdL;
    TypHandle		hdR;
    TypHandle		hdN;
{
    TypHandle		hdP;		/* result                          */
    TypHandle           hdLL;           /* one element of <hdL>            */
    TypHandle           hdRR;           /* one element of <hdR>            */
    TypHandle           hdPP;           /* one element of <hdP>            */
    TypHandle           hdTT;           /* temp element                    */
    TypHandle           hdQ;            /* <hdP> / 2                       */
    long                i,  u,  k;      /* loop variables                  */
    long		l;		/* length of <hdL>                 */
    long		r;		/* length of <hdR>                 */

    /* get the length of <hdL> and hd <hdR>                                */
    l = LEN_LIST(hdL);
    r = LEN_LIST(hdR);

    /* if <hdL> or <hdR> is trivial,  return the trivial polynomial        */
    if ( l == 0 || r == 0 || hdN == INT_TO_HD(0) ) {
	hdP = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdP, 0 );
	return hdP;
    }

    /* create a bag for the result                                         */
    hdP = NewBag( T_LIST, SIZE_PLEN_PLIST(l+r-1) );
    SET_LEN_PLIST( hdP, l+r-1 );

    /* if <hdP> is negative reduce into <hdP>/2 and <hdP>                  */
    if ( LT( hdN, INT_TO_HD(0) ) == HdTrue )
    {
	hdN = DIFF( INT_TO_HD(0), hdN );
	hdQ = SUM( hdN, INT_TO_HD(1) );
	hdQ = QuoInt( hdQ, INT_TO_HD(2) );
	hdQ = DIFF( hdQ, INT_TO_HD(1) );
    }
    else
	hdQ = 0;

    /* fold the product                                                    */
    for ( i = l+r;  1 < i;  i-- )
    {
	hdPP = INT_TO_HD(0);
	u = ( i-1 < l ) ? i-1 : l;
	for ( k = ( i-r < 1 ) ? 1 : i-r;  k <= u;  k++ )
	{
	    hdLL = ELML_LIST( hdL, k   );
	    hdRR = ELMR_LIST( hdR, i-k );
	    hdTT = PROD( hdLL, hdRR );
	    hdPP = SUM( hdPP, hdTT );
	}
	hdPP = MOD( hdPP, hdN );
	if ( hdQ != 0 && LT( hdQ, hdPP ) == HdTrue )
	    hdPP = DIFF( hdPP, hdN );
	SET_ELM_PLIST( hdP, i-1, hdPP );
    }

    /* and return the result                                               */
    return hdP;
}


/****************************************************************************
**
*F  REDUCE_COEFFS( <hdL>, <l>, <hdR>, <r> ) . . . . . . reduce <hdL> by <hdR>
**
#define REDUCE_COEFFS( hdL, l, hdR, r ) \
    (TabReduceCoeffs[XType(hdL)][XType(hdR)]( hdL, l, hdR, r ))
*/
long (*TabReduceCoeffs[T_VAR][T_VAR]) P((
    TypHandle, long, TypHandle, long ));

long CantReduceCoeffs ( hdL, l, hdR, r )
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    long            	l;      /* degree plus one of left polynomial      */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	r;      /* degree plus one of right polynomial     */
{
    Error( "<l> and <r> must be vectors over a common field", 0L, 0L);
    return 0;
}

long ReduceCoeffsListxListx ( hdL, l, hdR, r )
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    long            	l;      /* degree plus one of left polynomial      */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	r;      /* degree plus one of right polynomial     */
{
    TypHandle           hdLL;   /* one element of <hdL>                    */
    TypHandle           hdRR;   /* one element of <hdR>                    */
    TypHandle           hdCC;   /* temp element                            */
    TypHandle           hdTT;   /* temp element                            */
    long                i,  k;  /* loop variables                          */

    /* <r> must be none zero                                               */
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }
    hdCC = PROD( ELML_LIST( hdR, 1 ), INT_TO_HD(0) );
    for ( ;  0 < r;  r-- ) {
	hdTT = ELMR_LIST( hdR, r );
	if ( EQ( hdCC, hdTT ) == HdFalse )
	    break;
    }
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }

    /* if <l> is trivial return                                            */
    if ( l == 0 )
	return 0;

    /* compute the remainder                                               */
    for ( i = l-r;  0 <= i;  i-- )
    {
	hdLL = ELMR_LIST( hdL, i+r );
	if ( hdLL != INT_TO_HD(0) ) {
	    hdRR = ELML_LIST( hdR, r );
	    hdCC = QUO( hdLL, hdRR );
	    for ( k = r;  0 < k;  k-- )
	    {
		hdRR = ELML_LIST( hdR, k );
		hdTT = PROD( hdCC, hdRR );
		hdLL = ELMR_LIST( hdL, i+k );
		hdLL = DIFF( hdLL, hdTT );
		ASS_LIST( hdL, i+k, hdLL );
	    }
	}
    }
    return ( l < r ) ? l : r-1;
}

long ReduceCoeffsVecFFEVecFFE ( hdL, l, hdR, r )
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    long            	l;      /* degree plus one of left polynomial      */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	r;      /* degree plus one of right polynomial     */
{
    TypFFE *            ptL;    /* coeffs vectors of left polynomial       */
    TypFFE *            ptLL;   /* coeffs vectors of left polynomial       */
    TypFFE *            ptR;    /* coeffs vectors of right polynomial      */
    TypFFE *            ptRR;   /* coeffs vectors of right polynomial      */
    TypFFE *            f;      /* the finite field                        */
    TypFFE              o;      /* size of <f> minus one                   */
    TypFFE              c,q,t;  /* temps for FFEs                          */
    register long       i,k;    /* loop variables                          */

    /* <r> must be none zero                                               */
    ptR = (TypFFE*)( PTR(hdR) + 1 ) + (r-1);
    while ( 0 < r && *ptR == 0 ) {
	r--;  ptR--;
    }
    if ( r == 0 )
	Error( "<r> must be non zero", 0L, 0L );

    /* if <l> is trivial return                                            */
    if ( l == 0 )
	return 0;

    /* get a common field                                                  */
    f = (TypFFE*) PTR( UnifiedFieldVecFFE( hdL, hdR ) );
    o = *f;

    /* set up all the pointers                                             */
    ptL = (TypFFE*)( PTR(hdL) + 1 );
    ptR = (TypFFE*)( PTR(hdR) + 1 ) + (r-1);

    /* get the leading coefficient of <hdR> * -1, <c> is never zero        */
    c = ( o%2 == 1 ? (*ptR) : ( (*ptR) <= o/2 ? (*ptR)+o/2 : (*ptR)-o/2 ) );

    /* compute the remainder                                               */
    for ( i = l-r;  0 <= i;  i-- ) {

	/* if <ptLL> already ends with a zero, continue                    */
	ptLL = ptL + (i-1+r);
        if ( *ptLL == 0 )
	    continue;

        /* compute quotient of leading coefficients                        */
	q = ( c <= (*ptLL) ? (*ptLL)-c+1 : o-c+1+(*ptLL) );

        /* reduce <ptLL> by <q> * <ptRR>                                   */
	for ( k = r, ptRR = ptR;  0 < k;  k--, ptLL--, ptRR-- ) {
	    if ( *ptRR == 0 )
		continue;
	    t = ( q-1 <= o-(*ptRR) ) ? q-1+(*ptRR) : q-1-(o-(*ptRR));
	    if ( *ptLL == 0 )
		*ptLL = t;
	    else if ( *ptLL <= t )
		*ptLL = PROD_FF( *ptLL, f[t-(*ptLL)+1], f );
	    else
		*ptLL = PROD_FF( t, f[(*ptLL)-t+1], f );
	}
    }
    return ( l < r ) ? l : r-1;
}


/****************************************************************************
**
*F  FunReduceCoeffs( <hdCall> ) . . . . . .  internal function 'ReduceCoeffs'
**
**  'FunReduceCoeffs' implements 'ReduceCoeffs( <l>, <r> )'
*/
TypHandle FunReduceCoeffs ( hdCall )
    TypHandle 		hdCall;
{
    TypHandle       	hdL;
    long                l;
    TypHandle           hdR;
    long                r;

    /* check arguments                                                     */
    if ( SIZE( hdCall ) != 3 * SIZE_HD )
        return Error( "usage: ReduceCoeffs( <l>, <r> )", 0L, 0L );
    hdL = EVAL( PTR(hdCall)[1] );
    hdR = EVAL( PTR(hdCall)[2] );
    l   = LEN_LIST(hdL);
    r   = LEN_LIST(hdR);

    /* jump through the table                                              */
    TabReduceCoeffs[XType(hdL)][XType(hdR)]( hdL, l, hdR, r );
    return HdVoid;
}


/****************************************************************************
**
*F  FunRemainderCoeffs( <hdCall> )  . . . internal function 'RemainderCoeffs'
**
**  'FunRemainderCoeffs' implements 'RemainderCoeffs( <l>, <r> )'
*/
TypHandle FunRemainderCoeffs ( hdCall )
    TypHandle       hdCall;
{
    TypHandle       	hdL;
    long                l;
    TypHandle           hdR;
    long                r;

    /* check arguments                                                     */
    if ( SIZE( hdCall ) != 3 * SIZE_HD )
        return Error( "usage: ReduceCoeffs( <l>, <r> )", 0L, 0L );
    hdL = EVAL( PTR(hdCall)[1] );
    hdR = EVAL( PTR(hdCall)[2] );
    l   = LEN_LIST(hdL);
    r   = LEN_LIST(hdR);

    /* jump through the table                                              */
    hdL = Copy(hdL);
    TabReduceCoeffs[XType(hdL)][XType(hdR)]( hdL, l, hdR, r );
    return hdL;
}


/****************************************************************************
**
*F  REDUCE_COEFFS_MOD( <hdL>, <l>, <hdR>, <r>, <hdN> )  reduce <hdL> by <hdR>
**
#define REDUCE_COEFFS_MOD( hdL, l, hdR, r ) \
    (TabReduceCoeffsMod[XType(hdL)][XType(hdR)]( hdL, l, hdR, r, hdN ))
*/
long (*TabReduceCoeffsMod[T_VAR][T_VAR]) P((
    TypHandle, long, TypHandle, long, TypHandle ));

long CantReduceCoeffsMod ( hdL, l, hdR, r, hdP )
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    long            	l;      /* degree plus one of left polynomial      */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	r;      /* degree plus one of right polynomial     */
    TypHandle       	hdP;    /* modulo                                  */
{
    Error( "<l> and <r> must be vectors over a common field", 0L, 0L);
    return 0;
}

long ReduceCoeffsModListxListx ( hdL, l, hdR, r, hdP )
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    long            	l;      /* degree plus one of left polynomial      */
    TypHandle       	hdR;    /* right polynomial coeffs                 */
    long            	r;      /* degree plus one of right polynomial     */
    TypHandle       	hdP;    /* modulo                                  */
{
    TypHandle       hdLL;       /* one element of <hdL>                    */
    TypHandle       hdRR;       /* one element of <hdR>                    */
    TypHandle       hdCC;       /* temp element                            */
    TypHandle       hdTT;       /* temp element                            */
    TypHandle       hdQ;        /* <hdP> / 2                               */
    long            i,  k;      /* loop variables                          */

    /* <r> must be none zero                                               */
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }
    hdCC = PROD( ELML_LIST( hdR, 1 ), INT_TO_HD(0) );
    for ( ;  0 < r;  r-- ) {
	hdTT = ELMR_LIST( hdR, r );
	if ( EQ( hdCC, hdTT ) == HdFalse )
	    break;
    }
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }

    /* catch the trivial cases (<l> or <hdP> equal zero)                   */
    if ( l == 0 )
	return 0;
    if ( EQ( hdP, INT_TO_HD(0) ) == HdTrue ) {
	for ( i = l;  0 < i;  i-- )
	    ASS_LIST( hdL, i, INT_TO_HD(0) );
	return 0;
    }

    /* if <hdP> is negative reduce into <hdP>/2 and <hdP>                  */
    if ( LT( hdP, INT_TO_HD(0) ) == HdTrue ) {
	hdP = DIFF( INT_TO_HD(0), hdP );
	hdQ = SUM( hdP, INT_TO_HD(1) );
	hdQ = QuoInt( hdQ, INT_TO_HD(2) );
	hdQ = DIFF( hdQ, INT_TO_HD(1) );
    }
    else
	hdQ = 0;

    /* if <r> is zero or too big reduce modulo <hP>                        */
    if ( l < r ) {
	for ( i = l;  0 < i;  i-- ) {
	    hdTT = MOD( ELMF_LIST(hdL,i), hdP );
	    if ( hdQ != 0 && LT( hdQ, hdTT ) == HdTrue )
		hdTT = DIFF( hdTT, hdP );
	    ASS_LIST( hdL, i, hdTT );
	}
	r = l+1;
    }

    /* otherwise, compute the remainder                                    */
    else
	for ( i = l-r;  0 <= i;  i-- ) {
	    hdLL = ELM_LIST( hdL, i+r );
	    if ( hdLL != INT_TO_HD(0) ) {
		hdRR = ELM_LIST( hdR, r );
		hdCC = QUO( hdLL, hdRR );
		hdCC = MOD( hdCC, hdP );
		for ( k = r;  0 < k;  k-- ) {
		    hdRR = ELM_LIST( hdR, k );
		    hdTT = PROD( hdCC, hdRR );
		    hdLL = ELM_LIST( hdL, i+k );
		    hdLL = DIFF( hdLL, hdTT );
		    hdLL = MOD( hdLL, hdP );
		    if ( hdQ != 0 && LT( hdQ, hdLL ) == HdTrue )
			hdLL = DIFF( hdLL, hdP );
		    SET_ELM_PLIST( hdL, i+k, hdLL );
		}
	    }
	}

    /* and return the new length                                           */
    return r-1;
}

long ReduceCoeffsModListx ( hdL, l, hdR, r, hdP )
    TypHandle       	hdL;    /* left polynomial coeffs                  */
    long            	l;      /* degree plus one of left polynomial      */
    TypHandle       	hdR;    /* void                                    */
    long            	r;      /* zero                                    */
    TypHandle       	hdP;    /* modulo                                  */
{
    TypHandle       hdTT;       /* temp element                            */
    TypHandle       hdQ;        /* <hdP> / 2                               */
    long            i;          /* loop variables                          */

    /* catch the trivial cases (<l> or <hdP> equal zero)                   */
    if ( l == 0 )
	return 0;
    if ( EQ( hdP, INT_TO_HD(0) ) == HdTrue ) {
	for ( i = l;  0 < i;  i-- )
	    ASS_LIST( hdL, i, INT_TO_HD(0) );
	return 0;
    }

    /* if <hdP> is negative reduce into <hdP>/2 and <hdP>                  */
    if ( LT( hdP, INT_TO_HD(0) ) == HdTrue ) {
	hdP = DIFF( INT_TO_HD(0), hdP );
	hdQ = SUM( hdP, INT_TO_HD(1) );
	hdQ = QuoInt( hdQ, INT_TO_HD(2) );
	hdQ = DIFF( hdQ, INT_TO_HD(1) );
    }
    else
	hdQ = 0;

    /* reduce modulo <hP>                                                  */
    for ( i = l;  0 < i;  i-- ) {
	hdTT = MOD( ELMF_LIST(hdL,i), hdP );
	if ( hdQ != 0 && LT( hdQ, hdTT ) == HdTrue )
	    hdTT = DIFF( hdTT, hdP );
	ASS_LIST( hdL, i, hdTT );
    }
    return l;
}


/****************************************************************************
**
*F  FunReduceCoeffsMod( <hdCall> )  . . . internal function 'ReduceCoeffsMod'
**
**  'FunReduceCoeffsMod' implements 'ReduceCoeffsMod( <l>, <r>, <p> )'
*/
TypHandle FunReduceCoeffsMod ( hdCall )
    TypHandle       hdCall;
{
    TypHandle       	hdL;
    long                l;
    TypHandle           hdR;
    long                r;
    TypHandle           hdN;

    /* check arguments                                                     */
    if ( 4*SIZE_HD < SIZE(hdCall) || SIZE(hdCall) < 3*SIZE_HD )
        return Error( "usage: ReduceCoeffsMod( <l>, <r>, <p> )", 0L, 0L );
    hdL = EVAL( PTR(hdCall)[1] );
    l   = LEN_LIST(hdL);
    if ( SIZE(hdCall) == 4*SIZE_HD ) {
	hdR = EVAL( PTR(hdCall)[2] );
	r   = LEN_LIST(hdR);
	hdN = EVAL( PTR(hdCall)[3] );
    }
    else {
	hdR = HdVoid;
	r   = 0;
	hdN = EVAL( PTR(hdCall)[2] );
    }

    /* jump through the table                                              */
    TabReduceCoeffsMod[XType(hdL)][XType(hdR)]( hdL, l, hdR, r, hdN );
    return HdVoid;
}


/****************************************************************************
**
*F  FunPowerModCoeffs( <hdCall> ) . . . .  internal function 'PowerModCoeffs'
**
**  'FunPowerModCoeffs' implements 'PowerModCoeffs( <g>, <n>, <r> )'
*/
TypHandle (*TabPowerModCoeffsInt[T_VAR][T_VAR]) P((
    TypHandle, TypHandle, TypHandle ));

TypHandle (*TabPowerModCoeffsLInt[T_VAR][T_VAR]) P((
    TypHandle, TypHandle, TypHandle ));

TypHandle FunPowerModCoeffs ( hdCall )
    TypHandle 		hdCall;
{
    TypHandle       	hdG;
    TypHandle       	hdE;
    TypHandle       	hdR;

    /* check arguments                                                     */
    if ( SIZE( hdCall ) != 4 * SIZE_HD )
        return Error( "usage: PowerModCoeffs( <g>, <exp>, <r> )", 0L, 0L );
    hdG = EVAL( PTR(hdCall)[1] );
    hdE = EVAL( PTR(hdCall)[2] );
    hdR = EVAL( PTR(hdCall)[3] );
    if ( TYPE(hdE)!=T_INTPOS && ( TYPE(hdE)!=T_INT || HD_TO_INT(hdE)<1 ) )
	return Error( "<exp> must be a positive integer", 0L, 0L );

    /* jump through the table                                              */
    if ( TYPE(hdE) == T_INT )
	return TabPowerModCoeffsInt [XType(hdG)][XType(hdR)](hdG, hdE, hdR);
    else
	return TabPowerModCoeffsLInt[XType(hdG)][XType(hdR)](hdG, hdE, hdR);
}

TypHandle PowerModListxIntListx ( hdG, hdE, hdR )
    TypHandle       	hdG;    /* polynomial coeffs                       */
    TypHandle       	hdE;    /* exponent                                */
    TypHandle       	hdR;    /* modulus                                 */
{
    TypHandle	        hdP;    /* result                                  */
    TypHandle           hdR1;   /* temporary storage for multiplication    */
    TypHandle           hdR2;   /* temporary storage for multiplication    */
    long                g;      /* length of <hdG>                         */
    long                r;      /* length of <hdR>                         */
    long                p;      /* length of <hdP>                         */
    unsigned long       exp;    /* value of <hdE>                          */
    unsigned long       i;      /* loop variable                           */

    /* <hdR> must be none zero                                             */
    r = LEN_LIST(hdR);
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }
    hdR1 = PROD( ELML_LIST( hdR, 1 ), INT_TO_HD(0) );
    for ( ;  0 < r;  r-- ) {
	hdR2 = ELMR_LIST( hdR, r );
	if ( EQ( hdR1, hdR2 ) == HdFalse )
	    break;
    }
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }

    /* copy <hdG> and reduce it modulo <hdR>                               */
    hdG = Copy(hdG);
    g   = REDUCE_COEFFS( hdG, LEN_LIST(hdG), hdR, r );

    /* if <hdG> is already trivial,  return                                */
    for ( ;  0 < g;  g-- ) {
	hdR2 = ELMR_LIST( hdG, g );
	if ( EQ( hdR1, hdR2 ) == HdFalse )
	    break;
    }
    if ( g == 0 ) {
	hdG = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdG, 0 );
	return hdG;
    }

    /* allocate storage for multiplication                                 */
    hdR1 = Copy(hdG);
    hdR2 = NewBag( T_LIST, SIZE_PLEN_PLIST(2*r) );

    /* we need at most two times the <r>                                   */
    PLAIN_LIST(hdG);
    PLAIN_LIST(hdR1);
    Resize( hdR1, SIZE_PLEN_PLIST(2*r) );
    SET_LEN_PLIST( hdR1, 2*r );

    /* compute the power using left to right repeated squaring             */
    i   = 1 << 31;
    p   = 0;
    hdP = 0;
    exp = HD_TO_INT(hdE);
    while ( 1 < i ) {
	if ( hdP ) {

	    /* use table directly in order to avoid changing the types     */
	    p = TabMultiplyCoeffs[T_LISTX][T_LISTX]( hdR2, hdP, p, hdP, p );
	    p = TabReduceCoeffs[T_LISTX][T_LISTX]( hdR2, p, hdR, r );
	    hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
	}
	i = i / 2;
	if ( i <= exp ) {
	    if ( hdP ) {

		/* use table directly in order to avoid changing the types */
		p = TabMultiplyCoeffs[T_LISTX][T_LISTX](hdR2,hdP,p,hdG,g);
		p = TabReduceCoeffs[T_LISTX][T_LISTX](hdR2,p,hdR,r);
		hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
	    }
	    else {
		hdP = hdR1;
		p = g;
	    }
	    exp = exp - i;
	}
    }

    /* resize result and return                                            */
    SET_LEN_PLIST( hdP, p );
    return hdP;
}

TypHandle PowerModVecFFEIntVecFFE ( hdG, hdE, hdR )
    TypHandle       	hdG;    /* polynomial coeffs                       */
    TypHandle       	hdE;    /* exponent                                */
    TypHandle       	hdR;    /* modulus                                 */
{
    TypHandle	        hdP;    /* result                                  */
    TypHandle           hdR1;   /* temporary storage for multiplication    */
    TypHandle           hdR2;   /* temporary storage for multiplication    */
    long                g;      /* length of <hdG>                         */
    long                r;      /* length of <hdR>                         */
    long                p;      /* length of <hdP>                         */
    unsigned long       exp;    /* value of <hdE>                          */
    unsigned long       i;      /* loop variable                           */

    /* <hdR> must be none zero                                             */
    r = LEN_VECFFE(hdR);
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }
    for ( ;  0 < r;  r-- ) {
	if ( VAL_VECFFE( hdR, r ) != 0 )
	    break;
    }
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }

    /* copy <hdG> and reduce it modulo <hdR>                               */
    hdG = Copy(hdG);
    g   = REDUCE_COEFFS( hdG, LEN_LIST(hdG), hdR, r );

    /* if <hdG> is already trivial,  return                                */
    for ( ;  0 < g;  g-- ) {
	if ( VAL_VECFFE( hdG, g ) != 0 )
	    break;
    }
    if ( g == 0 ) {
	hdG = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdG, 0 );
	return hdG;
    }

    /* allocate storage for multiplication                                 */
    hdR1 = Copy(hdG);
    hdR2 = NewBag( T_VECFFE, SIZE_PLEN_VECFFE(2*r) );
    SET_FLD_VECFFE( hdR2, FLD_VECFFE(hdR1) );

    /* we need at most two times the <r>                                   */
    Resize( hdR1, SIZE_PLEN_VECFFE(2*r) );

    /* compute the power using left to right repeated squaring             */
    i   = 1 << 31;
    p   = 0;
    hdP = 0;
    exp = HD_TO_INT(hdE);
    while ( 1 < i ) {
	if ( hdP ) {

	    /* use table directly in order to avoid changing the types     */
	    p = TabMultiplyCoeffs[T_VECFFE][T_VECFFE](hdR2,hdP,p,hdP,p);
	    p = TabReduceCoeffs[T_VECFFE][T_VECFFE]( hdR2, p, hdR, r );
	    hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
	}
	i = i / 2;
	if ( i <= exp ) {
	    if ( hdP ) {

		/* use table directly in order to avoid changing the types */
		p = TabMultiplyCoeffs[T_VECFFE][T_VECFFE](hdR2,hdP,p,hdG,g);
		p = TabReduceCoeffs[T_VECFFE][T_VECFFE](hdR2,p,hdR,r);
		hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
	    }
	    else {
		hdP = hdR1;
		p = g;
	    }
	    exp = exp - i;
	}
    }

    /* resize result and return                                            */
    SET_LEN_VECFFE( hdP, p );
    return hdP;
}

TypHandle PowerModListxLIntListx ( hdG, hdE, hdR )
    TypHandle       	hdG;    /* polynomial coeffs                       */
    TypHandle       	hdE;    /* exponent                                */
    TypHandle       	hdR;    /* modulus polynomial coeffs               */
{
    TypHandle	        hdP;    /* result                                  */
    TypHandle           hdR1;   /* temporary storage for multiplication    */
    TypHandle           hdR2;   /* temporary storage for multiplication    */
    TypDigit            e;      /* one digit of <hdE>                      */
    long                g;      /* length of <hdG>                         */
    long                r;      /* length of <hdR>                         */
    long                p;      /* length of <hdP>                         */
    unsigned long       i;      /* loop variable                           */
    long                l;      /* loop variable                           */

    /* <hdR> must be none zero                                             */
    r = LEN_LIST(hdR);
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }
    hdR1 = PROD( ELML_LIST( hdR, 1 ), INT_TO_HD(0) );
    for ( ;  0 < r;  r-- ) {
	hdR2 = ELMR_LIST( hdR, r );
	if ( EQ( hdR1, hdR2 ) == HdFalse )
	    break;
    }
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }

    /* copy <hdG> and reduce it modulo <hdR>                               */
    hdG = Copy(hdG);
    g   = REDUCE_COEFFS( hdG, LEN_LIST(hdG), hdR, r );

    /* if <hdG> is already trivial,  return                                */
    for ( ;  0 < g;  g-- ) {
	hdR2 = ELMR_LIST( hdG, g );
	if ( EQ( hdR1, hdR2 ) == HdFalse )
	    break;
    }
    if ( g == 0 ) {
	hdG = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdG, 0 );
	return hdG;
    }

    /* allocate storage for multiplication                                 */
    hdR1 = Copy(hdG);
    hdR2 = NewBag( T_LIST, SIZE_PLEN_PLIST(2*r) );

    /* we need at most two times the <r>                                   */
    PLAIN_LIST(hdR1);
    PLAIN_LIST(hdG);
    Resize( hdR1, SIZE_PLEN_PLIST(2*r) );
    SET_LEN_PLIST( hdR1, 2*r );

    /* compute the power using left to right repeated squaring             */
    hdP = 0;
    p   = 0;
    for ( l = SIZE(hdE)/sizeof(TypDigit)-1;  0 <= l;  l-- ) {
	i = 1 << (8*sizeof(TypDigit));
	e = ((TypDigit*) PTR(hdE))[l];
	while ( 1 < i ) {
	    if ( hdP ) {

		/* use table directly in order to avoid changing the types */
		p = TabMultiplyCoeffs[T_LISTX][T_LISTX](hdR2,hdP,p,hdP,p);
		p = TabReduceCoeffs[T_LISTX][T_LISTX]( hdR2, p, hdR, r );
		hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
	    }
	    i = i / 2;
	    if ( i <= e ) {
		if ( hdP ) {
		    /* use table directly                                  */
                   p = TabMultiplyCoeffs[T_LISTX][T_LISTX](hdR2,hdP,p,hdG,g);
		   p = TabReduceCoeffs[T_LISTX][T_LISTX]( hdR2, p, hdR, r );
		   hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
		}
		else {
		    hdP = hdR1;
		    p = g;
		}
		e = e - i;
	    }
	}
    }

    /* resize result and return                                            */
    SET_LEN_PLIST( hdP, p );
    return hdP;
}

TypHandle PowerModVecFFELIntVecFFE ( hdG, hdE, hdR )
    TypHandle       	hdG;    /* polynomial coeffs                       */
    TypHandle       	hdE;    /* exponent                                */
    TypHandle       	hdR;    /* modulus                                 */
{
    TypHandle	        hdP;    /* result                                  */
    TypHandle           hdR1;   /* temporary storage for multiplication    */
    TypHandle           hdR2;   /* temporary storage for multiplication    */
    TypDigit            e;      /* one digit of <hdE>                      */
    long                g;      /* length of <hdG>                         */
    long                r;      /* length of <hdR>                         */
    long                p;      /* length of <hdP>                         */
    unsigned long       i;      /* loop variable                           */
    long                l;      /* loop variable                           */

    /* <hdR> must be none zero                                             */
    r = LEN_VECFFE(hdR);
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }
    for ( ;  0 < r;  r-- ) {
	if ( VAL_VECFFE( hdR, r ) != 0 )
	    break;
    }
    if ( r == 0 ) {
	Error( "<r> must be non zero", 0L, 0L );
	return 0;
    }

    /* copy <hdG> and reduce it modulo <hdR>                               */
    hdG = Copy(hdG);
    g   = REDUCE_COEFFS( hdG, LEN_LIST(hdG), hdR, r );

    /* if <hdG> is already trivial,  return                                */
    for ( ;  0 < g;  g-- ) {
	if ( VAL_VECFFE( hdG, g ) != 0 )
	    break;
    }
    if ( g == 0 ) {
	hdG = NewBag( T_LIST, SIZE_PLEN_PLIST(0) );
	SET_LEN_PLIST( hdG, 0 );
	return hdG;
    }

    /* allocate storage for multiplication                                 */
    hdR1 = Copy(hdG);
    hdR2 = NewBag( T_VECFFE, SIZE_PLEN_VECFFE(2*r) );
    SET_FLD_VECFFE( hdR2, FLD_VECFFE(hdR1) );

    /* we need at most two times the <r>                                   */
    Resize( hdR1, SIZE_PLEN_VECFFE(2*r) );

    /* compute the power using left to right repeated squaring             */
    hdP = 0;
    p   = 0;
    for ( l = SIZE(hdE)/sizeof(TypDigit)-1;  0 <= l;  l-- ) {
	i = 1 << (8*sizeof(TypDigit));
	e = ((TypDigit*) PTR(hdE))[l];
	while ( 1 < i ) {
	    if ( hdP ) {

		/* use table directly in order to avoid changing the types */
		p = TabMultiplyCoeffs[T_VECFFE][T_VECFFE](hdR2,hdP,p,hdP,p);
		p = TabReduceCoeffs[T_VECFFE][T_VECFFE]( hdR2, p, hdR, r );
		hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
	    }
	    i = i / 2;
	    if ( i <= e ) {
		if ( hdP ) {
		 /* use table directly                                     */
                 p = TabMultiplyCoeffs[T_VECFFE][T_VECFFE](hdR2,hdP,p,hdG,g);
	         p = TabReduceCoeffs[T_VECFFE][T_VECFFE]( hdR2, p, hdR, r );
	         hdR1 = hdP;  hdP = hdR2;  hdR2 = hdR1;
		}
		else {
		    hdP = hdR1;
		    p = g;
		}
		e = e - i;
	    }
	}
    }

    /* resize result and return                                            */
    SET_LEN_VECFFE( hdP, p );
    return hdP;
}

TypHandle CantPowerModCoeffs ( hdG, hdE, hdR )
    TypHandle       	hdG;    /* polynomial coeffs                       */
    TypHandle       	hdE;    /* exponent                                */
    TypHandle       	hdR;    /* modulus polynomial coeffs               */
{
    Error( "<g> and <r> must be vectors over a common field", 0L, 0L);
    return 0;
}



/****************************************************************************
**
*F  InitPolynom() . . . . . . . . . . . . . .  initialize the polynom package
*/
void InitPolynom ()
{
    long            type1, type2;    	/* loop variables                  */

    /* install tables for gap functions                                    */
    for ( type1 = T_VOID;  type1 < T_VAR;  type1++ ) {
        TabNormalizeCoeffs[type1] = CantNormalizeCoeffs;
        TabShrinkCoeffs   [type1] = CantShrinkCoeffs;
        TabShiftedCoeffs  [type1] = CantShiftedCoeffs;
	for ( type2 = T_VOID;  type2 < T_VAR;  type2++ ) {
	    TabAddCoeffs         [type1][type2] = CantAddCoeffs;
	    TabMultiplyCoeffs    [type1][type2] = CantMultiplyCoeffs;
	    TabProductCoeffs     [type1][type2] = CantProductCoeffs;
	    TabProductCoeffsMod  [type1][type2] = CantProductCoeffsMod;
	    TabReduceCoeffs      [type1][type2] = CantReduceCoeffs;
	    TabReduceCoeffsMod   [type1][type2] = CantReduceCoeffsMod;
	    TabPowerModCoeffsInt [type1][type2] = CantPowerModCoeffs;
	    TabPowerModCoeffsLInt[type1][type2] = CantPowerModCoeffs;
	}
    }

    TabNormalizeCoeffs[T_LISTX ] = NormalizeCoeffsListx;
    TabNormalizeCoeffs[T_VECTOR] = NormalizeCoeffsListx;
    TabNormalizeCoeffs[T_VECFFE] = NormalizeCoeffsVecFFE;

    TabShrinkCoeffs[T_LISTX ] = ShrinkCoeffsListx;
    TabShrinkCoeffs[T_VECTOR] = ShrinkCoeffsListx;
    TabShrinkCoeffs[T_VECFFE] = ShrinkCoeffsVecFFE;

    TabShiftedCoeffs  [T_LISTX ] = ShiftedCoeffsListx;
    TabShiftedCoeffs  [T_VECTOR] = ShiftedCoeffsListx;
    TabShiftedCoeffs  [T_VECFFE] = ShiftedCoeffsVecFFE;

    TabAddCoeffs[T_LISTX ][T_LISTX ] = AddCoeffsListxListx;
    TabAddCoeffs[T_LISTX ][T_VECTOR] = AddCoeffsListxListx;
    TabAddCoeffs[T_LISTX ][T_VECFFE] = AddCoeffsListxVecFFE;
    TabAddCoeffs[T_VECTOR][T_LISTX ] = AddCoeffsListxListx;
    TabAddCoeffs[T_VECTOR][T_VECTOR] = AddCoeffsListxListx;
    TabAddCoeffs[T_VECTOR][T_VECFFE] = AddCoeffsListxListx;
    TabAddCoeffs[T_VECFFE][T_LISTX ] = AddCoeffsListxListx;
    TabAddCoeffs[T_VECFFE][T_VECTOR] = AddCoeffsListxListx;
    TabAddCoeffs[T_VECFFE][T_VECFFE] = AddCoeffsVecFFEVecFFE;

    TabMultiplyCoeffs[T_LISTX ][T_LISTX ] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_LISTX ][T_VECTOR] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_LISTX ][T_VECFFE] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_VECTOR][T_LISTX ] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_VECTOR][T_VECTOR] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_VECTOR][T_VECFFE] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_VECFFE][T_LISTX ] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_VECFFE][T_VECTOR] = MultiplyCoeffsListxListx;
    TabMultiplyCoeffs[T_VECFFE][T_VECFFE] = MultiplyCoeffsVecFFEVecFFE;

    TabProductCoeffs[T_LISTX ][T_LISTX ] = ProductCoeffsListxListx;
    TabProductCoeffs[T_LISTX ][T_VECTOR] = ProductCoeffsListxListx;
    TabProductCoeffs[T_LISTX ][T_VECFFE] = ProductCoeffsListxListx;
    TabProductCoeffs[T_VECTOR][T_LISTX ] = ProductCoeffsListxListx;
    TabProductCoeffs[T_VECTOR][T_VECTOR] = ProductCoeffsListxListx;
    TabProductCoeffs[T_VECTOR][T_VECFFE] = ProductCoeffsListxListx;
    TabProductCoeffs[T_VECFFE][T_LISTX ] = ProductCoeffsListxListx;
    TabProductCoeffs[T_VECFFE][T_VECTOR] = ProductCoeffsListxListx;
    TabProductCoeffs[T_VECFFE][T_VECFFE] = ProductCoeffsVecFFEVecFFE;

    TabProductCoeffsMod[T_LISTX ][T_LISTX ] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_LISTX ][T_VECTOR] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_LISTX ][T_VECFFE] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_VECTOR][T_LISTX ] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_VECTOR][T_VECTOR] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_VECTOR][T_VECFFE] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_VECFFE][T_LISTX ] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_VECFFE][T_VECTOR] = ProductCoeffsModListxListx;
    TabProductCoeffsMod[T_VECFFE][T_VECFFE] = ProductCoeffsModListxListx;

    TabReduceCoeffs[T_LISTX ][T_LISTX ] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_LISTX ][T_VECTOR] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_LISTX ][T_VECFFE] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_VECTOR][T_LISTX ] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_VECTOR][T_VECTOR] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_VECTOR][T_VECFFE] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_VECFFE][T_LISTX ] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_VECFFE][T_VECTOR] = ReduceCoeffsListxListx;
    TabReduceCoeffs[T_VECFFE][T_VECFFE] = ReduceCoeffsVecFFEVecFFE;

    TabReduceCoeffsMod[T_LISTX ][T_LISTX ] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_LISTX ][T_VECTOR] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_LISTX ][T_VECFFE] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_LISTX ][T_VOID  ] = ReduceCoeffsModListx;
    TabReduceCoeffsMod[T_VECTOR][T_LISTX ] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_VECTOR][T_VECTOR] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_VECTOR][T_VECFFE] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_VECTOR][T_VOID  ] = ReduceCoeffsModListx;
    TabReduceCoeffsMod[T_VECFFE][T_LISTX ] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_VECFFE][T_VECTOR] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_VECFFE][T_VECFFE] = ReduceCoeffsModListxListx;
    TabReduceCoeffsMod[T_VECFFE][T_VOID  ] = ReduceCoeffsModListx;

    TabPowerModCoeffsInt[T_LISTX ][T_LISTX ] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_LISTX ][T_VECTOR] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_LISTX ][T_VECFFE] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_VECTOR][T_LISTX ] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_VECTOR][T_VECTOR] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_VECTOR][T_VECFFE] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_VECFFE][T_LISTX ] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_VECFFE][T_VECTOR] = PowerModListxIntListx;
    TabPowerModCoeffsInt[T_VECFFE][T_VECFFE] = PowerModVecFFEIntVecFFE;

    TabPowerModCoeffsLInt[T_LISTX ][T_LISTX ] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_LISTX ][T_VECTOR] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_LISTX ][T_VECFFE] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_VECTOR][T_LISTX ] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_VECTOR][T_VECTOR] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_VECTOR][T_VECFFE] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_VECFFE][T_LISTX ] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_VECFFE][T_VECTOR] = PowerModListxLIntListx;
    TabPowerModCoeffsLInt[T_VECFFE][T_VECFFE] = PowerModVecFFELIntVecFFE;

    /* install the internal functions                                      */
    InstIntFunc( "ShiftedCoeffs",   	FunShiftedCoeffs    );
    InstIntFunc( "NormalizeCoeffs",     FunNormalizeCoeffs  );
    InstIntFunc( "ShrinkCoeffs",        FunShrinkCoeffs  );
    InstIntFunc( "AddCoeffs",       	FunAddCoeffs 	    );
    InstIntFunc( "SumCoeffs",       	FunSumCoeffs 	    );
    InstIntFunc( "ProductCoeffs",   	FunProductCoeffs    );
    InstIntFunc( "ProductCoeffsMod",	FunProductCoeffsMod );
    InstIntFunc( "ReduceCoeffs",    	FunReduceCoeffs     );
    InstIntFunc( "RemainderCoeffs", 	FunRemainderCoeffs  );
    InstIntFunc( "ReduceCoeffsMod", 	FunReduceCoeffsMod  );
    InstIntFunc( "PowerModCoeffs",  	FunPowerModCoeffs   );
}
