/****************************************************************************
**
*F  WordVectorAndClear( <type>, <vv>, <num> )
*/
libGAP_Obj libGAP_WordVectorAndClear ( libGAP_Obj type, libGAP_Obj vv, libGAP_Int num )
{
    libGAP_Int         ebits;          /* number of bits in the exponent          */
    libGAP_UInt        expm;           /* unsigned exponent mask                  */
    libGAP_Int         i;              /* loop variable for gen/exp pairs         */
    libGAP_Int         j;              /* loop variable for exponent vector       */
    libGAP_Int *       qtr;            /* pointer into the collect vector         */
    libGAP_UIntN *     ptr;            /* pointer into the data area of <obj>     */
    libGAP_Obj         obj;            /* result                                  */

    /* get the number of bits for exponents                                */
    ebits = libGAP_EBITS_WORDTYPE(type);

    /* get the exponent mask                                               */
    expm = (1UL << ebits) - 1;

    /* construct a new object                                              */
    libGAP_NEW_WORD( obj, type, num );

    /* clear <vv>                                                          */
    ptr = (libGAP_UIntN*)libGAP_DATA_WORD(obj);
    qtr = (libGAP_Int*)(libGAP_ADDR_OBJ(vv)+1);
    for ( i = 1, j = 0;  i <= num;  i++,  qtr++ ) {
        if ( *qtr != 0 ) {
            *ptr++ = ((i-1) << ebits) | (*qtr & expm);
            *qtr = 0;
            j++;
        }
    }

    /* correct the size of <obj>                                           */
    (void) libGAP_RESIZE_WORD( obj, j );

    libGAP_MakeBagReadOnly( obj );

    return obj;
}


/****************************************************************************
**
*F  VectorWord( <vv>, <v>, <num> )
**
**  WARNING: This function assumes that <vv> is cleared!
*/
libGAP_Int libGAP_VectorWord ( libGAP_Obj vv, libGAP_Obj v, libGAP_Int num )
{
    libGAP_Int         ebits;          /* number of bits in the exponent          */
    libGAP_UInt        expm;           /* unsigned exponent mask                  */
    libGAP_UInt        exps;           /* sign exponent mask                      */
    libGAP_Int         i;              /* loop variable for gen/exp pairs         */
    libGAP_Int         pos;            /* generator number                        */
    libGAP_Int *       qtr;            /* pointer into the collect vector         */
    libGAP_UIntN *     ptr;            /* pointer into the data area of <obj>     */

    /* <vv> must be a string                                               */
    if ( libGAP_TNUM_OBJ(vv) != libGAP_T_STRING ) {
        if ( libGAP_TNUM_OBJ(vv) == libGAP_IMMUTABLE_TNUM(libGAP_T_STRING) ) {
            libGAP_RetypeBag( vv, libGAP_T_STRING );
        }
        else {
            libGAP_ErrorQuit( "collect vector must be a string not a %s", 
                       (libGAP_Int)libGAP_TNAM_OBJ(vv), 0L );
            return -1;
        }
    }

    /* fix the length                                                      */
    if ( libGAP_SIZE_OBJ(vv) != num*sizeof(libGAP_Int)+sizeof(libGAP_Obj)+1 ) {
        libGAP_ResizeBag( vv, num*sizeof(libGAP_Int)+sizeof(libGAP_Obj)+1 );
        for ( i = num, qtr = (libGAP_Int*)(libGAP_ADDR_OBJ(vv)+1);  0 < i;  i--, qtr++ )
            *qtr = 0;
    }

    /* if <v> is zero, return                                              */
    if ( v == 0 )
        return 0;

    /* get the number of bits for exponents                                */
    ebits = libGAP_EBITS_WORD(v);

    /* get the exponent masks                                              */
    exps = 1UL << (ebits-1);
    expm = exps - 1;

    /* unfold <v> into <vv>                                                */
    ptr = (libGAP_UIntN*)libGAP_DATA_WORD(v);
    qtr = (libGAP_Int*)libGAP_ADDR_OBJ(vv);
    for ( i = libGAP_NPAIRS_WORD(v);  0 < i;  i--, ptr++ ) {
        pos = ((*ptr) >> ebits)+1;
        if ( pos > num ) {
           libGAP_ErrorQuit( "word contains illegal generators %d", (libGAP_Int)i, 0L );
           return 0;
        }
        if ( (*ptr) & exps )
            qtr[pos] = ((*ptr)&expm)-exps;
        else
            qtr[pos] = (*ptr)&expm;
    }
    return 0;
}

/****************************************************************************
**
*F  SingleCollectWord( <sc>, <vv>, <w> )
**
**  If a stack overflow occurs, we simply stop and return false.
**
**  SC_PUSH_WORD( word, exp )
**    push <word>  with global exponent <exp>  into the stack, the macro uses
**    <word> and <exp> only once.
**
**  SC_POP_WORD()
**    remove topmost word from stack
*/
#define libGAP_SC_PUSH_WORD( word, exp ) \
    if ( ++sp == max ) { \
        libGAP_TLS(libGAP_SC_MAX_STACK_SIZE) *= 2; \
        return -1; \
    } \
    *++nw = (void*)libGAP_DATA_WORD(word); \
    *++lw = *nw + (libGAP_INT_INTOBJ((((libGAP_Obj*)(*nw))[-1])) - 1); \
    *++pw = *nw; \
    *++ew = (**pw) & expm; \
    *++ge = exp

#define libGAP_SC_POP_WORD() \
    sp--;  nw--;  lw--;  pw--;  ew--;  ge--


/****************************************************************************
**
**  The following functions are  used to add  a word into the exponent vector
**  without collection.  Two different cases occur:
**
**  Add   a word  into  the exponent  vector.   Here we   can  use the global
**  exponent.
**
**  Add part  of a word  into the  exponent vector.   Here  we cannot use the
**  global exponent because the beginning of  the word might not commute with
**  the rest.
**/
static libGAP_Int libGAP_SAddWordIntoExpVec( libGAP_Int *v, libGAP_UIntN *w, libGAP_Int e, 
                           libGAP_Int ebits, libGAP_UInt expm, 
                           libGAP_Obj *ro, libGAP_Obj *pow, libGAP_Int lpow ) {

    libGAP_UIntN *    wend = w + (libGAP_INT_INTOBJ((((libGAP_Obj*)(w))[-1])) - 1);
    libGAP_Int        i;
    libGAP_Int        ex;
    libGAP_Int        start = 0;

    for( ; w <= wend; w++ ) {
        i = ((*w) >> ebits) + 1; 
        v[ i ] += ((*w) & expm) * e;      /* overflow check necessary? */
        if ( libGAP_INT_INTOBJ(ro[i]) <= v[i] ) {
            ex = v[i] / libGAP_INT_INTOBJ(ro[i]);
            v[i] -= ex * libGAP_INT_INTOBJ(ro[i]);
            if ( i <= lpow && pow[i] && 0 < libGAP_NPAIRS_WORD(pow[i]) ) {
                start = libGAP_SAddWordIntoExpVec( 
                    v, (libGAP_UIntN*)libGAP_DATA_WORD(pow[i]), ex,
                    ebits, expm, ro, pow, lpow  );
            }
        }
        if( start < i && v[i] ) start = i;
    }
    return start;
}

static libGAP_Int libGAP_SAddPartIntoExpVec( libGAP_Int *v, libGAP_UIntN *w, libGAP_UIntN *wend,
                           libGAP_Int ebits, libGAP_UInt expm, 
                           libGAP_Obj* ro, libGAP_Obj *pow, libGAP_Int lpow ) {

    libGAP_Int        i;
    libGAP_Int        ex;
    libGAP_Int        start = 0;

    for( ; w <= wend; w++ ) {
        i = ((*w) >> ebits) + 1; 
        v[ i ] += ((*w) & expm);     /* overflow check necessary? */
        if ( libGAP_INT_INTOBJ(ro[i]) <= v[i] ) {
            ex = v[i] / libGAP_INT_INTOBJ(ro[i]);
            v[i] -= ex * libGAP_INT_INTOBJ(ro[i]);
            if ( i <= lpow && pow[i] && 0 < libGAP_NPAIRS_WORD(pow[i]) ) {
                start = libGAP_SAddWordIntoExpVec( 
                    v, (libGAP_UIntN*)libGAP_DATA_WORD(pow[i]), ex,
                    ebits, expm, ro, pow, lpow  );
            }
        }
        if( start < i && v[i] ) start = i;
    }
    return start;
}

libGAP_Int libGAP_SingleCollectWord ( libGAP_Obj sc, libGAP_Obj vv, libGAP_Obj w )
{
    libGAP_Int         ebits;      /* number of bits in the exponent              */
    libGAP_UInt        expm;       /* unsigned exponent mask                      */
    libGAP_UInt        exps;       /* sign exponent mask                          */

    libGAP_Obj         vnw;        /* word stack                                  */
    libGAP_UIntN **    nw;         /* address of <vnw>                            */
    libGAP_Obj         vlw;        /* last syllable stack                         */
    libGAP_UIntN **    lw;         /* address of <vlw>                            */
    libGAP_Obj         vpw;        /* current syllable stack                      */
    libGAP_UIntN **    pw;         /* address of <vpw>                            */
    libGAP_Obj         vew;        /* unprocessed exponent stack                  */
    libGAP_UIntN *     ew;         /* address of <vew>                            */
    libGAP_Obj         vge;        /* global exponent stack                       */
    libGAP_Int *       ge;         /* address of <vge>                            */

    libGAP_Obj         vpow;       /* rhs of power relations                      */
    libGAP_Int         lpow;       /* length of <vpow>                            */
    libGAP_Obj *       pow;        /* address of <vpow>                           */

    libGAP_Obj         vcnj;       /* rhs of conjugate relations                  */
    libGAP_Int         lcnj;       /* length of <vcnj>                            */
    libGAP_Obj *       cnj;        /* address of <vcnj>                           */

    libGAP_Obj *       avc;        /* address of the avector                      */
    libGAP_Obj *       gns;        /* address of the list of generators           */
    libGAP_Obj *       ro;         /* address of the list of relative orders      */
    libGAP_Obj *       inv;        /* address of the list of inverses             */

    libGAP_Int *       v;          /* address of <vv>                             */

    libGAP_Int         max;        /* maximal stack size                          */
    libGAP_Int         sp;         /* stack pointer                               */
    libGAP_Int         i, j;       /* loop variable                               */
    libGAP_Int         gn;         /* current generator number                    */
    libGAP_Int         ex;         /* current exponent                            */
    libGAP_Int         start;      /* last non-trivial entry                      */

    libGAP_Obj         tmp;        /* temporary obj for power                     */

    libGAP_Int         resized = 0;/* indicates whether a Resize() happened       */

    /* <start> is the first non-trivial entry in <v>                       */
    start = libGAP_SC_NUMBER_RWS_GENERATORS(sc);

    /* if <w> is the identity return now                                   */
    if ( libGAP_NPAIRS_WORD(w) == 0 ) {
        return start;
    }

    /* get the number of bits for exponents                                */
    ebits = libGAP_EBITS_WORDTYPE( libGAP_SC_DEFAULT_TYPE(sc) );

    /* get the exponent mask                                               */
    expm = (1UL << ebits) - 1;

    /* get the exponent sign masks                                         */
    exps = 1UL << (ebits-1);

    /* <nw> contains the stack of words to insert                          */
    vnw = libGAP_TLS(libGAP_SC_NW_STACK);

    /* <lw> contains the word end of the word in <nw>                      */
    vlw = libGAP_TLS(libGAP_SC_LW_STACK);

    /* <pw> contains the position of the word in <nw> to look at           */
    vpw = libGAP_TLS(libGAP_SC_PW_STACK);

    /* <ew> contains the unprocessed exponents at position <pw>            */
    vew = libGAP_TLS(libGAP_SC_EW_STACK);

    /* <ge> contains the global exponent of the word                       */
    vge = libGAP_TLS(libGAP_SC_GE_STACK);

    /* get the maximal stack size                                          */
    max = libGAP_TLS(libGAP_SC_MAX_STACK_SIZE);

    /* ensure that the stacks are large enough                             */
    if ( libGAP_SIZE_OBJ(vnw)/sizeof(libGAP_Obj) < max+1 ) {
        libGAP_ResizeBag( vnw, sizeof(libGAP_Obj)*(max+1) );
        libGAP_RetypeBag( vnw, libGAP_T_STRING );
        resized = 1;
    }
    if ( libGAP_SIZE_OBJ(vlw)/sizeof(libGAP_Obj) < max+1 ) {
        libGAP_ResizeBag( vlw, sizeof(libGAP_Obj)*(max+1) );
        libGAP_RetypeBag( vlw, libGAP_T_STRING );
        resized = 1;
    }
    if ( libGAP_SIZE_OBJ(vpw)/sizeof(libGAP_Obj) < max+1 ) {
        libGAP_ResizeBag( vpw, sizeof(libGAP_Obj)*(max+1) );
        libGAP_RetypeBag( vpw, libGAP_T_STRING );
        resized = 1;
    }
    if ( libGAP_SIZE_OBJ(vew)/sizeof(libGAP_Obj) < max+1 ) {
        libGAP_ResizeBag( vew, sizeof(libGAP_Obj)*(max+1) );
        libGAP_RetypeBag( vew, libGAP_T_STRING );
        resized = 1;
    }
    if ( libGAP_SIZE_OBJ(vge)/sizeof(libGAP_Obj) < max+1 ) {
        libGAP_ResizeBag( vge, sizeof(libGAP_Obj)*(max+1) );
        libGAP_RetypeBag( vge, libGAP_T_STRING );
        resized = 1;
    }
    if( resized ) return -1;

    /* from now on we use addresses instead of handles most of the time    */
    v  = (libGAP_Int*)libGAP_ADDR_OBJ(vv);
    nw = (libGAP_UIntN**)libGAP_ADDR_OBJ(vnw);
    lw = (libGAP_UIntN**)libGAP_ADDR_OBJ(vlw);
    pw = (libGAP_UIntN**)libGAP_ADDR_OBJ(vpw);
    ew = (libGAP_UIntN*)libGAP_ADDR_OBJ(vew);
    ge = (libGAP_Int*)libGAP_ADDR_OBJ(vge);

    /* conjujagtes, powers, order, generators, avector, inverses           */
    vpow = libGAP_SC_POWERS(sc);
    lpow = libGAP_LEN_PLIST(vpow);
    pow  = libGAP_ADDR_OBJ(vpow);

    vcnj = libGAP_SC_CONJUGATES(sc);
    lcnj = libGAP_LEN_PLIST(vcnj);
    (void) lcnj; /* please compiler -- lcnj not actually used */
    cnj  = libGAP_ADDR_OBJ(vcnj);

    avc = libGAP_ADDR_OBJ( libGAP_SC_AVECTOR(sc) );
    gns = libGAP_ADDR_OBJ( libGAP_SC_RWS_GENERATORS(sc) );

    ro  = libGAP_ADDR_OBJ( libGAP_SC_RELATIVE_ORDERS(sc) );
    inv = libGAP_ADDR_OBJ( libGAP_SC_INVERSES(sc) );

    /* initialize the stack with <w>                                        */
    sp = 0;
    libGAP_SC_PUSH_WORD( w, 1 );

    /* run until the stack is empty                                        */
    while ( 0 < sp ) {

        /* if <ew> is negative use inverse                                 */
        if ( *ew & exps ) {
            gn = ((**pw) >> ebits) + 1;
            ex = ( *ew & (exps-1) ) - exps;
            *ew = 0;
            libGAP_SC_PUSH_WORD( inv[gn], -ex );
        }

        /* if <ew> is zero get next syllable                               */
        else if ( 0 == *ew ) {

            /* if <pw> has reached <lw> get next & reduce globale exponent */
            if ( *pw == *lw ) {

                /* if the globale exponent is greater one reduce it        */
                if ( 1 < *ge ) {
                    (*ge)--;
                    *pw = *nw;
                    *ew = (**pw) & expm;
                }

                /* otherwise get the next word from the stack              */
                else {
                    libGAP_SC_POP_WORD();
                }
            }

            /* otherwise set <ew> to exponent of next syllable             */
            else {
                (*pw)++;
                *ew = (**pw) & expm;
            }
        }

        /* now move the next generator to the correct position             */
        else {

            /* get generator number                                        */
            gn = ((**pw) >> ebits) + 1;

            /* we can move <gn> directly to the correct position           */
            if ( libGAP_INT_INTOBJ(avc[gn]) == gn ) {
              /*
              *T  This if-statement implies that the next two cases are never
              *T  executed.  This is intended for the time being because we 
              *T  need the single collector to work with pc-presentations
              *T  whose rhs are not reduced while the next two if-case need
              *T  reduced rhs.  This will be fixed at a later stage.
              */
                v[gn] += *ew;
                *ew = 0;
                if ( start <= gn )
                    start = gn;
            }

            /* collect a whole word exponent pair                          */
            else if( *pw == *nw && libGAP_INT_INTOBJ(avc[gn]) == gn ) {
              gn = libGAP_SAddWordIntoExpVec( 
                   v, *pw, *ge, ebits, expm, ro, pow, lpow  );
              *pw = *lw;
              *ew = *ge = 0;

              if( start <= gn ) start = gn;
              continue;
            }

            /* move the rest of a word directly into the correct positions */
            else if( libGAP_INT_INTOBJ(avc[gn]) == gn ) {
              gn = libGAP_SAddPartIntoExpVec( 
                   v, *pw, *lw, ebits, expm, ro, pow, lpow  );
              *pw = *lw;
              *ew = 0;

              if( start <= gn ) start = gn;
              continue;
            }

            /* we have to move <gn> step by step                           */
            else {
                (*ew)--; v[gn]++;

                i = libGAP_INT_INTOBJ(avc[gn]);
                if ( start < i )
                    i = start;

                /* Find the first position in v from where on ordinary
                   collection  has to be applied.                          */
                for( ; gn < i; i-- )
                    if( v[i] && gn <= libGAP_LEN_PLIST(cnj[i]) ) {
                        tmp = libGAP_ELM_PLIST( cnj[i], gn );
                        if ( tmp != 0 && 0 < libGAP_NPAIRS_WORD(tmp) )
                            break;
                    }

                /* Stack up this part of v if we run through the next 
                   for-loop or if a power relation will be applied         */
                if( gn < i || (libGAP_INT_INTOBJ(ro[gn]) <= v[gn] &&
                    gn <= lpow && pow[gn] && 0 < libGAP_NPAIRS_WORD(pow[gn])) ) {
                    j = libGAP_INT_INTOBJ(avc[gn]);
                    for( ; i < j; j-- )
                        if( v[j] ) {
                            libGAP_SC_PUSH_WORD( gns[j], v[j] );
                            v[j] = 0;
                        }
                }

                if( gn < i ) {
                  for ( ;  gn < i;  i-- ) {
                    if ( v[i] ) {
                        if ( libGAP_LEN_PLIST(cnj[i]) < gn )
                            tmp = gns[i];
                        else {
                            tmp = libGAP_ELM_PLIST( cnj[i], gn );
                            if ( tmp == 0 || libGAP_NPAIRS_WORD(tmp) == 0 )
                                tmp = gns[i];
                        }
                        libGAP_SC_PUSH_WORD( tmp, v[i] );
                        v[i] = 0;
                    }
                  }
                  if ( start <= libGAP_INT_INTOBJ(avc[gn]) )
                    start = gn;
                }
                if( start <= gn ) start = gn;
            }

            /* check that the exponent is not too big                      */
            if ( libGAP_INT_INTOBJ(ro[gn]) <= v[gn] ) {
                i = v[gn] / libGAP_INT_INTOBJ(ro[gn]);
                v[gn] -= i * libGAP_INT_INTOBJ(ro[gn]);
                if ( gn <= lpow && pow[gn] && 0 < libGAP_NPAIRS_WORD(pow[gn]) ) {
                    libGAP_SC_PUSH_WORD( pow[gn], i );
                }
            }
        }
    }
    return start;
}
#undef libGAP_SC_PUSH_WORD
#undef libGAP_SC_POP_WORD


/****************************************************************************
**
*F  Solution( <sc>, <ww>, <uu>, <func> )
*/
libGAP_Int libGAP_Solution( 
    libGAP_Obj         sc,
    libGAP_Obj         ww,
    libGAP_Obj         uu,
    libGAP_FuncIOOO    func )
{
    libGAP_Int         ebits;          /* number of bits in the exponent          */
    libGAP_UInt        expm;           /* unsigned exponent mask                  */
    libGAP_Int         num;            /* number of gen/exp pairs in <data>       */
    libGAP_Int         i;              /* loop variable for gen/exp pairs         */
    libGAP_Int         ro;             /* relative order                          */
    libGAP_Obj         rod;            /* relative orders                         */
    libGAP_Obj         g;              /* one generator word                      */
    libGAP_UIntN *     gtr;            /* pointer into the data area of <g>       */
    libGAP_Int *       ptr;            /* pointer into the collect vector         */
    libGAP_Int *       qtr;            /* pointer into the collect vector         */

    /* get the number of generators                                        */
    num = libGAP_SC_NUMBER_RWS_GENERATORS(sc);
    rod = libGAP_SC_RELATIVE_ORDERS(sc);

    /* <ww> must be a string                                               */
    if ( libGAP_TNUM_OBJ(ww) != libGAP_T_STRING ) {
        if ( libGAP_TNUM_OBJ(ww) == libGAP_IMMUTABLE_TNUM(libGAP_T_STRING) ) {
            libGAP_RetypeBag( ww, libGAP_T_STRING );
        }
        else {
            libGAP_ErrorQuit( "collect vector must be a string not a %s", 
                       (libGAP_Int)libGAP_TNAM_OBJ(ww), 0L );
            return -1;
        }
    }

    /* fix the length                                                      */
    if ( libGAP_SIZE_OBJ(ww) != num*sizeof(libGAP_Int)+sizeof(libGAP_Obj)+1 ) {
        i = (libGAP_SIZE_OBJ(ww)-sizeof(libGAP_Obj)-1) / sizeof(libGAP_Int);
        libGAP_ResizeBag( ww, num*sizeof(libGAP_Int)+sizeof(libGAP_Obj)+1 );
        qtr = (libGAP_Int*)(libGAP_ADDR_OBJ(ww)+1);
        for ( i = i+1;  i <= num;  i++ )
            qtr[i] = 0;
    }

    /* <uu> must be a string                                               */
    if ( libGAP_TNUM_OBJ(uu) != libGAP_T_STRING ) {
        if ( libGAP_TNUM_OBJ(uu) == libGAP_IMMUTABLE_TNUM(libGAP_T_STRING) ) {
            libGAP_RetypeBag( uu, libGAP_T_STRING );
        }
        else {
            libGAP_ErrorQuit( "collect vector must be a string not a %s", 
                       (libGAP_Int)libGAP_TNAM_OBJ(uu), 0L );
            return -1;
        }
    }

    /* fix the length                                                      */
    if ( libGAP_SIZE_OBJ(uu) != num*sizeof(libGAP_Int)+sizeof(libGAP_Obj)+1 ) {
        i = (libGAP_SIZE_OBJ(uu)-sizeof(libGAP_Obj)-1) / sizeof(libGAP_Int);
        libGAP_ResizeBag( uu, num*sizeof(libGAP_Int)+sizeof(libGAP_Obj)+1 );
        qtr = (libGAP_Int*)(libGAP_ADDR_OBJ(uu)+1);
        for ( i = i+1;  i <= num;  i++ )
            qtr[i] = 0;
    }

    /* get the number of bits for exponents                                */
    ebits = libGAP_EBITS_WORDTYPE( libGAP_SC_DEFAULT_TYPE(sc) );

    /* get the exponent mask                                               */
    expm = (1UL << ebits) - 1;

    /* use <g> as right argument for the collector                         */
    libGAP_NEW_WORD( g, libGAP_SC_DEFAULT_TYPE(sc), 1 );

    /* start clearing <ww>, storing the result in <uu>                     */
    ptr = (libGAP_Int*)(libGAP_ADDR_OBJ(ww)+1);
    qtr = (libGAP_Int*)(libGAP_ADDR_OBJ(uu)+1);
    gtr = (libGAP_UIntN*)libGAP_DATA_WORD(g);
    for ( i = 0;  i < num; i++, ptr++, qtr++ ) {
        ro = libGAP_INT_INTOBJ(libGAP_ELMW_LIST(rod,i+1));
        *qtr = ( *qtr - *ptr ) % ro;
        if ( *qtr < 0 )  *qtr += ro;
        if ( *qtr != 0 ) {
            *gtr = ( i << ebits ) | ( *qtr & expm );
            if ( func(sc,ww,g) == -1 )
                return -1;
        }
        *ptr = 0;
    }
    return 0;
}

#undef libGAP_WordVectorAndClear
#undef libGAP_VectorWord
#undef libGAP_SingleCollectWord
#undef libGAP_SAddWordIntoExpVec
#undef libGAP_SAddPartIntoExpVec
#undef libGAP_SingleCollectWord
#undef libGAP_Solution
#undef libGAP_UIntN
