Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/src/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 125 kB image not shown  

Quelle  vecgf2.c

  Sprache: C
 

/****************************************************************************
**
**  This file is part of GAP, a system for computational discrete algebra.
**
**  Copyright of GAP belongs to its developers, whose names are too numerous
**  to list here. Please refer to the COPYRIGHT file for details.
**
**  SPDX-License-Identifier: GPL-2.0-or-later
*/


#include "vecgf2.h"

#include "ariths.h"
#include "bits_intern.h"
#include "blister.h"
#include "bool.h"
#include "error.h"
#include "finfield.h"
#include "gvars.h"
#include "integer.h"
#include "lists.h"
#include "modules.h"
#include "opers.h"
#include "plist.h"
#include "precord.h"
#include "range.h"
#include "records.h"
#include "stats.h"
#include "vec8bit.h"

#include <gmp.h>


/****************************************************************************
**
*F * * * * * * * * * * * imported library variables * * * * * * * * * * * * *
*/



/****************************************************************************
**
*V  TYPE_LIST_GF2VEC  . . . . . . . . . . . . . . type of a GF2 vector object
*/

Obj TYPE_LIST_GF2VEC;


/****************************************************************************
**
*V  TYPE_LIST_GF2VEC_LOCKED. . . .  type of a mutable GF2 vector object
**                                          with locked representation
*/

Obj TYPE_LIST_GF2VEC_LOCKED;


/****************************************************************************
**
*V  TYPE_LIST_GF2VEC_IMM  . . . . . .  type of an immutable GF2 vector object
*/

Obj TYPE_LIST_GF2VEC_IMM;

/****************************************************************************
**
*V  TYPE_LIST_GF2VEC_IMM_LOCKED . . .  type of an immutable GF2 vector object
**                                          with locked representation
*/

Obj TYPE_LIST_GF2VEC_IMM_LOCKED;


/****************************************************************************
**
*V  TYPE_LIST_GF2MAT  . . . . . . . . . . . . . . type of a GF2 matrix object
*/

Obj TYPE_LIST_GF2MAT;


/****************************************************************************
**
*V  TYPE_LIST_GF2MAT_IMM  . . . . . .  type of an immutable GF2 matrix object
*/

Obj TYPE_LIST_GF2MAT_IMM;


/****************************************************************************
**
*V  IsGF2VectorRep  . . . . . . . . . . . . . . . . . . . . . . . . .  filter
*/

Obj IsGF2VectorRep;


/****************************************************************************
**
*V  GF2One  . . . . . . . . . . . . . . . . . . . . . . . . . . .  one of GF2
*/

static Obj GF2One;


/****************************************************************************
**
*V  GF2Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . zero of GF2
*/

static Obj GF2Zero;


/****************************************************************************
**
*F * * * * * * * * * * * * arithmetic operations  * * * * * * * * * * * * * *
*/


static inline void AddGF2VecToGF2Vec(UInt * ptS, const UInt * ptV, UInt len)
{
    register UInt ct;
    ct = (len + BIPEB - 1) / BIPEB;
    while (ct--) {
        *ptS++ ^= *ptV++;
    }
}

/****************************************************************************
**
*F  AddCoeffsGF2VecGF2Vec( <sum>, <vec> ) . . . . . . . .  add <vec> to <sum>
**
**  `AddCoeffsGF2VecGF2Vec' adds  the   entries of <vec>  to <sum>.    If the
**  length  are not equal the  missing entries are  assumed  to be zero.  The
**  position of the rightmost Z(2) is returned.
*/


static UInt RightMostOneGF2Vec(Obj vec)
{
    UInt len;

    len = LEN_GF2VEC(vec);
    while (0 < len) {
        if (CONST_BLOCK_ELM_GF2VEC(vec, len) == 0)
            len = BIPEB * ((len - 1) / BIPEB);
        else if (BLOCK_ELM_GF2VEC(vec, len) & MASK_POS_GF2VEC(len))
            break;
        else
            len--;
    }
    return len;
}


static Obj AddCoeffsGF2VecGF2Vec(Obj sum, Obj vec)
{
    UInt *       ptS;
    const UInt * ptV;
    UInt         len;

    // get the length
    len = LEN_GF2VEC(vec);

    // grow <sum> is necessary
    if (LEN_GF2VEC(sum) < len) {
        ResizeWordSizedBag(sum, SIZE_PLEN_GF2VEC(len));
        SET_LEN_GF2VEC(sum, len);
    }

    // add <vec> to <sum>
    ptS = BLOCKS_GF2VEC(sum);
    ptV = CONST_BLOCKS_GF2VEC(vec);
    AddGF2VecToGF2Vec(ptS, ptV, len);
    return INTOBJ_INT(RightMostOneGF2Vec(sum));
}


static inline void
CopySection_GF2Vecs(Obj src, Obj dest, UInt smin, UInt dmin, UInt nelts)
{
    UInt         soff;
    UInt         doff;
    const UInt * sptr;
    UInt *       dptr;

    // switch to zero-based indices and find the first blocks and so on
    soff = (smin - 1) % BIPEB;
    doff = (dmin - 1) % BIPEB;
    sptr = CONST_BLOCKS_GF2VEC(src) + (smin - 1) / BIPEB;
    dptr = BLOCKS_GF2VEC(dest) + (dmin - 1) / BIPEB;

    CopyBits(sptr, soff, dptr, doff, nelts);
    return;
}

/****************************************************************************
**
*F  AddPartialGF2VecGF2Vec( <sum>, <vl>, <vr>, <n> )  . . . . . . partial sum
**
**  'AddPartialGF2VecGF2Vec' adds the entries  of <vl> and <vr> starting from
**  that block which is corresponding to the entry with number <n> and stores
**  the result in <sum>.
**
**  Note: The other entries are set to be zero. So use a higher value for <n>
**        only for vectors, which both have leading zero-entries.
**
**  You  can use  the parameter  <n> for  example for  an  gauss-algorithm on
**  gf2-matrices  can be  improved,  because when  using the gauss-algorithm,
**  you  know that  the leading entries of two vectors to be  added are equal
**  zero. If <n> = 1 all entries are added.
**
**  Note that the caller has to ensure, that <sum> is a gf2-vector with the
**  correct size.
*/

static Obj AddPartialGF2VecGF2Vec(Obj sum, Obj vl, Obj vr, UInt n)
{
    const UInt * ptL;       // bit field of <vl>
    const UInt * ptR;       // bit field of <vr>
    UInt *       ptS;       // bit field of <sum>
    UInt *       end;       // end marker
    UInt         len;       // length of the list
    UInt         offset;    // number of block to start adding
    UInt         x;


    // both operands lie in the same field
    len = LEN_GF2VEC(vl);
    if (len != LEN_GF2VEC(vr)) {
        ErrorMayQuit("Vector +: vectors must have the same length", 0, 0);
    }


    // calculate the offset for adding
    if (n == 1) {
        ptL = CONST_BLOCKS_GF2VEC(vl);
        ptR = CONST_BLOCKS_GF2VEC(vr);
        ptS = BLOCKS_GF2VEC(sum);
        end = ptS + ((len + BIPEB - 1) / BIPEB);
    }
    else {
        offset = (n - 1) / BIPEB;
        ptL = CONST_BLOCKS_GF2VEC(vl) + offset;
        ptR = CONST_BLOCKS_GF2VEC(vr) + offset;
        ptS = BLOCKS_GF2VEC(sum) + offset;
        end = ptS + ((len + BIPEB - 1) / BIPEB) - offset;
    }

    // loop over the entries and add
    if (vl == sum)
        while (ptS < end) {
            // maybe remove this condition
            if ((x = *ptR) != 0)
                *ptS = *ptL ^ x;
            ptL++;
            ptS++;
            ptR++;
        }
    else if (vr == sum)
        while (ptS < end) {
            // maybe remove this condition
            if ((x = *ptL) != 0)
                *ptS = *ptR ^ x;
            ptL++;
            ptS++;
            ptR++;
        }
    else
        while (ptS < end)
            *ptS++ = *ptL++ ^ *ptR++;

    return sum;
}


/****************************************************************************
**
*F  ProdGF2VecGF2Vec( <vl>, <vr> )  . . . . . . .  product of two GF2 vectors
**
**  'ProdVecGF2VecGF2' returns  the product of  the two GF2 vectors <vl> and
**  <vr>.   The product is  the folded sum of   the corresponding entries of
**  <vl> and <vr>.
**
**  'ProdVecGF2VecGF2' is an improved  version of the general multiplication,
**  which  does not  call 'PROD'  but uses bit  operations instead.   It will
**  always return either 'GF2One' or 'GF2Zero'.
*/

#ifdef SYS_IS_64_BIT

#define PARITY_BLOCK(m)                                                      \
    do {                                                                     \
        m = m ^ (m >> 32);                                                   \
        m = m ^ (m >> 16);                                                   \
        m = m ^ (m >> 8);                                                    \
        m = m ^ (m >> 4);                                                    \
        m = m ^ (m >> 2);                                                    \
        m = m ^ (m >> 1);                                                    \
    } while (0)

#else

#define PARITY_BLOCK(m)                                                      \
    do {                                                                     \
        m = m ^ (m >> 16);                                                   \
        m = m ^ (m >> 8);                                                    \
        m = m ^ (m >> 4);                                                    \
        m = m ^ (m >> 2);                                                    \
        m = m ^ (m >> 1);                                                    \
    } while (0)

#endif

static Obj ProdGF2VecGF2Vec(Obj vl, Obj vr)
{
    const UInt * ptL;     // bit field of <vl>
    const UInt * ptR;     // bit field of <vr>
    UInt         lenL;    // length of the list
    UInt         lenR;    // length of the list
    UInt         len;     // minimum of the lengths
    UInt         nrb;     // number of whole blocks to use
    UInt         m;       // number of bits in a block
    UInt         n;       // number of bits in blist
    UInt         i;       // loop variable
    UInt         mask;    // bit selecting mask

    // both operands lie in the same field
    lenL = LEN_GF2VEC(vl);
    lenR = LEN_GF2VEC(vr);
    len = (lenL < lenR) ? lenL : lenR;

    if (len == 0) {
        ErrorMayQuit("Vector *: both vectors must have at least one entry",
                     (Int)0, (Int)0);
    }

    // loop over the entries and multiply
    ptL = CONST_BLOCKS_GF2VEC(vl);
    ptR = CONST_BLOCKS_GF2VEC(vr);
    nrb = len / BIPEB;
    n = 0;
    for (i = nrb; i > 0; i--) {
        m = (*ptL++) & (*ptR++);
        PARITY_BLOCK(m);
        n ^= m;
    }
    // now process the remaining bits

    mask = 1;
    for (i = 0; i < len % BIPEB; i++) {
        n ^= (mask & *ptL & *ptR) >> i;
        mask <<= 1;
    }

    return (n & 1) ? GF2One : GF2Zero;
}


/****************************************************************************
**
*F  ProdGF2VecGF2Mat( <vl>, <vr> )  . .  product of GF2 vector and GF2 matrix
**
**  'ProdGF2VecGF2Mat'  returns the product  of the  GF2 vector <vl>  and the
**  GF2 matrix  <vr>.   The product is   the sum of  the  rows of <vr>,  each
**  multiplied by the corresponding entry of <vl>.  Note that the  caller has
**  to ensure, that <vl> is a gf2-vector and <vr> is a gf2-matrix.
*/

static Obj ProdGF2VecGF2Mat(Obj vl, Obj vr)
{
    UInt         len;    // length of the list
    UInt         stop;
    UInt         col;     // length of the rows
    UInt         i;       // loop variables
    Obj          prod;    // product, result
    Obj          row1;    // top row of matrix
    UInt *       start;
    const UInt * ptL;
    UInt         mask;

    // both operands lie in the same field
    len = LEN_GF2VEC(vl);
    if (len > LEN_GF2MAT(vr))
        len = LEN_GF2MAT(vr);

    // make the result vector
    row1 = ELM_GF2MAT(vr, 1);
    col = LEN_GF2VEC(row1);
    NEW_GF2VEC(prod,
               (IS_MUTABLE_OBJ(vl) || IS_MUTABLE_OBJ(row1))
                   ? TYPE_LIST_GF2VEC
                   : TYPE_LIST_GF2VEC_IMM,
               col);

    // get the start and end block
    start = BLOCKS_GF2VEC(prod);
    ptL = CONST_BLOCKS_GF2VEC(vl);

    // loop over the vector
    for (i = 1; i <= len; ptL++) {

        // if the whole block is zero, get the next entry
        if (*ptL == 0) {
            i += BIPEB;
            continue;
        }

        // run through the block
        stop = i + BIPEB - 1;
        if (len < stop)
            stop = len;
        for (mask = 1; i <= stop; i++, mask <<= 1) {

            // if there is entry add the row to the result
            if ((*ptL & mask) != 0) {
                const UInt * ptRR = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(vr, i));
                AddGF2VecToGF2Vec(start, ptRR, col);
            }
        }
    }

    return prod;
}


/****************************************************************************
**
*F  ProdGF2MatGF2Vec( <ml>, <vr> )  . .  product of GF2 matrix and GF2 vector
**
**  'ProdGF2MatGF2Vec'  returns the product  of the  GF2 matrix <ml>  and the
**  GF2 vector  <vr>.   The ith entry of the
**  product is the inner product of  the  ith row of <ml> with <vr>.
**  Note that the  caller has
**  to ensure, that <ml> is a GF2 matrix and <vr> is a GF2 vector.
*/

static Obj ProdGF2MatGF2Vec(Obj ml, Obj vr)
{
    UInt         len;     // length of the vector
    UInt         ln1;     // length of the rows of the mx
    UInt         ln2;     // length of the matrix
    const UInt * ptL;     // bit field of <ml>[j]
    const UInt * ptR;     // bit field of <vr>
    UInt         nrb;     // number of blocks in blist
    UInt         m;       // number of bits in a block
    UInt         n;       // number of bits in blist
    UInt         i;       // loop variable
    UInt         j;       // loop variable
    Obj          prod;    // result
    UInt         mask;    // a one bit mask

    // both operands lie in the same field
    len = LEN_GF2VEC(vr);
    ln2 = LEN_GF2MAT(ml);
    if (0 == ln2) {
        ErrorMayQuit("PROD: empty GF2 matrix * GF2 vector not allowed", 0, 0);
    }

    ln1 = LEN_GF2VEC(ELM_GF2MAT(ml, 1));
    if (len > ln1) {
        len = ln1;
    }

    // make the result vector
    NEW_GF2VEC(prod,
               (IS_MUTABLE_OBJ(ELM_GF2MAT(ml, 1)) || IS_MUTABLE_OBJ(vr))
                   ? TYPE_LIST_GF2VEC
                   : TYPE_LIST_GF2VEC_IMM,
               ln2);

    // loop over the entries and multiply
    nrb = len / BIPEB;
    for (j = 1; j <= ln2; j++) {
        ptL = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(ml, j));
        ptR = CONST_BLOCKS_GF2VEC(vr);
        n = 0;
        for (i = 1; i <= nrb; i++) {
            m = (*ptL++) & (*ptR++);
            PARITY_BLOCK(m);
            n ^= m;
        }

        mask = 1;
        for (i = 0; i < len % BIPEB; i++) {
            n ^= (mask & *ptL & *ptR) >> i;
            mask <<= 1;
        }


        if (n & 1)
            BLOCK_ELM_GF2VEC(prod, j) |= MASK_POS_GF2VEC(j);
    }

    return prod;
}

/****************************************************************************
**
*F  ProdGF2MatGF2MatSimple( <ml>, <mr> ) . . . .  product of two GF2 matrices
*F  ProdGF2MatGF2MatAdvanced( <ml>, <mr>, <greaselevel>, <blocksize> )
**                                     . .  product of twp GF2 matrices
**
**  'ProdGF2MatGF2MatSimple' returns the product of the GF2 matrix <ml> and
**  the GF2 matrix <mr>. This simply calls ProdGF2VecGF2Mat once on each row.
**
**  ProdGF2MatGF2MatAdvanced uses the specified grease and blocking to
**  accelerate larger matrix multiplies. In this case, the matrix dimensions
**  must be compatible.
*/


static Obj ProdGF2MatGF2MatSimple(Obj ml, Obj mr)
{
    Obj  prod;
    UInt i;
    UInt len;
    Obj  row;
    Obj  rtype;
    len = LEN_GF2MAT(ml);
    prod = NewBag(T_POSOBJ, SIZE_PLEN_GF2MAT(len));
    SET_LEN_GF2MAT(prod, len);
    if (IS_MUTABLE_OBJ(ml) || IS_MUTABLE_OBJ(mr)) {
        SET_TYPE_POSOBJ(prod, TYPE_LIST_GF2MAT);
        if (IS_MUTABLE_OBJ(ELM_GF2MAT(ml, 1)) ||
            IS_MUTABLE_OBJ(ELM_GF2MAT(mr, 1)))
            rtype = TYPE_LIST_GF2VEC_LOCKED;
        else
            rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }
    else {
        SET_TYPE_POSOBJ(prod, TYPE_LIST_GF2MAT_IMM);
        rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }
    for (i = 1; i <= len; i++) {
        row = ProdGF2VecGF2Mat(ELM_GF2MAT(ml, i), mr);

        // Since I'm going to put this vector into a matrix, I must lock its
        // representation, so that it doesn't get rewritten over GF(2^k)
        SetTypeDatObj(row, rtype);
        SET_ELM_GF2MAT(prod, i, row);
        CHANGED_BAG(prod);
        TakeInterrupt();
    }
    return prod;
}


// Utility functions for the advanced matrix multiply code below


// extract nbits bits starting from position from in vector vptr
// return them as the nbits least significant bits in a UInt.
// Bits are always numbered least-significant first

static inline UInt getbits(const UInt * vptr, UInt from, UInt nbits)
{
    UInt wno = (from - 1) / BIPEB;
    UInt word1 = vptr[wno];
    UInt shift1 = (from - 1) % BIPEB;
    UInt lbit = shift1 + nbits;
    UInt word2;
    if (lbit <= BIPEB) {
        // range is all in one word
        word1 <<= BIPEB - lbit;
        word1 >>= BIPEB - nbits;
    }
    else {
        // range is split across two words
        word1 >>= shift1;
        lbit -= BIPEB;
        word2 = vptr[wno + 1];
        word2 <<= BIPEB - lbit;
        word2 >>= shift1 - lbit;
        word1 |= word2;
    }
    return word1;
}

// To avoid having a lot of arguments to the recursive getgreasedata function,
// we put the things that don't change in the recursive call into this
// structure

struct greaseinfo {
    UInt *        pgtags;
    UInt *        pgbuf;
    UInt          nblocks;
    UInt *        pgrules;
    const UInt ** prrows;
};


// Make if necessary the grease row for bits controlled by the data in g.
// Recursive so can't be inlined
static const UInt * getgreasedata(struct greaseinfo * g, UInt bits)
{
    UInt         x, y;
    const UInt * ps;
    UInt *       pd;
    const UInt * ps2;
    UInt         i;
    UInt *       pd1;
    switch (g->pgtags[bits]) {
    case 0:
        // Need to make the row
        x = g->pgrules[bits];
        y = bits ^ (1 << x);
        // make it by adding row x to grease vector indexed y
        ps = g->prrows[x];
        ps2 = getgreasedata(g, y);
        pd1 = g->pgbuf + (bits - 3) * g->nblocks;
        pd = pd1;
        // time critical inner loop
        for (i = g->nblocks; i > 0; i--)
            *pd++ = *ps++ ^ *ps2++;
        // record that we made it
        g->pgtags[bits] = 1;
        return pd1;

    case 1:
        // we've made this one already, so just return it
        return g->pgbuf + (bits - 3) * g->nblocks;

    case 2:
        // This one does not need making, bits actually
        // has just a single 1 bit in it
        return g->prrows[g->pgrules[bits]];
    }
    return (UInt *)0;    // can't actually get here; include the return to
                         // pacify compiler
}


static Obj
ProdGF2MatGF2MatAdvanced(Obj ml, Obj mr, UInt greasesize, UInt blocksize)
{
    Obj          prod;          // Product Matrix
    UInt         i, j, k, b;    // Loop counters
    UInt         gs;            // Actual level of grease for current block
    const UInt * rptr;          // Pointer to current row of ml
    UInt bits;    // current chunk of current row, for lookup in grease tables
    const UInt * v;          // pointer to computed grease vector
    UInt len, rlen, ilen;    // len = length of ml, ilen = row length of ml =
                             // length of mr, rlen = row length of mr
    Obj    row;    // current row of ml, or row of prod when it is being built
    Obj    rtype;              // type of rows of prod
    Obj    gbuf = (Obj)0;      // grease buffer
    Obj    gtags = (Obj)0;     // grease tags (whether that row is known yet
    Obj    grules = (Obj)0;    // rules for making new grease vectors
    UInt * pgrules;            // pointer to contents of grules
    UInt * pgtags = (UInt *)0;     // pointer to contents of gtags
    UInt * pgbuf = (UInt *)0;      // pointer to grease buffer
    UInt   nwords;                 // number of words in a row of mr
    UInt   glen;                   // 1 << greasesize
    UInt   bs;                     // actual size of current block
    UInt * pprow;                  // pointer into current row of prod
    Obj    lrowptrs;               // cache of direct pointers to rows of ml
    const UInt **     plrows;      // and a direct pointer to that cache
    Obj               rrowptrs;    // and for mr
    const UInt **     prrows;
    Obj               prowptrs;    // and for prod
    UInt **           pprows;
    struct greaseinfo g;

    len = LEN_GF2MAT(ml);
    row = ELM_GF2MAT(mr, 1);
    rlen = LEN_GF2VEC(row);
    ilen = LEN_GF2MAT(mr);
    nwords = NUMBER_BLOCKS_GF2VEC(row);

    // Make a zero product matrix
    prod = NewBag(T_POSOBJ, SIZE_PLEN_GF2MAT(len));
    SET_LEN_GF2MAT(prod, len);
    if (IS_MUTABLE_OBJ(ml) || IS_MUTABLE_OBJ(mr)) {
        SET_TYPE_POSOBJ(prod, TYPE_LIST_GF2MAT);
        if (IS_MUTABLE_OBJ(ELM_GF2MAT(ml, 1)) ||
            IS_MUTABLE_OBJ(ELM_GF2MAT(mr, 1)))
            rtype = TYPE_LIST_GF2VEC_LOCKED;
        else
            rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }
    else {
        SET_TYPE_POSOBJ(prod, TYPE_LIST_GF2MAT_IMM);
        rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }


    for (i = 1; i <= len; i++) {
        NEW_GF2VEC(row, rtype, rlen);
        SET_ELM_GF2MAT(prod, i, row);
        CHANGED_BAG(prod);
    }

    // Cap greasesize and blocksize by the actual length
    if (ilen < greasesize)
        greasesize = ilen;
    if (ilen < greasesize * blocksize)
        blocksize = (ilen + greasesize - 1) / greasesize;


    // calculate glen
    glen = 1 << greasesize;

    // Allocate memory

    lrowptrs = NewBag(T_DATOBJ, sizeof(UInt *) * len);
    rrowptrs = NewBag(T_DATOBJ, sizeof(UInt *) * ilen);
    prowptrs = NewBag(T_DATOBJ, sizeof(UInt *) * len);

    if (greasesize >= 2) {
        gbuf =
            NewBag(T_DATOBJ, sizeof(UInt) * nwords * (glen - 3) * blocksize);
        gtags = NewBag(T_DATOBJ, sizeof(UInt) * glen * blocksize);
        grules = NewBag(T_DATOBJ, sizeof(Int) * glen);


        // From here no garbage collections

        pgtags = (UInt *)ADDR_OBJ(gtags);
        pgrules = (UInt *)ADDR_OBJ(grules);
        pgbuf = (UInt *)ADDR_OBJ(gbuf);


        // Calculate the greasing rules
        for (j = 3; j < glen; j++)
            for (i = 0; i < greasesize; i++)
                if ((j & (1 << i)) != 0) {
                    pgrules[j] = i;
                    break;
                }
        for (j = 0; j < greasesize; j++)
            pgrules[1 << j] = j;

        // fill in some more bits of g
        g.pgrules = pgrules;
        g.nblocks = nwords;
    }

    // Take direct pointers to all the parts of all the matrices to avoid
    // multiple indirection overheads
    plrows = (const UInt **)ADDR_OBJ(lrowptrs);
    prrows = (const UInt **)ADDR_OBJ(rrowptrs);
    pprows = (UInt **)ADDR_OBJ(prowptrs);

    for (i = 0; i < len; i++) {
        plrows[i] = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(ml, i + 1));
        pprows[i] = BLOCKS_GF2VEC(ELM_GF2MAT(prod, i + 1));
    }
    for (i = 0; i < ilen; i++)
        prrows[i] = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(mr, i + 1));


    // OK, finally ready to start work
    // loop over blocks
    for (b = 1; b <= ilen; b += blocksize * greasesize) {
        // last block may be a small one
        bs = blocksize;
        if ((b + bs * greasesize) > ilen)
            bs = (ilen - b + greasesize) / greasesize;

        // If we're greasing, start afresh
        if (greasesize > 1) {
            for (k = 0; k < bs; k++) {
                for (j = 0; j < 1 << greasesize; j++)
                    pgtags[k * glen + j] = 0;
                // powers of 2 correspond to rows of mr
                for (j = 0; j < greasesize; j++)
                    pgtags[k * glen + (1 << j)] = 2;
            }
        }

        // For each block, we run through rows of ml & prod
        for (j = 1; j <= len; j++) {
            // get pointers
            rptr = plrows[j - 1];
            pprow = pprows[j - 1];

            // Now within the block, we have multiple grease-units, run
            // through them
            for (i = 0; i < bs; i++) {
                // start of current grease unit
                k = b + i * greasesize;

                // last unit of last block may be short
                gs = greasesize;
                if (k + gs > ilen)
                    gs = ilen - k + 1;

                // find the appropriate parts of grease tags
                // grease buffer and mr. Store in g

                if (gs > 1) {
                    g.pgtags = pgtags + glen * i;
                    g.pgbuf = pgbuf + (glen - 3) * nwords * i;
                    g.prrows = prrows + k - 1;
                }

                // get a chunk from a row of ml
                bits = getbits(rptr, k, gs);

                // 0 means nothing to do
                if (bits == 0)
                    continue;
                else if (bits == 1)    // handle this one specially to speed
                                       // up the greaselevel 1 case
                    v = prrows[k - 1];    // -1 is because k is 1-based index
                else
                    v = getgreasedata(
                        &g, bits);    // The main case
                                      // This function should be inlined
                AddGF2VecToGF2Vec(pprow, v, rlen);
            }
        }

        // Allow GAP to respond to Ctrl-C
        if (TakeInterrupt()) {
            // Might have been a garbage collection, reload everything
            if (greasesize >= 2) {
                pgtags = (UInt *)ADDR_OBJ(gtags);
                pgrules = (UInt *)ADDR_OBJ(grules);
                pgbuf = (UInt *)ADDR_OBJ(gbuf);
                // fill in some more bits of g
                g.pgrules = pgrules;
                g.nblocks = nwords;
            }
            plrows = (const UInt **)ADDR_OBJ(lrowptrs);
            prrows = (const UInt **)ADDR_OBJ(rrowptrs);
            pprows = (UInt **)ADDR_OBJ(prowptrs);
            for (i = 0; i < len; i++) {
                plrows[i] = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(ml, i + 1));
                pprows[i] = BLOCKS_GF2VEC(ELM_GF2MAT(prod, i + 1));
            }
            for (i = 0; i < ilen; i++)
                prrows[i] = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(mr, i + 1));
        }
    }
    return prod;
}

/****************************************************************************
**
*F  FuncPROD_GF2VEC_ANYMAT( <self>, <v>, <m>)
**
**  method to handle vector*plain list of GF2Vectors reasonably efficiently.
*/

static Obj FuncPROD_GF2VEC_ANYMAT(Obj self, Obj vec, Obj mat)
{
    Obj  res;
    UInt len;
    UInt len1;
    Obj  row1;
    UInt i;
    UInt block = 0;

    len = LEN_GF2VEC(vec);
    if (len > LEN_PLIST(mat))
        len = LEN_PLIST(mat);

    // Get the first row, to establish the size of the result
    row1 = ELM_PLIST(mat, 1);
    if (!IS_GF2VEC_REP(row1))
        return TRY_NEXT_METHOD;
    len1 = LEN_GF2VEC(row1);

    // create the result space
    NEW_GF2VEC(res,
               (IS_MUTABLE_OBJ(vec) || IS_MUTABLE_OBJ(row1))
                   ? TYPE_LIST_GF2VEC
                   : TYPE_LIST_GF2VEC_IMM,
               len1);

    // Finally, we start work
    for (i = 1; i <= len; i++) {
        if (i % BIPEB == 1)
            block = CONST_BLOCK_ELM_GF2VEC(vec, i);
        if (block & MASK_POS_GF2VEC(i)) {
            row1 = ELM_PLIST(mat, i);
            if (!IS_GF2VEC_REP(row1))
                return TRY_NEXT_METHOD;
            AddPartialGF2VecGF2Vec(res, res, row1, 1);
        }
    }
    return res;
}

/****************************************************************************
**
*F  InversePlistGF2VecsDesstructive( <list> )
**
**  This is intended to form the core of a method for InverseOp.
**  by this point it should be checked that list is a plain list of GF2
**  vectors of equal lengths.
*/

static Obj InversePlistGF2VecsDesstructive(Obj list)
{
    UInt         len;     // dimension
    Obj          inv;     // result
    Obj          row;     // row vector
    Obj          old;     // row from <mat>
    Obj          tmp;     // temporary
    UInt *       ptQ;     // data block of <row>
    const UInt * ptP;     // data block of source row
    const UInt * end;     // end marker
    const UInt * end2;    // end marker
    UInt         i;       // loop variable
    UInt         k;       // loop variable

    len = LEN_PLIST(list);

    // create the identity matrix
    tmp = NEW_PLIST(T_PLIST, len);
    for (i = len; 0 < i; i--) {
        NEW_GF2VEC(row, TYPE_LIST_GF2VEC, len);
        BLOCK_ELM_GF2VEC(row, i) |= MASK_POS_GF2VEC(i);
        SET_ELM_PLIST(tmp, i, row);
        CHANGED_BAG(tmp);
    }
    SET_LEN_PLIST(tmp, len);
    inv = tmp;

    // now start with ( id | mat ) towards ( inv | id )
    for (k = 1; k <= len; k++) {

        // find a nonzero entry in column <k>
        for (i = k; i <= len; i++) {
            row = ELM_PLIST(list, i);
            if (CONST_BLOCK_ELM_GF2VEC(row, k) & MASK_POS_GF2VEC(k))
                break;
        }
        if (i > len) {
            return Fail;
        }
        if (i != k) {
            row = ELM_PLIST(list, i);
            SET_ELM_PLIST(list, i, ELM_PLIST(list, k));
            SET_ELM_PLIST(list, k, row);
            row = ELM_PLIST(inv, i);
            SET_ELM_PLIST(inv, i, ELM_PLIST(inv, k));
            SET_ELM_PLIST(inv, k, row);
        }

        // clear entries
        old = ELM_PLIST(list, k);
        end = CONST_BLOCKS_GF2VEC(old) + ((len + BIPEB - 1) / BIPEB);
        for (i = 1; i <= len; i++) {
            if (i == k)
                continue;
            row = ELM_PLIST(list, i);
            if (CONST_BLOCK_ELM_GF2VEC(row, k) & MASK_POS_GF2VEC(k)) {

                // clear <mat>
                ptQ = &(BLOCK_ELM_GF2VEC(row, k));
                ptP = &(CONST_BLOCK_ELM_GF2VEC(old, k));
                while (ptP < end) {
                    *ptQ++ ^= *ptP++;
                }

                // modify <inv>
                row = ELM_PLIST(inv, i);
                ptQ = BLOCKS_GF2VEC(row);
                row = ELM_PLIST(inv, k);
                ptP = CONST_BLOCKS_GF2VEC(row);
                end2 = ptP + ((len + BIPEB - 1) / BIPEB);
                while (ptP < end2) {
                    *ptQ++ ^= *ptP++;
                }
            }
        }
        TakeInterrupt();
    }
    return inv;
}


/****************************************************************************
**
*F  InverseGF2Mat( <mat> )  . . . . . . . . . . . . . . inverse of GF2 matrix
**
**  This should be improved to work with mutable GF2 matrices
**
*/


static Obj InverseGF2Mat(Obj mat, UInt mut)
{
    UInt         len;    // dimension
    Obj          inv;    // result
    Obj          row;    // row vector
    Obj          tmp;    // temporary
    UInt         i;      // loop variable
    Obj          old;    // row from <mat>
    const UInt * ptQ;    // data block of <row>
    UInt *       ptP;    // data block of source row
    UInt *       end;    // end marker
    Obj          rtype;

    // make a structural copy of <mat> as list of GF2 vectors
    len = LEN_GF2MAT(mat);

    // special routes for very small matrices
    if (len == 0) {
        return CopyObj(mat, 1);
    }
    if (len == 1) {
        row = ELM_GF2MAT(mat, 1);
        if (CONST_BLOCKS_GF2VEC(row)[0] & 1) {
            return CopyObj(mat, 1);
        }
        else
            return Fail;
    }

    tmp = NEW_PLIST(T_PLIST, len);
    for (i = len; 0 < i; i--) {
        old = ELM_GF2MAT(mat, i);
        NEW_GF2VEC(row, TYPE_LIST_GF2VEC_IMM, len);
        ptQ = CONST_BLOCKS_GF2VEC(old);
        ptP = BLOCKS_GF2VEC(row);
        end = ptP + ((len + BIPEB - 1) / BIPEB);
        while (ptP < end)
            *ptP++ = *ptQ++;
        SET_ELM_PLIST(tmp, i, row);
        CHANGED_BAG(tmp);
    }
    SET_LEN_PLIST(tmp, len);
    inv = InversePlistGF2VecsDesstructive(tmp);
    if (inv == Fail)
        return inv;

    // convert list <inv> into a matrix
    ResizeBag(inv, SIZE_PLEN_GF2MAT(len));
    if (mut == 2 || (mut == 1 && IS_MUTABLE_OBJ(mat) &&
                     IS_MUTABLE_OBJ(ELM_GF2MAT(mat, 1))))
        rtype = TYPE_LIST_GF2VEC_LOCKED;
    else
        rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    for (i = len; 0 < i; i--) {
        row = ELM_PLIST(inv, i);
        SET_TYPE_POSOBJ(row, rtype);
        SET_ELM_GF2MAT(inv, i, row);
    }
    SET_LEN_GF2MAT(inv, len);
    RetypeBag(inv, T_POSOBJ);
    SET_TYPE_POSOBJ(inv, (mut == 2 || (mut == 1 && IS_MUTABLE_OBJ(mat)))
                             ? TYPE_LIST_GF2MAT
                             : TYPE_LIST_GF2MAT_IMM);
    return inv;
}

/****************************************************************************
**
*F  ShallowCopyVecGF2( <vec> )
**
*/


Obj ShallowCopyVecGF2(Obj vec)
{
    Obj          copy;
    UInt         len;
    const UInt * ptrS;
    UInt *       ptrD;
    len = LEN_GF2VEC(vec);
    NEW_GF2VEC(copy, TYPE_LIST_GF2VEC, len);
    ptrS = CONST_BLOCKS_GF2VEC(vec);
    ptrD = BLOCKS_GF2VEC(copy);
    memcpy(ptrD, ptrS, NUMBER_BLOCKS_GF2VEC(vec) * sizeof(UInt));
    return copy;
}

/****************************************************************************
**
*F  SemiEchelonPlistGF2Vecs( <mat>, <transformations-needed> )
**
**  The matrix needs to have mutable rows, so it can't be a GF2 mat
**
**  This has changed. There should now be a method for mutable GF2mats as
**  well.
**
**  This function DOES NOT CHECK that the rows are all GF2 vectors
**
**  Does not copy the matrix, may destroy it, may include some
**  of the rows among the returned vectors
*/



static UInt RNheads, RNvectors, RNcoeffs, RNrelns;


static Obj SemiEchelonListGF2Vecs(Obj mat, UInt TransformationsNeeded)
{
    UInt  nrows, ncols;
    UInt  i, j, h;
    Obj   heads, vectors, coeffs = 0, relns = 0;
    UInt  nvecs, nrels = 0;
    Obj   coeffrow = 0;
    Obj   row;
    UInt *rowp, *coeffrowp = 0;
    Obj   res;
    nrows = LEN_PLIST(mat);
    ncols = LEN_GF2VEC(ELM_PLIST(mat, 1));
    heads = NEW_PLIST(T_PLIST_CYC, ncols);
    SET_LEN_PLIST(heads, ncols);
    vectors = NEW_PLIST(T_PLIST_TAB_RECT, nrows);
    nvecs = 0;
    if (TransformationsNeeded) {
        coeffs = NEW_PLIST(T_PLIST_TAB_RECT, nrows);
        relns = NEW_PLIST(T_PLIST_TAB_RECT, nrows);
        nrels = 0;
    }
    for (i = 1; i <= ncols; i++)
        SET_ELM_PLIST(heads, i, INTOBJ_INT(0));
    for (i = 1; i <= nrows; i++) {
        row = ELM_PLIST(mat, i);
        if (TransformationsNeeded) {
            NEW_GF2VEC(coeffrow, TYPE_LIST_GF2VEC, nrows);
            BLOCK_ELM_GF2VEC(coeffrow, i) |= MASK_POS_GF2VEC(i);
        }

        // No garbage collection risk from here
        rowp = BLOCKS_GF2VEC(row);
        if (TransformationsNeeded)
            coeffrowp = BLOCKS_GF2VEC(coeffrow);
        for (j = 1; j <= ncols; j++) {
            h = INT_INTOBJ(ELM_PLIST(heads, j));
            if (h != 0) {
                if (rowp[(j - 1) / BIPEB] & MASK_POS_GF2VEC(j)) {
                    AddGF2VecToGF2Vec(
                        rowp, CONST_BLOCKS_GF2VEC(ELM_PLIST(vectors, h)),
                        ncols);
                    if (TransformationsNeeded)
                        AddGF2VecToGF2Vec(
                            coeffrowp,
                            CONST_BLOCKS_GF2VEC(ELM_PLIST(coeffs, h)), nrows);
                }
            }
        }
        j = 1;
        while (j <= ncols && !*rowp) {
            j += BIPEB;
            rowp++;
        }
        while (j <= ncols && !(*rowp & MASK_POS_GF2VEC(j)))
            j++;

        // garbage collection OK again after here
        if (j <= ncols) {
            SET_ELM_PLIST(vectors, ++nvecs, row);
            CHANGED_BAG(vectors);    // Could be an old bag by now. Max.
            SET_LEN_PLIST(vectors, nvecs);
            SET_ELM_PLIST(heads, j, INTOBJ_INT(nvecs));
            if (TransformationsNeeded) {
                SET_ELM_PLIST(coeffs, nvecs, coeffrow);
                CHANGED_BAG(coeffs);    // Could be an old bag by now. Max.
                SET_LEN_PLIST(coeffs, nvecs);
            }
        }
        else if (TransformationsNeeded) {
            SET_ELM_PLIST(relns, ++nrels, coeffrow);
            CHANGED_BAG(relns);    // Could be an old bag by now. Max.
            SET_LEN_PLIST(relns, nrels);
        }
        TakeInterrupt();
    }
    if (RNheads == 0) {
        RNheads = RNamName("heads");
        RNvectors = RNamName("vectors");
    }
    res = NEW_PREC(TransformationsNeeded ? 4 : 2);
    AssPRec(res, RNheads, heads);
    AssPRec(res, RNvectors, vectors);
    if (LEN_PLIST(vectors) == 0)
        RetypeBag(vectors, T_PLIST_EMPTY);
    if (TransformationsNeeded) {
        if (RNcoeffs == 0) {
            RNcoeffs = RNamName("coeffs");
            RNrelns = RNamName("relations");
        }
        AssPRec(res, RNcoeffs, coeffs);
        if (LEN_PLIST(coeffs) == 0)
            RetypeBag(coeffs, T_PLIST_EMPTY);
        AssPRec(res, RNrelns, relns);
        if (LEN_PLIST(relns) == 0)
            RetypeBag(relns, T_PLIST_EMPTY);
    }
    SortPRecRNam(res);
    return res;
}

/****************************************************************************
**
*F  UInt TriangulizeListGF2Vecs( <mat>, <clearup> ) -- returns the rank
**
**  Again should add a method to work with mutable GF2 matrices
**
*/


static UInt TriangulizeListGF2Vecs(Obj mat, UInt clearup)
{
    UInt         nrows;
    UInt         ncols;
    UInt         workcol;
    UInt         workrow;
    UInt         rank;
    Obj          row, row2;
    const UInt * rowp;
    UInt *       row2p;
    UInt         block;
    UInt         mask;
    UInt         j;
    nrows = LEN_PLIST(mat);
    ncols = LEN_GF2VEC(ELM_PLIST(mat, 1));
    rank = 0;

    // Nothing here can cause a garbage collection

    for (workcol = 1; workcol <= ncols; workcol++) {
        block = (workcol - 1) / BIPEB;
        mask = MASK_POS_GF2VEC(workcol);
        for (workrow = rank + 1;
             workrow <= nrows &&
             !(CONST_BLOCKS_GF2VEC(ELM_PLIST(mat, workrow))[block] & mask);
             workrow++)
            ;
        if (workrow <= nrows) {
            rank++;
            row = ELM_PLIST(mat, workrow);
            if (workrow != rank) {
                SET_ELM_PLIST(mat, workrow, ELM_PLIST(mat, rank));
                SET_ELM_PLIST(mat, rank, row);
            }
            rowp = CONST_BLOCKS_GF2VEC(row);
            if (clearup)
                for (j = 1; j < rank; j++) {
                    row2 = ELM_PLIST(mat, j);
                    row2p = BLOCKS_GF2VEC(row2);
                    if (row2p[block] & mask)
                        AddGF2VecToGF2Vec(row2p, rowp, ncols);
                }
            for (j = workrow + 1; j <= nrows; j++) {
                row2 = ELM_PLIST(mat, j);
                row2p = BLOCKS_GF2VEC(row2);
                if (row2p[block] & mask)
                    AddGF2VecToGF2Vec(row2p, rowp, ncols);
            }
        }
        TakeInterrupt();
    }
    return rank;
}

/****************************************************************************
**
*F * * * * * * * * * * * *  conversion functions  * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*F  PlainGF2Vec( <list> ) . . .  . convert a GF2 vector into an ordinary list
**
**  'PlainGF2Vec' converts the GF2 vector <list> to a plain list.
*/

static Obj IsLockedRepresentationVector;


static void PlainGF2Vec(Obj list)
{
    Int  len;          // length of <list>
    UInt i;            // loop variable
    Obj  first = 0;    // first entry

    // check for representation lock
    if (True == DoFilter(IsLockedRepresentationVector, list))
        ErrorMayQuit("Cannot convert a locked GF2 vector into a plain list",
                     0, 0);

    // resize the list and retype it, in this order
    len = LEN_GF2VEC(list);

    RetypeBagSM(list, (len == 0) ? T_PLIST_EMPTY : T_PLIST_FFE);

    GROW_PLIST(list, (UInt)len);
    SET_LEN_PLIST(list, len);

    // keep the first entry because setting the second destroys the first
    if (len == 0)
        SET_ELM_PLIST(list, 1, 0);
    else
        first = ELM_GF2VEC(list, 1);

    // wipe out the first entry of the GF2 vector (which becomes the  second
    // entry of the plain list, in case the list has length 1.
    if (len == 1)
        SET_ELM_PLIST(list, 2, 0);

    // replace the bits by 'GF2One' or 'GF2Zero' as the case may be
    // this must of course be done from the end of the list backwards
    for (i = len; 1 < i; i--)
        SET_ELM_PLIST(list, i, ELM_GF2VEC(list, i));
    if (len != 0)
        SET_ELM_PLIST(list, 1, first);

    CHANGED_BAG(list);
}


/****************************************************************************
**
*F  PlainGF2Mat( <list> ) . . .  . convert a GF2 matrix into an ordinary list
**
**  'PlainGF2Mat' converts the GF2 matrix <list> to a plain list.
*/

static void PlainGF2Mat(Obj list)
{
    Int  len;    // length of <list>
    UInt i;      // loop variable

    // resize the list and retype it, in this order
    len = LEN_GF2MAT(list);
    RetypeBagSM(list, T_PLIST);
    SET_LEN_PLIST(list, len);

    // shift the entries to the left
    for (i = 1; i <= len; i++) {
        SET_ELM_PLIST(list, i, ELM_GF2MAT(list, i));
    }
    SHRINK_PLIST(list, len);
    CHANGED_BAG(list);
}


/****************************************************************************
**
*F  ConvGF2Vec( <list> )  . . . . . . convert a list into a GF2 vector object
*/

static void ConvGF2Vec(Obj list)
{
    Int  len;      // logical length of the vector
    Int  i;        // loop variable
    UInt block;    // one block of the boolean list
    UInt bit;      // one bit of a block
    Obj  x;

    // already in the correct representation
    if (IS_GF2VEC_REP(list)) {
        return;
    }

    // Otherwise make it a plain list so that we will know where it keeps
    // its data -- could do much better in the case of GF(2^n) vectors that
    // actually lie over GF(2)

    if (IS_VEC8BIT_REP(list))
        PlainVec8Bit(list);
    else
        PLAIN_LIST(list);

    // change its representation
    len = LEN_PLIST(list);

    // We may have to resize the bag now because a length 1
    // plain list is shorter than a length 1 GF2VEC
    if (SIZE_PLEN_GF2VEC(len) > SIZE_OBJ(list))
        ResizeBag(list, SIZE_PLEN_GF2VEC(len));

    // now do the work
    block = 0;
    bit = 1;
    for (i = 1; i <= len; i++) {
        x = ELM_PLIST(list, i);
        if (x == GF2One)
            block |= bit;
        else if (x != GF2Zero) {
            // might be GF(2) elt written over bigger field
            if (EQ(x, GF2One))
                block |= bit;
            else if (!EQ(x, GF2Zero))
                ErrorMayQuit(
                    "COPY_GF2VEC: argument must be a list of GF2 elements",
                    0, 0);
        }

        bit = bit << 1;
        if (bit == 0 || i == len) {
            BLOCK_ELM_GF2VEC(list, i) = block;
            block = 0;
            bit = 1;
        }
    }

    // retype and resize bag
    ResizeWordSizedBag(list, SIZE_PLEN_GF2VEC(len));
    SET_LEN_GF2VEC(list, len);
    if (IS_PLIST_MUTABLE(list)) {
        SetTypeDatObj(list, TYPE_LIST_GF2VEC);
    }
    else {
        SetTypeDatObj(list, TYPE_LIST_GF2VEC_IMM);
    }
    RetypeBag(list, T_DATOBJ);
}


/****************************************************************************
**
*F  FuncCONV_GF2VEC( <self>, <list> ) . . . . . convert into a GF2 vector rep
*/

static Obj FuncCONV_GF2VEC(Obj self, Obj list)
{
    ConvGF2Vec(list);
    return 0;
}


/****************************************************************************
**
*F  NewGF2Vec( <list> )  . . . . . . convert a list into a GF2 vector object
**
**  This is a non-destructive counterpart of ConvGF2Vec
*/

static Obj NewGF2Vec(Obj list)
{
    Int  len;      // logical length of the vector
    Int  i;        // loop variable
    UInt block;    // one block of the boolean list
    UInt bit;      // one bit of a block
    Obj  x;
    Obj  res;    // resulting GF2 vector object

    // already in the correct representation
    if (IS_GF2VEC_REP(list)) {
        res = ShallowCopyVecGF2(list);
        if (!IS_MUTABLE_OBJ(list))
            SetTypeDatObj(res, TYPE_LIST_GF2VEC_IMM);
        return res;
    }

    if (!IS_LIST(list)) {
        ErrorMayQuit("COPY_GF2VEC: argument must be a list of GF2 elements",
                     0, 0);
    }
    if (!IS_PLIST(list)) {
        list = SHALLOW_COPY_OBJ(list);
        // TODO: if list is in 8bit rep, we could do better
        if (IS_VEC8BIT_REP(list))
            PlainVec8Bit(list);
        else
            PLAIN_LIST(list);
    }

    len = LEN_PLIST(list);
    NEW_GF2VEC(res, TYPE_LIST_GF2VEC, len);

    // now do the work
    block = 0;
    bit = 1;
    for (i = 1; i <= len; i++) {
        x = ELM_PLIST(list, i);
        if (x == GF2One)
            block |= bit;
        else if (x != GF2Zero) {
            // might be GF(2) elt written over bigger field
            if (EQ(x, GF2One))
                block |= bit;
            else if (!EQ(x, GF2Zero))
                ErrorMayQuit(
                    "COPY_GF2VEC: argument must be a list of GF2 elements",
                    0, 0);
        }

        bit = bit << 1;
        if (bit == 0 || i == len) {
            BLOCK_ELM_GF2VEC(res, i) = block;    // only changed list to res
            block = 0;
            bit = 1;
        }
    }

    // mutability should be inherited from the argument
    if (IS_PLIST_MUTABLE(list))
        SetTypeDatObj(res, TYPE_LIST_GF2VEC);
    else
        SetTypeDatObj(res, TYPE_LIST_GF2VEC_IMM);

    return res;
}


/****************************************************************************
**
*F  FuncCOPY_GF2VEC( <self>, <list> ) . . . . . convert into a GF2 vector rep
**
**  This is a non-destructive counterpart of FuncCONV_GF2VEC
*/

static Obj FuncCOPY_GF2VEC(Obj self, Obj list)
{
    list = NewGF2Vec(list);
    return list;
}

/****************************************************************************
**
*F FuncCONV_GF2MAT (<self>, <list> ) . . . convert into a GF2 matrix rep
**
** <list> should be a list of compressed GF2 vectors
**
*/

static Obj FuncCONV_GF2MAT(Obj self, Obj list)
{
    UInt len, i;
    Obj  tmp;
    UInt mut;
    len = LEN_LIST(list);
    if (len == 0)
        return (Obj)0;

    PLAIN_LIST(list);
    GROW_PLIST(list, len + 1);
    for (i = len; i > 0; i--) {
        tmp = ELM_PLIST(list, i);
        if (!IS_GF2VEC_REP(tmp)) {
            int j;
            for (j = i + 1; j <= len; j++) {
                tmp = ELM_PLIST(list, j + 1);
                SET_ELM_PLIST(list, j, tmp);
            }
            ErrorMayQuit("CONV_GF2MAT: argument must be a list of compressed "
                         "GF2 vectors",
                         0, 0);
        }
        SetTypeDatObj(tmp, IS_MUTABLE_OBJ(tmp) ? TYPE_LIST_GF2VEC_LOCKED
                                               : TYPE_LIST_GF2VEC_IMM_LOCKED);
        SET_ELM_PLIST(list, i + 1, tmp);
    }
    SET_ELM_PLIST(list, 1, INTOBJ_INT(len));
    mut = IS_PLIST_MUTABLE(list);
    RetypeBag(list, T_POSOBJ);
    SET_TYPE_POSOBJ(list, mut ? TYPE_LIST_GF2MAT : TYPE_LIST_GF2MAT_IMM);
    return (Obj)0;
}


/****************************************************************************
**
*F  FuncPLAIN_GF2VEC( <self>, <list> ) . . .  convert back into ordinary list
*/

static Obj FuncPLAIN_GF2VEC(Obj self, Obj list)
{
    if (!IS_GF2VEC_REP(list)) {
        RequireArgument(SELF_NAME, list, "must be a GF2 vector");
    }
    PlainGF2Vec(list);
    return 0;
}


/****************************************************************************
**
*F  revertbits -- utility function to reverse bit orders
*/



// A list of flip values for bytes (i.e. ..xyz -> zyx..)
static const UInt1 revertlist[] = {
    0,  128, 64, 192, 32, 160, 96,  224, 16, 144, 80, 208, 48, 176, 112, 240,
    8,  136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
    4,  132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
    12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
    2,  130, 66, 194, 34, 162, 98,  226, 18, 146, 82, 210, 50, 178, 114, 242,
    10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
    6,  134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
    14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
    1,  129, 65, 193, 33, 161, 97,  225, 17, 145, 81, 209, 49, 177, 113, 241,
    9,  137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
    5,  133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
    13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
    3,  131, 67, 195, 35, 163, 99,  227, 19, 147, 83, 211, 51, 179, 115, 243,
    11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
    7,  135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
    15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
};

// Takes an UInt a on n bits and returns the Uint obtained by reverting the
// bits
static UInt revertbits(UInt a, Int n)
{
    UInt b, c;
    b = 0;
    while (n > 8) {
        c = a & 0xff;    // last byte
        a = a >> 8;
        b = b << 8;
        b += (UInt)revertlist[(UInt1)c];    // add flipped
        n -= 8;
    }
    // cope with the last n bits
    a &= 0xff;
    b = b << n;
    c = (UInt)revertlist[(UInt1)a];
    c = c >> (8 - n);
    b += c;
    return b;
}

/****************************************************************************
**
*F  Cmp_GF2Vecs( <vl>, <vr> )   compare GF2 vectors -- internal
**                                    returns -1, 0 or 1
*/

static Int Cmp_GF2VEC_GF2VEC(Obj vl, Obj vr)
{
    UInt         i;                  // loop variable
    const UInt * bl;                 // block of <vl>
    const UInt * br;                 // block of <vr>
    UInt         len, lenl, lenr;    // length of the list
    UInt         a, b, nb;

    // get and check the length
    lenl = LEN_GF2VEC(vl);
    lenr = LEN_GF2VEC(vr);
    nb = NUMBER_BLOCKS_GF2VEC(vl);
    a = NUMBER_BLOCKS_GF2VEC(vr);
    if (a < nb) {
        nb = a;
    }

    // check all blocks
    bl = CONST_BLOCKS_GF2VEC(vl);
    br = CONST_BLOCKS_GF2VEC(vr);
    for (i = nb; 1 < i; i--, bl++, br++) {
        // comparison is numeric of the reverted lists
        if (*bl != *br) {
            a = revertbits(*bl, BIPEB);
            b = revertbits(*br, BIPEB);
            if (a < b)
                return -1;
            else
                return 1;
        }
    }


    // The last block remains
    len = lenl;
    if (len > lenr) {
        len = lenr;
    }

    // are both vectors length 0?
    if (len == 0)
        return 0;

    // is there still a full block in common?
    len = len % BIPEB;
    if (len == 0) {
        a = revertbits(*bl, BIPEB);
        b = revertbits(*br, BIPEB);
    }
    else {
        a = revertbits(*bl, len);
        b = revertbits(*br, len);
    }

    if (a < b)
        return -1;
    if (a > b)
        return 1;

    // blocks still the same --left length must be smaller to be true
    if (lenr > lenl)
        return -1;
    if (lenl > lenr)
        return 1;

    return 0;
}


/****************************************************************************
**
*F  FuncEQ_GF2VEC_GF2VEC( <self>, <vl>, <vr> )   test equality of GF2 vectors
*/

static Obj FuncEQ_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr)
{
    // we can do this case MUCH faster if we just want equality
    if (LEN_GF2VEC(vl) != LEN_GF2VEC(vr))
        return False;
    return (Cmp_GF2VEC_GF2VEC(vl, vr) == 0) ? True : False;
}


/****************************************************************************
**
*F  FuncLEN_GF2VEC( <self>, <list> )  . . . . . . . .  length of a GF2 vector
*/

static Obj FuncLEN_GF2VEC(Obj self, Obj list)
{
    return INTOBJ_INT(LEN_GF2VEC(list));
}


/****************************************************************************
**
*F  FuncELM0_GF2VEC( <self>, <list>, <pos> )  . select an elm of a GF2 vector
**
**  'ELM0_GF2VEC'  returns the element at the  position  <pos> of the boolean
**  list <list>, or `Fail' if <list> has no assigned  object at <pos>.  It is
**  the  responsibility of  the caller to   ensure  that <pos> is  a positive
**  integer.
*/

static Obj FuncELM0_GF2VEC(Obj self, Obj list, Obj pos)
{
    UInt p = GetSmallInt(SELF_NAME, pos);
    if (LEN_GF2VEC(list) < p) {
        return Fail;
    }
    else {
        return ELM_GF2VEC(list, p);
    }
}


/****************************************************************************
**
*F  FuncELM_GF2VEC( <self>, <list>, <pos> ) . . select an elm of a GF2 vector
**
**  'ELM_GF2VEC' returns the element at the position <pos>  of the GF2 vector
**  <list>.   An  error  is signalled  if  <pos>  is  not bound.    It is the
**  responsibility of the caller to ensure that <pos> is a positive integer.
*/

static Obj FuncELM_GF2VEC(Obj self, Obj list, Obj pos)
{
    UInt p = GetSmallInt(SELF_NAME, pos);
    if (LEN_GF2VEC(list) < p) {
        ErrorMayQuit("List Element: <list>[%d] must have an assigned value",
                     p, 0);
    }
    else {
        return ELM_GF2VEC(list, p);
    }
}


/****************************************************************************
**
*F  FuncELMS_GF2VEC( <self>, <list>, <poss> ) . . . sublist from a GF2 vector
**
**  'ELMS_GF2VEC' returns a new list containing  the elements at the position
**  given in    the   list  <poss> from  the   vector   <list>.   It  is  the
**  responsibility of the caller to ensure that <poss>  is dense and contains
**  only positive integers.  An error is signalled if an element of <poss> is
**  larger than the length of <list>.
*/

static Obj FuncELMS_GF2VEC(Obj self, Obj list, Obj poss)
{
    Obj elms;       // selected sublist, result
    Int lenList;    // length of <list>
    Int lenPoss;    // length of positions
    Int pos;        // position as integer
    Int inc;        // increment in a range
    Int i;          // loop variable
    Obj apos;

    // get the length of <list>
    lenList = LEN_GF2VEC(list);

    // general code for arbitrary lists, which are ranges
    if (!IS_RANGE(poss)) {

        // get the length of <positions>
        lenPoss = LEN_LIST(poss);

        // make the result vector
        NEW_GF2VEC(elms, TYPE_LIST_GF2VEC, lenPoss);

        // loop over the entries of <positions> and select
        for (i = 1; i <= lenPoss; i++) {

            // get next position

            apos = ELM0_LIST(poss, i);
            if (!apos || !IS_INTOBJ(apos))
                ErrorMayQuit("ELMS_GF2VEC: error at position %d in positions "
                             "list, entry must be bound to a small integer",
                             i, 0);
            pos = INT_INTOBJ(apos);
            if (lenList < pos) {
                ErrorMayQuit("List Elements: <list>[%d] must have a value",
                             pos, 0);
            }

            // assign the element into <elms>
            if (ELM_GF2VEC(list, pos) == GF2One) {
                BLOCK_ELM_GF2VEC(elms, i) |= MASK_POS_GF2VEC(i);
            }
        }
    }

    // special code for ranges
    else {

        // get the length of <positions>, the first elements, and the inc.
        lenPoss = GET_LEN_RANGE(poss);
        pos = GET_LOW_RANGE(poss);
        inc = GET_INC_RANGE(poss);

        // check that no <position> is larger than <lenList>
        if (lenList < pos) {
            ErrorMayQuit("List Elements: <list>[%d] must have a value", pos,
                         0);
        }
        if (lenList < pos + (lenPoss - 1) * inc) {
            ErrorMayQuit("List Elements: <list>[%d] must have a value",
                         pos + (lenPoss - 1) * inc, 0);
        }

        // make the result vector
        NEW_GF2VEC(elms, TYPE_LIST_GF2VEC, lenPoss);

        // increment 1 ranges is a block copy
        if (inc == 1)
            CopySection_GF2Vecs(list, elms, pos, 1, lenPoss);

        // loop over the entries of <positions> and select
        else {
            for (i = 1; i <= lenPoss; i++, pos += inc) {
                if (ELM_GF2VEC(list, pos) == GF2One) {
                    BLOCK_ELM_GF2VEC(elms, i) |= MASK_POS_GF2VEC(i);
                }
            }
        }
    }

    return elms;
}


/****************************************************************************
**
*F  FuncASS_GF2VEC( <self>, <list>, <pos>, <elm> ) set an elm of a GF2 vector
**
**  'ASS_GF2VEC' assigns the element  <elm> at the position  <pos> to the GF2
**  vector <list>.
**
**  It is the responsibility of the caller  to ensure that <pos> is positive,
**  and that <elm> is not 0.
*/


static Obj FuncASS_GF2VEC(Obj self, Obj list, Obj pos, Obj elm)
{
    // check that <list> is mutable
    RequireMutable("List Assignment", list, "list");

    // get the position
    UInt p = GetSmallInt(SELF_NAME, pos);

    // if <elm> is Z(2) or 0*Z(2) and the position is OK, keep rep
    if (p <= LEN_GF2VEC(list) + 1) {
        if (LEN_GF2VEC(list) + 1 == p) {
            if (DoFilter(IsLockedRepresentationVector, list) == True)
                ErrorMayQuit("Assignment forbidden beyond the end of locked "
                             "GF2 vector",
                             0, 0);
            ResizeWordSizedBag(list, SIZE_PLEN_GF2VEC(p));
            SET_LEN_GF2VEC(list, p);
        }
        if (EQ(GF2One, elm)) {
            BLOCK_ELM_GF2VEC(list, p) |= MASK_POS_GF2VEC(p);
        }
        else if (EQ(GF2Zero, elm)) {
            BLOCK_ELM_GF2VEC(list, p) &= ~MASK_POS_GF2VEC(p);
        }
        else if (IS_FFE(elm) && CHAR_FF(FLD_FFE(elm)) == 2 &&
                 DEGR_FF(FLD_FFE(elm)) <= 8) {
            RewriteGF2Vec(list, SIZE_FF(FLD_FFE(elm)));
            ASS_VEC8BIT(list, pos, elm);
        }
        else {
            PlainGF2Vec(list);
            ASS_LIST(list, p, elm);
        }
    }
    else {
        PlainGF2Vec(list);
        ASS_LIST(list, p, elm);
    }
    return 0;
}

/****************************************************************************
**
*F  FuncPLAIN_GF2MAT( <self>, <list> ) . . .  convert back into ordinary list
*/

static Obj FuncPLAIN_GF2MAT(Obj self, Obj list)
{
    PlainGF2Mat(list);
    return 0;
}


/****************************************************************************
**
*F  FuncASS_GF2MAT( <self>, <list>, <pos>, <elm> ) set an elm of a GF2 matrix
**
**  'ASS_GF2MAT' assigns the element  <elm> at the position  <pos> to the GF2
**  matrix <list>.
**
**  It is the responsibility of the caller  to ensure that <pos> is positive,
**  and that <elm> is not 0.
*/

static Obj FuncASS_GF2MAT(Obj self, Obj list, Obj pos, Obj elm)
{
    // check that <list> is mutable
    RequireMutable("List Assignment", list, "list");

    // get the position
    UInt p = GetSmallInt(SELF_NAME, pos);

    // if <elm> is a GF2 vector and the length is OK, keep the rep
    if (!IS_GF2VEC_REP(elm)) {
        PlainGF2Mat(list);
        ASS_LIST(list, p, elm);
    }
    else if (p == 1 && 1 >= LEN_GF2MAT(list)) {
        ResizeBag(list, SIZE_PLEN_GF2MAT(p));
        SetTypeDatObj(elm, IS_MUTABLE_OBJ(elm) ? TYPE_LIST_GF2VEC_LOCKED
                                               : TYPE_LIST_GF2VEC_IMM_LOCKED);
        SET_ELM_GF2MAT(list, p, elm);
        CHANGED_BAG(list);
    }
    else if (p > LEN_GF2MAT(list) + 1) {
        PlainGF2Mat(list);
        ASS_LIST(list, p, elm);
    }
    else if (LEN_GF2VEC(elm) == LEN_GF2VEC(ELM_GF2MAT(list, 1))) {
        if (LEN_GF2MAT(list) + 1 == p) {
            ResizeBag(list, SIZE_PLEN_GF2MAT(p));
            SET_LEN_GF2MAT(list, p);
        }
        SetTypeDatObj(elm, IS_MUTABLE_OBJ(elm) ? TYPE_LIST_GF2VEC_LOCKED
                                               : TYPE_LIST_GF2VEC_IMM_LOCKED);
        SET_ELM_GF2MAT(list, p, elm);
        CHANGED_BAG(list);
    }
    else {
        PlainGF2Mat(list);
        ASS_LIST(list, p, elm);
    }
    return 0;
}


/****************************************************************************
**
*F  FuncELM_GF2MAT( <self>, <mat>, <row> ) . . . select a row of a GF2 matrix
**
*/

static Obj FuncELM_GF2MAT(Obj self, Obj mat, Obj row)
{
    UInt r = GetSmallInt(SELF_NAME, row);
    if (LEN_GF2MAT(mat) < r) {
        ErrorMayQuit("row index %d exceeds %d, the number of rows", r,
                     LEN_GF2MAT(mat));
    }
    return ELM_GF2MAT(mat, r);
}


/****************************************************************************
**
*F  FuncSWAP_ROWS_GF2MAT( <self>, <mat>, <r1>, <r2> )
**
*/

static Obj FuncSWAP_ROWS_GF2MAT(Obj self, Obj mat, Obj row1, Obj row2)
{
    RequireMutable(SELF_NAME, mat, "mat");

    UInt r1 = GetSmallInt(SELF_NAME, row1);
    UInt r2 = GetSmallInt(SELF_NAME, row2);
    UInt m = LEN_GF2MAT(mat);
    if (m < r1) {
        ErrorMayQuit("row index %d exceeds %d, the number of rows", r1, m);
    }
    if (m < r2) {
        ErrorMayQuit("row index %d exceeds %d, the number of rows", r2, m);
    }

    Obj a = ELM_GF2MAT(mat, r1);
    Obj b = ELM_GF2MAT(mat, r2);

    SET_ELM_GF2MAT(mat, r1, b);
    SET_ELM_GF2MAT(mat, r2, a);

    return 0;
}


/****************************************************************************
**
*F  FuncSWAP_COLS_GF2MAT( <self>, <mat>, <c1>, <c2> )
**
*/

static Obj FuncSWAP_COLS_GF2MAT(Obj self, Obj mat, Obj col1, Obj col2)
{
    UInt c1 = GetSmallInt(SELF_NAME, col1);
    UInt c2 = GetSmallInt(SELF_NAME, col2);
    UInt m = LEN_GF2MAT(mat);
    if (m == 0)
        return 0;

    UInt n = LEN_GF2VEC(ELM_GF2MAT(mat, 1));
    if (n < c1) {
        ErrorMayQuit("column index %d exceeds %d, the number of columns", c1, n);
    }
    if (n < c2) {
        ErrorMayQuit("column index %d exceeds %d, the number of columns", c2, n);
    }

    for (UInt i = 1; i <= m; ++i) {
        Obj vec = ELM_GF2MAT(mat, i);
        if (!IS_MUTABLE_OBJ(vec)) {
            ErrorMayQuit("row %d is immutable", i, 0);
        }
        if (LEN_GF2VEC(vec) != n) {
            ErrorMayQuit("row length mismatch, %d versus %d", n, LEN_GF2VEC(vec));
        }

        Obj a = ELM_GF2VEC(vec, c1);
        Obj b = ELM_GF2VEC(vec, c2);
        if (a != b) {
            // one entry is 1, the other is 0; so to switch them,
            // we can simply flip each individually
            BLOCK_ELM_GF2VEC(vec, c1) ^= MASK_POS_GF2VEC(c1);
            BLOCK_ELM_GF2VEC(vec, c2) ^= MASK_POS_GF2VEC(c2);
        }
    }

    return 0;
}


/****************************************************************************
**
*F  FuncUNB_GF2VEC( <self>, <list>, <pos> ) . unbind position of a GF2 vector
**
**  'UNB_GF2VEC' unbind  the element at  the position  <pos> in  a GF2 vector
**  <list>.
**
**  It is the responsibility of the caller  to ensure that <pos> is positive.
*/

static Obj FuncUNB_GF2VEC(Obj self, Obj list, Obj pos)
{
    // check that <list> is mutable
    RequireMutable("List Unbind", list, "vector");

    if (DoFilter(IsLockedRepresentationVector, list) == True) {
        ErrorMayQuit("Unbind forbidden on locked GF2 vector", 0, 0);
    }

    // get the position
    UInt p = GetSmallInt(SELF_NAME, pos);

    // if we unbind the last position keep the representation
    if (LEN_GF2VEC(list) < p) {
        ;
    }
    else if (LEN_GF2VEC(list) == p) {
        ResizeWordSizedBag(list, SIZE_PLEN_GF2VEC(p - 1));
        SET_LEN_GF2VEC(list, p - 1);
    }
    else {
        PlainGF2Vec(list);
        UNB_LIST(list, p);
    }
    return 0;
}


/****************************************************************************
**
*F  FuncUNB_GF2MAT( <self>, <list>, <pos> ) . unbind position of a GF2 matrix
**
**  'UNB_GF2VEC' unbind  the element at  the position  <pos> in  a GF2 matrix
**  <list>.
**
**  It is the responsibility of the caller  to ensure that <pos> is positive.
*/

static Obj FuncUNB_GF2MAT(Obj self, Obj list, Obj pos)
{
    // check that <list> is mutable
    RequireMutable("List Unbind", list, "matrix");

    // get the position
    UInt p = GetSmallInt(SELF_NAME, pos);

    // if we unbind the last position keep the representation
    if (p > 1 && LEN_GF2MAT(list) < p) {
        ;
    }
    else if (LEN_GF2MAT(list) == p) {
        ResizeBag(list, SIZE_PLEN_GF2MAT(p - 1));
        SET_LEN_GF2MAT(list, p - 1);
    }
    else {
        PlainGF2Mat(list);
        UNB_LIST(list, p);
    }
    return 0;
}


/****************************************************************************
**
*F * * * * * * * * * * * * arithmetic operations  * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*F  FuncZERO_GF2VEC( <self>, <mat> )  . . . . . . . . . . . . zero GF2 vector
**
**  return the zero vector over GF2 of the same length as <mat>.
*/

static Obj FuncZERO_GF2VEC(Obj self, Obj mat)
{
    Obj  zero;
    UInt len;

    // create a new GF2 vector
    len = LEN_GF2VEC(mat);
    NEW_GF2VEC(zero, TYPE_LIST_GF2VEC, len);
    return zero;
}

/****************************************************************************
**
*F  FuncZERO_GF2VEC_2( <self>, <len>) . . . . . . . . . zero GF2 vector
**
**  return the zero vector over GF2 of length <len>
*/

static Obj FuncZERO_GF2VEC_2(Obj self, Obj len)
{
    Obj zero;
    RequireNonnegativeSmallInt(SELF_NAME, len);
    NEW_GF2VEC(zero, TYPE_LIST_GF2VEC, INT_INTOBJ(len));
    return zero;
}


/****************************************************************************
**
*F  FuncINV_GF2MAT_MUTABLE( <self>, <mat> ) . .. . . . .  inverse GF2 matrix
**
** This might now be redundant, a library method using
**  INVERSE_PLIST_GF2VECS_DESTRUCTIVE
** might do just as good a job
*/

static Obj FuncINV_GF2MAT_MUTABLE(Obj self, Obj mat)
{
    UInt len;

    len = LEN_GF2MAT(mat);
    if (len != 0) {
        if (len != LEN_GF2VEC(ELM_GF2MAT(mat, 1))) {
            ErrorMayQuit("<matrix> must be square", 0, 0);
        }
    }
    return InverseGF2Mat(mat, 2);
}

/****************************************************************************
**
*F  FuncINV_GF2MAT_SAME_MUTABILITY( <self>, <mat> ) . ...  inverse GF2 matrix
**
** This might now be redundant, a library method using
**  INVERSE_PLIST_GF2VECS_DESTRUCTIVE
** might do just as good a job
*/

static Obj FuncINV_GF2MAT_SAME_MUTABILITY(Obj self, Obj mat)
{
    UInt len;

    len = LEN_GF2MAT(mat);
    if (len != 0) {
        if (len != LEN_GF2VEC(ELM_GF2MAT(mat, 1))) {
            ErrorMayQuit("<matrix> must be square", 0, 0);
        }
    }
    return InverseGF2Mat(mat, 1);
}

/****************************************************************************
**
*F  FuncINV_GF2MAT_IMMUTABLE( <self>, <mat> ) . .. . . .  inverse GF2 matrix
**
** This might now be redundant, a library method using
**  INVERSE_PLIST_GF2VECS_DESTRUCTIVE
** might do just as good a job
*/

static Obj FuncINV_GF2MAT_IMMUTABLE(Obj self, Obj mat)
{
    UInt len;

    len = LEN_GF2MAT(mat);
    if (len != 0) {
        if (len != LEN_GF2VEC(ELM_GF2MAT(mat, 1))) {
            ErrorMayQuit("<matrix> must be square", 0, 0);
        }
    }
    return InverseGF2Mat(mat, 0);
}


/****************************************************************************
**
*F  FuncINV_PLIST_GF2VECS_DESTRUCTIVE( <self>, <list> )
**
**  invert possible GF2 matrix
*/

static Obj FuncINV_PLIST_GF2VECS_DESTRUCTIVE(Obj self, Obj list)
{
    UInt len, i;
    Obj  row;
    len = LEN_PLIST(list);
    for (i = 1; i <= len; i++) {
        row = ELM_PLIST(list, i);
        if (!IS_GF2VEC_REP(row) || LEN_GF2VEC(row) != len)
            return TRY_NEXT_METHOD;
    }
    if (len == 0) {
        return CopyObj(list, 1);
    }
    if (len == 1) {
        row = ELM_PLIST(list, 1);
        if (CONST_BLOCKS_GF2VEC(row)[0] & 1) {
            return CopyObj(list, 1);
        }
        else
            return Fail;
    }
    return InversePlistGF2VecsDesstructive(list);
}


/****************************************************************************
**
*F  FuncSUM_GF2VEC_GF2VEC( <self>, <vl>, <vr> ) . . . . .  sum of GF2 vectors
**
**  'FuncSUM_GF2VEC_GF2VEC' returns the sum  of the two gf2-vectors <vl>  and
**  <vr>.  The sum is a new gf2-vector, where each element is  the sum of the
**  corresponding entries of <vl>  and <vr>.  The  major work is done  in the
**  routine   'AddPartialGF2VecGF2Vec'     which     is         called   from
**  'FuncSUM_GF2VEC_GF2VEC'.
**
**  'FuncSUM_GF2VEC_GF2VEC'  is  an improved  version of 'SumListList', which
**  does not call 'SUM' but uses bit operations instead.
*/

static Obj FuncSUM_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr)
{
    Obj  sum;    // sum, result
    UInt ll, lr;

    ll = LEN_GF2VEC(vl);
    lr = LEN_GF2VEC(vr);


    if (ll < lr) {
        sum = ShallowCopyVecGF2(vr);
        AddGF2VecToGF2Vec(BLOCKS_GF2VEC(sum), CONST_BLOCKS_GF2VEC(vl), ll);
    }
    else {
        sum = ShallowCopyVecGF2(vl);
        AddGF2VecToGF2Vec(BLOCKS_GF2VEC(sum), CONST_BLOCKS_GF2VEC(vr), lr);
    }

    if (!IS_MUTABLE_OBJ(vl) && !IS_MUTABLE_OBJ(vr))
        SET_TYPE_POSOBJ(sum, TYPE_LIST_GF2VEC_IMM);

    return sum;
}

/****************************************************************************
**
*F  FuncMULT_VECTOR_GF2VECS_2( <self>, <vl>, <mul> )
**                                      . . . . .  sum of GF2 vectors
**
*/

static Obj FuncMULT_VECTOR_GF2VECS_2(Obj self, Obj vl, Obj mul)
{
    if (EQ(mul, GF2One))
        return (Obj)0;
    else if (EQ(mul, GF2Zero)) {
        AddCoeffsGF2VecGF2Vec(vl, vl);
        return (Obj)0;
    }
    else
        return TRY_NEXT_METHOD;
}


/****************************************************************************
**
*F  FuncPROD_GF2VEC_GF2VEC( <self>, <vl>, <vr> )  . .  product of GF2 vectors
**
**  'FuncPROD_GF2VEC_GF2VEC' returns the product of  the two GF2 vectors <vl>
**  and <vr>.  The product is either `GF2One' or `GF2Zero'.
*/

static Obj FuncPROD_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr)
{
    return ProdGF2VecGF2Vec(vl, vr);
}


/****************************************************************************
**
*F  FuncPROD_GF2VEC_GF2MAT( <self>, <vl>, <vr> ) product of GF2 vector/matrix
**
**  'FuncPROD_GF2VEC_GF2MAT' returns  the product of the GF2 vectors <vl> and
**  the GF2 matrix <vr>.
**
**  The  product is  again a  GF2 vector.  It  is  the  responsibility of the
**  caller to ensure that <vl> is a  GF2 vector, <vr>  a GF2 matrix.
*/

static Obj FuncPROD_GF2VEC_GF2MAT(Obj self, Obj vl, Obj vr)
{
    return ProdGF2VecGF2Mat(vl, vr);
}

/****************************************************************************
**
*F  FuncPROD_GF2MAT_GF2MAT( <self>, <ml>, <mr> ) product of GF2 vector/matrix
**
**  'FuncPROD_GF2MAT_GF2MAT' returns the product of the GF2 matricess <ml>
**  and <mr>.
**
**  The  product is  again a  GF2 matrix.  It  is  the  responsibility of the
**  caller to ensure that <ml> and <mr> are  GF2 matrices
*/

static Obj FuncPROD_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr)
{
    UInt lenl = LEN_GF2MAT(ml);
    UInt lenm;
    if (lenl >= 128) {
        lenm = LEN_GF2VEC(ELM_GF2MAT(ml, 1));
        if (lenm >= 128 && lenm == LEN_GF2MAT(mr) &&
            LEN_GF2VEC(ELM_GF2MAT(mr, 1)) >= 128) {
            return ProdGF2MatGF2MatAdvanced(ml, mr, 8, (lenm + 255) / 256);
        }
    }
    return ProdGF2MatGF2MatSimple(ml, mr);
}

/****************************************************************************
**
*F  FuncPROD_GF2MAT_GF2MAT_SIMPLE( <self>, <ml>, <mr> )
**
**  'FuncPROD_GF2MAT_GF2MAT' returns  the product of the GF2 matricess <ml>
**  and <mr>. It never uses grease or blocking.
**
**  The  product is  again a  GF2 matrix.  It  is  the  responsibility of the
**  caller to ensure that <ml> and <mr> are  GF2 matrices
*/

static Obj FuncPROD_GF2MAT_GF2MAT_SIMPLE(Obj self, Obj ml, Obj mr)
{
    return ProdGF2MatGF2MatSimple(ml, mr);
}


/****************************************************************************
**
*F  FuncPROD_GF2MAT_GF2MAT_ADVANCED( <self>, <ml>, <mr>, <greaselevel>,
**                                                              <blocksize> )
**
**  'FuncPROD_GF2MAT_GF2MAT_ADVANCED' returns the product of the GF2 matrices
**  <ml> and <mr> using grease level <greaselevel> and block size <blocksize>
**
**  The  product is  again a  GF2 matrix.  It  is  the  responsibility of the
**  caller to ensure that <ml> and <mr> are  GF2 matrices
*/

static Obj FuncPROD_GF2MAT_GF2MAT_ADVANCED(
    Obj self, Obj ml, Obj mr, Obj greaselevel, Obj blocksize)
{
    return ProdGF2MatGF2MatAdvanced(ml, mr, INT_INTOBJ(greaselevel),
                                    INT_INTOBJ(blocksize));
}


/****************************************************************************
**
*F  FuncPROD_GF2MAT_GF2VEC( <self>, <vl>, <vr> ) product of GF2 matrix/vector
**
**  'FuncPROD_GF2VEC_GF2MAT' returns  the product of the GF2 matrix  <vl> and
**  the GF2 vector <vr>.
**
**  The  product is  again a  GF2 vector.  It  is  the  responsibility of the
**  caller to ensure that <vr> is a  GF2 vector, <vl>  a GF2 matrix.
*/

static Obj FuncPROD_GF2MAT_GF2VEC(Obj self, Obj vl, Obj vr)
{
    return ProdGF2MatGF2Vec(vl, vr);
}


/****************************************************************************
**
*F  FuncADDCOEFFS_GF2VEC_GF2VEC_MULT( <self>, <vl>, <vr>, <mul> ) GF2 vectors
*/

static Obj FuncADDCOEFFS_GF2VEC_GF2VEC_MULT(Obj self, Obj vl, Obj vr, Obj mul)
{
    // do nothing if <mul> is zero
    if (EQ(mul, GF2Zero)) {
        return INTOBJ_INT(RightMostOneGF2Vec(vl));
    }

    // add if <mul> is one
    if (EQ(mul, GF2One)) {
        return AddCoeffsGF2VecGF2Vec(vl, vr);
    }

    // try next method
    return TRY_NEXT_METHOD;
}

/****************************************************************************
**
*F  FuncADDCOEFFS_GF2VEC_GF2VEC( <self>, <vl>, <vr> ) . . . . . . GF2 vectors
*/

static Obj FuncADDCOEFFS_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr)
{
    return AddCoeffsGF2VecGF2Vec(vl, vr);
}


/****************************************************************************
**
*F  FuncSHRINKCOEFFS_GF2VEC( <self>, <vec> )  . . . . . remove trailing zeros
*/

static Obj FuncSHRINKCOEFFS_GF2VEC(Obj self, Obj vec)
{
    UInt   len;
    UInt   nbb;
    UInt   onbb;
    UInt * ptr;
    UInt   off;

    // get length and number of blocks
    len = LEN_GF2VEC(vec);
    if (len == 0) {
        return INTOBJ_INT(0);
    }

    nbb = (len + BIPEB - 1) / BIPEB;
    onbb = nbb;
    ptr = BLOCKS_GF2VEC(vec) + (nbb - 1);

    // number of insignificant bit positions in last word
    off = BIPEB - ((len - 1) % BIPEB + 1);

    // mask out the last bits
    *ptr &= ALL_BITS_UINT >> off;

    // find last non-trivial block
    while (0 < nbb && !*ptr) {
        nbb--;
        ptr--;
    }
    // did the block number change?
    if (nbb < onbb) {
        len = nbb * BIPEB;
    }

    // find position inside this block
    // we are guaranteed not to cross a block boundary !
    while (0 < len && !(*ptr & MASK_POS_GF2VEC(len))) {
        len--;
    }
    ResizeWordSizedBag(vec, SIZE_PLEN_GF2VEC(len));
    SET_LEN_GF2VEC(vec, len);
    return INTOBJ_INT(len);
}

/****************************************************************************
**
*F  FuncPOSITION_NONZERO_GF2VEC( <self>, <vec>, <zero>) ..find first non-zero
**
**  The pointless zero argument is because this is a method for PositionNot
**  It is *not* used in the code and can be replaced by a dummy argument.
*/


static UInt PositionNonZeroGF2Vec(Obj vec, UInt from)
{
    UInt         len;
    UInt         nbb;
    UInt         nb;
    const UInt * ptr;
    UInt         pos;

    // get length and number of blocks
    len = LEN_GF2VEC(vec);
    if (len == 0) {
        return 1;
    }


    nbb = from / BIPEB;
    pos = from % BIPEB;
    ptr = CONST_BLOCKS_GF2VEC(vec) + nbb;
    if (pos)    // partial block to check
    {
        pos = from + 1;
        while ((pos - 1) % BIPEB && pos <= len) {
            if ((*ptr) & MASK_POS_GF2VEC(pos))
                return (pos);
            pos++;
        }
        if (pos > len)
            return len + 1;
        nbb++;
        ptr++;
    }
    // find first non-trivial block
    nb = NUMBER_BLOCKS_GF2VEC(vec);
    while (nbb < nb && !*ptr) {
        nbb++;
        ptr++;
    }

    // find position inside this block
    pos = nbb * BIPEB + 1;
    while (pos <= len && !(*ptr & MASK_POS_GF2VEC(pos))) {
        pos++;
    }
    // as the code is intended to run over, trailing 1's are innocent
    if (pos <= len)
        return pos;
    else
        return len + 1;
}


static Obj FuncPOSITION_NONZERO_GF2VEC(Obj self, Obj vec, Obj zero)
{
    return INTOBJ_INT(PositionNonZeroGF2Vec(vec, 0));
}

static Obj FuncPOSITION_NONZERO_GF2VEC3(Obj self, Obj vec, Obj zero, Obj from)
{
    return INTOBJ_INT(PositionNonZeroGF2Vec(vec, INT_INTOBJ(from)));
}


static Obj FuncCOPY_SECTION_GF2VECS(
    Obj self, Obj src, Obj dest, Obj from, Obj to, Obj howmany)
{
    Int ifrom = GetPositiveSmallInt(SELF_NAME, from);
    Int ito = GetPositiveSmallInt(SELF_NAME, to);
    Int ihowmany = GetSmallInt(SELF_NAME, howmany);

    if (!IS_GF2VEC_REP(src)) {
        RequireArgument(SELF_NAME, src, "must be a GF2 vector");
    }
    if (!IS_GF2VEC_REP(dest)) {
        RequireArgument(SELF_NAME, dest, "must be a GF2 vector");
    }

    UInt lens = LEN_GF2VEC(src);
    UInt lend = LEN_GF2VEC(dest);
    if (ihowmany < 0 ||
        ifrom + ihowmany - 1 > lens || ito + ihowmany - 1 > lend)
        ErrorMayQuit("Bad argument values", 0, 0);
    RequireMutable(SELF_NAME, dest, "vector");

    CopySection_GF2Vecs(src, dest, (UInt)ifrom, (UInt)ito, (UInt)ihowmany);
    return (Obj)0;
}


/****************************************************************************
**
*F  FuncAPPEND_GF2VEC( <self>, <vecl>, <vecr> )
**
*/


static Obj FuncAPPEND_GF2VEC(Obj self, Obj vecl, Obj vecr)
{
    UInt lenl, lenr;
    lenl = LEN_GF2VEC(vecl);
    lenr = LEN_GF2VEC(vecr);
    if (True == DoFilter(IsLockedRepresentationVector, vecl) && lenr > 0) {
        ErrorMayQuit("Append to locked compressed vector is forbidden", 0, 0);
    }
    ResizeWordSizedBag(vecl, SIZE_PLEN_GF2VEC(lenl + lenr));
    CopySection_GF2Vecs(vecr, vecl, 1, lenl + 1, lenr);
    SET_LEN_GF2VEC(vecl, lenl + lenr);
    return (Obj)0;
}


/****************************************************************************
**
*F  FuncSHALLOWCOPY_GF2VEC( <self>, <vec> )
**
*/


static Obj FuncSHALLOWCOPY_GF2VEC(Obj self, Obj vec)
{
    return ShallowCopyVecGF2(vec);
}

/****************************************************************************
**
*F  FuncSUM_GF2MAT_GF2MAT( <self>, <matl>, <matr> )
**
*/



static Obj FuncSUM_GF2MAT_GF2MAT(Obj self, Obj matl, Obj matr)
{
    UInt ll, lr, ls, lm, wl, wr, ws, wm;
    Obj  sum;
    Obj  vl, vr, sv;
    UInt i;
    Obj  rtype;
    ll = LEN_GF2MAT(matl);
    lr = LEN_GF2MAT(matr);
    if (ll > lr) {
        ls = ll;
        lm = lr;
    }
    else {
        ls = lr;
        lm = ll;
    }
    wl = LEN_GF2VEC(ELM_GF2MAT(matl, 1));
    wr = LEN_GF2VEC(ELM_GF2MAT(matr, 1));
    if (wl > wr) {
        ws = wl;
        wm = wr;
    }
    else {
        ws = wr;
        wm = wl;
    }

    // In this case, the result is not rectangular

    if ((ll > lr && wr > wl) || (ll < lr && wr < wl))
        return TRY_NEXT_METHOD;


    sum = NewBag(T_POSOBJ, SIZE_PLEN_GF2MAT(ls));
    if (IS_MUTABLE_OBJ(matl) || IS_MUTABLE_OBJ(matr)) {
        SET_TYPE_POSOBJ(sum, TYPE_LIST_GF2MAT);
        if (IS_MUTABLE_OBJ(ELM_GF2MAT(matl, 1)) ||
            IS_MUTABLE_OBJ(ELM_GF2MAT(matr, 1)))
            rtype = TYPE_LIST_GF2VEC_LOCKED;
        else
            rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }
    else {
        SET_TYPE_POSOBJ(sum, TYPE_LIST_GF2MAT_IMM);
        rtype = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }

    SET_LEN_GF2MAT(sum, ls);
    for (i = 1; i <= lm; i++) {

        // copy the longer vector and add the shorter
        if (wl == ws) {
            sv = ShallowCopyVecGF2(ELM_GF2MAT(matl, i));
            vr = ELM_GF2MAT(matr, i);
            AddGF2VecToGF2Vec(BLOCKS_GF2VEC(sv), CONST_BLOCKS_GF2VEC(vr), wm);
        }
        else {
            sv = ShallowCopyVecGF2(ELM_GF2MAT(matr, i));
            vl = ELM_GF2MAT(matl, i);
            AddGF2VecToGF2Vec(BLOCKS_GF2VEC(sv), CONST_BLOCKS_GF2VEC(vl), wm);
        }

        SetTypeDatObj(sv, rtype);
        SET_ELM_GF2MAT(sum, i, sv);
        CHANGED_BAG(sum);
    }
    for (; i <= ls; i++) {
        if (ll > lr)
            sv = ELM_GF2MAT(matl, i);
        else
            sv = ELM_GF2MAT(matr, i);

        if (rtype == TYPE_LIST_GF2VEC_LOCKED)
            sv = ShallowCopyVecGF2(sv);

        SetTypeDatObj(sv, rtype);
        SET_ELM_GF2MAT(sum, i, sv);
        CHANGED_BAG(sum);
    }
    return sum;
}


/****************************************************************************
**
*F  FuncTRANSPOSED_GF2MAT( <self>, <mat>)
**
*/

static Obj FuncTRANSPOSED_GF2MAT(Obj self, Obj mat)
{
    UInt l, w;
    Obj  tra, row;
    Obj  typ, r1;
    UInt vals[BIPEB];
    UInt mask, val, bit;
    UInt imod, nrb, nstart;
    UInt i, j, k, n;

    if (TNUM_OBJ(mat) != T_POSOBJ) {
        ErrorMayQuit("TRANSPOSED_GF2MAT: Need compressed matrix over GF(2)",
                     0, 0);
    }
    // type for mat
    typ = TYPE_LIST_GF2MAT;


    // we assume here that there is a first row
    r1 = ELM_GF2MAT(mat, 1);

    l = LEN_GF2MAT(mat);
    w = LEN_GF2VEC(r1);
    nrb = NUMBER_BLOCKS_GF2VEC(r1);

    tra = NewBag(T_POSOBJ, SIZE_PLEN_GF2MAT(w));
    SET_TYPE_POSOBJ(tra, typ);

    // type for rows
    typ = TYPE_LIST_GF2VEC_LOCKED;

    SET_LEN_GF2MAT(tra, w);
    // create new matrix
    for (i = 1; i <= w; i++) {
        NEW_GF2VEC(row, typ, l);
        SET_ELM_GF2MAT(tra, i, row);
        CHANGED_BAG(tra);
    }
    // set entries
    // run over BIPEB row chunks of the original matrix
    for (i = 1; i <= l; i = i + BIPEB) {
        imod = (i - 1) / BIPEB;
        // run through these rows in block chunks
        for (n = 0; n < nrb; n++) {
            for (j = 0; j < BIPEB; j++) {
                if ((i + j) > l) {
                    vals[j] = 0;    // outside matrix
                }
                else {
                    const UInt * ptr =
                        CONST_BLOCKS_GF2VEC(ELM_GF2MAT(mat, i + j)) + n;
                    vals[j] = *ptr;
                }
            }
            // write transposed values in new matrix
            mask = 1;
            nstart = n * BIPEB + 1;
            for (j = 0; j < BIPEB; j++) {    // bit number = Row in transpose
                if ((nstart + j) <= w) {
                    // still within matrix
                    val = 0;
                    bit = 1;
                    for (k = 0; k < BIPEB; k++) {
                        if (mask == (vals[k] & mask)) {
                            val |= bit;    // set bit
                        }
                        bit = bit << 1;
                    }
                    // set entry
                    UInt * ptr =
                        BLOCKS_GF2VEC(ELM_GF2MAT(tra, nstart + j)) + imod;
                    *ptr = val;
                    // next bit
                    mask = mask << 1;
                }
            }
        }
    }
    return tra;
}


/****************************************************************************
**
*F  FuncNUMBER_GF2VEC( <self>, <vect> )
**
*/

static Obj FuncNUMBER_GF2VEC(Obj self, Obj vec)
{
    UInt        len, nd, i;
    UInt        head, a;
    UInt        off, off2;    // 0 based
    Obj         zahl;         // the long number
    UInt *      num2;
    mp_limb_t * vp;
    len = LEN_GF2VEC(vec);
    if (len == 0)
        return INTOBJ_INT(1);
    num2 = BLOCKS_GF2VEC(vec) + (len - 1) / BIPEB;
    off = (len - 1) % BIPEB + 1;    // number of significant bits in last word
    off2 = BIPEB - off;    // number of insignificant bits in last word

    // mask out the last bits
    *num2 &= ALL_BITS_UINT >> off2;

    if (len <= NR_SMALL_INT_BITS)
        // it still fits into a small integer
        return INTOBJ_INT(revertbits(*num2, len));
    else {
        // we might have to build a long integer

        // the number of words (limbs) we need.
        nd = ((len - 1) / GMP_LIMB_BITS) + 1;

        zahl = NewBag(T_INTPOS, nd * sizeof(UInt));

        // garbage collection might lose pointer
        const UInt * num = CONST_BLOCKS_GF2VEC(vec) + (len - 1) / BIPEB;

        vp = (mp_limb_t *)ADDR_OBJ(zahl);    // the place we write to
        i = 1;

        if (off != BIPEB) {
            head = revertbits(*num, off);    // the last 'off' bits, reverted
            while (i < nd) {
                // next word
                num--;
                *vp = head;    // the bits left from last word
                a = revertbits(*num, BIPEB);    // the full word reverted
                head = a >> off2;    // next head: trailing `off' bits
                a = a << off;        // the rest of the word
                *vp |= a;
                vp++;
                i++;
            }
            *vp = head;    // last head bits
            vp++;
        }
        else {
            while (i <= nd) {
                *vp = revertbits(*num--, BIPEB);
                vp++;
                i++;
            }
        }

        zahl = GMP_NORMALIZE(zahl);
        return zahl;
    }
}

/****************************************************************************
**
*F  FuncLT_GF2VEC_GF2VEC( <self>, <vl>, <vr> )   compare GF2 vectors
*/

static Obj FuncLT_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr)
{
    return (Cmp_GF2VEC_GF2VEC(vl, vr) < 0) ? True : False;
}

/****************************************************************************
**
*F  Cmp_GF2MAT_GF2MAT( <ml>, <mr> )   compare GF2 matrices
*/


static Int Cmp_GF2MAT_GF2MAT(Obj ml, Obj mr)
{
    UInt l1, l2, l, i;
    Int  c;
    l1 = INT_INTOBJ(ELM_PLIST(ml, 1));
    l2 = INT_INTOBJ(ELM_PLIST(mr, 1));
    l = (l1 < l2) ? l1 : l2;
    for (i = 2; i <= l + 1; i++) {
        c = Cmp_GF2VEC_GF2VEC(ELM_PLIST(ml, i), ELM_PLIST(mr, i));
        if (c != 0)
            return c;
    }
    if (l1 < l2)
        return -1;
    if (l1 > l2)
        return 1;
    return 0;
}

/****************************************************************************
**
*F  FuncEQ_GF2MAT_GF2MAT( <ml>, <mr> )   compare GF2 matrices
*/


static Obj FuncEQ_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr)
{
    if (ELM_PLIST(ml, 1) != ELM_PLIST(mr, 1))
        return False;
    return (0 == Cmp_GF2MAT_GF2MAT(ml, mr)) ? True : False;
}

/****************************************************************************
**
*F  FuncLT_GF2MAT_GF2MAT( <ml>, <mr> )   compare GF2 matrices
*/


static Obj FuncLT_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr)
{
    return (Cmp_GF2MAT_GF2MAT(ml, mr) < 0) ? True : False;
}

/****************************************************************************
**
*F  DistGF2Vecs( <ptL>, <ptR>, <len> )
**
**  computes the GF2-vector distance of two blocks in memory, pointed to by
**  ptL and ptR for a GF(2) vector of <len> entries.
**
*/

static UInt DistGF2Vecs(const UInt * ptL, const UInt * ptR, UInt len)
{
    UInt         sum, m;
    const UInt * end;    // end marker

    // TODO: this function will not work if the vectors have more than 2^28
    // entries

    end = ptL + ((len + BIPEB - 1) / BIPEB);
    sum = 0;
    // loop over the entries
    while (ptL < end) {
        m = *ptL++ ^ *ptR++;    // xor of bits, nr bits therein is difference
        sum += COUNT_TRUES_BLOCK(m);
    }
    return sum;
}

/****************************************************************************
**
*F  FuncDIST_GF2VEC_GF2VEC( <self>, <vl>, <vr> )
**
**  'FuncDIST_GF2VEC_GF2VEC' returns the number of position in which two
**  gf2-vectors <vl>  and  <vr> differ.
*/

static Obj FuncDIST_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr)
{
    UInt   len;    // length of the list
    UInt   off;    // bit offset at the end to clean out
    UInt * ptL;    // bit field of <vl>
    UInt * ptR;    // bit field of <vr>
    UInt * end;    // pointer used to zero out end bit
    // get and check the length
    len = LEN_GF2VEC(vl);

    if (len != LEN_GF2VEC(vr)) {
        ErrorMayQuit("DIST_GF2VEC_GF2VEC: vectors must have the same length",
                     0, 0);
    }

    // calculate the offsets
    ptL = BLOCKS_GF2VEC(vl);
    ptR = BLOCKS_GF2VEC(vr);

    // mask out the last bits
    off = (len - 1) % BIPEB + 1;    // number of significant bits in last word
    off = BIPEB - off;    // number of insignificant bits in last word
    end = ptL + ((len - 1) / BIPEB);
    *end &= ALL_BITS_UINT >> off;
    end = ptR + ((len - 1) / BIPEB);
    *end &= ALL_BITS_UINT >> off;

    return INTOBJ_INT(DistGF2Vecs(ptL, ptR, len));
}


static void DistVecClosVec(
    Obj  veclis,    // pointers to matrix vectors and their multiples
    Obj  ovec,      // vector we compute distance to
    Obj  d,         // distances list
    Obj  osum,      // position of the sum vector
    UInt pos,       // recursion depth
    UInt l,         // length of basis
    UInt len)       // length of the involved vectors
{
    UInt         i;
    UInt         di;
    Obj          cnt;
    Obj          vp;
    const UInt * vec;
    Obj          one;
    Obj          tmp;

    vec = CONST_BLOCKS_GF2VEC(ovec);
    vp = ELM_PLIST(veclis, pos);
    one = INTOBJ_INT(1);

    for (i = 0; i <= 1; i++) {
        if (pos < l) {
            DistVecClosVec(veclis, ovec, d, osum, pos + 1, l, len);
        }
        else {
            di = DistGF2Vecs(CONST_BLOCKS_GF2VEC(osum), vec, len);

            cnt = ELM_PLIST(d, di + 1);
            if (IS_INTOBJ(cnt) && SUM_INTOBJS(tmp, cnt, one)) {
                cnt = tmp;
                SET_ELM_PLIST(d, di + 1, cnt);
            }
            else {
                cnt = SumInt(cnt, one);
                vec = CONST_BLOCKS_GF2VEC(ovec);
                SET_ELM_PLIST(d, di + 1, cnt);
                CHANGED_BAG(d);
            }
        }
        AddGF2VecToGF2Vec(BLOCKS_GF2VEC(osum),
                          CONST_BLOCKS_GF2VEC(ELM_PLIST(vp, i + 1)), len);
    }
}

static Obj FuncDIST_VEC_CLOS_VEC(
    Obj self,
    Obj veclis,    // pointers to matrix vectors and their multiples
    Obj vec,       // vector we compute distance to
    Obj d)         // distances list

{
    Obj  sum;    // sum vector
    UInt len;

    len = LEN_GF2VEC(vec);

    // get space for sum vector
    NEW_GF2VEC(sum, TYPE_LIST_GF2VEC, len);

    // do the recursive work
    DistVecClosVec(veclis, vec, d, sum, 1, LEN_PLIST(veclis), len);

    return (Obj)0;
}

static UInt
AClosVec(Obj  veclis,    // pointers to matrix vectors and their multiples
         Obj  ovec,      // vector we compute distance to
         Obj  osum,      // position of the sum vector
         UInt pos,       // recursion depth
         UInt l,         // length of basis
         UInt len,       // length of the involved vectors
         UInt cnt,       // numbr of vectors used
         UInt stop,      // stop value
         UInt bd,        // best distance so far
         Obj  obv,       // best vector so far
         Obj  coords,    // coefficients to get current vector
         Obj  bcoords    // coefficients to get best vector
)
{
    UInt         di;
    Obj          vp;
    UInt *       sum;
    UInt *       bv;
    const UInt * vec;
    const UInt * end;
    const UInt * w;


    // maybe we don't add this basis vector -- if this leaves us enough
    // possibilitiies
    if (pos + cnt < l) {
        bd = AClosVec(veclis, ovec, osum, pos + 1, l, len, cnt, stop, bd, obv,
                      coords, bcoords);
        if (bd <= stop) {
            return bd;
        }
    }


    // Otherwise we do

    vec = CONST_BLOCKS_GF2VEC(ovec);
    sum = BLOCKS_GF2VEC(osum);
    vp = ELM_PLIST(veclis, pos);
    w = CONST_BLOCKS_GF2VEC(ELM_PLIST(vp, 1));
    AddGF2VecToGF2Vec(sum, w, len);

    if (coords != (Obj)0) {
        SET_ELM_PLIST(coords, pos, INTOBJ_INT(1));
    }


    if (cnt == 0)    // this is a candidate
    {
        di = DistGF2Vecs(sum, vec, len);
        if (di < bd) {

            // store new result
            bd = di;
            bv = BLOCKS_GF2VEC(obv);
            end = bv + ((len + BIPEB - 1) / BIPEB);
            while (bv < end)
                *bv++ = *sum++;
            sum = BLOCKS_GF2VEC(osum);
            if (coords != (Obj)0) {
                UInt i;
                for (i = 1; i <= l; i++) {
                    Obj x;
                    x = ELM_PLIST(coords, i);
                    SET_ELM_PLIST(bcoords, i, x);
                }
            }
        }
    }
    else    // need to add in some more
    {
        bd = AClosVec(veclis, ovec, osum, pos + 1, l, len, cnt - 1, stop, bd,
                      obv, coords, bcoords);
        if (bd <= stop) {
            return bd;
        }
    }

    // reset component
    AddGF2VecToGF2Vec(sum, w, len);
    if (coords != (Obj)0) {
        SET_ELM_PLIST(coords, pos, INTOBJ_INT(0));
    }

    TakeInterrupt();
    return bd;
}


static Obj FuncA_CLOS_VEC(
    Obj self,
    Obj veclis,    // pointers to matrix vectors and their multiples
    Obj vec,       // vector we compute distance to
    Obj cnt,       // distances list
    Obj stop)      // distances list

{
    Obj  sum;     // sum vector
    Obj  best;    // best vector
    UInt len;

    len = LEN_GF2VEC(vec);

    RequireNonnegativeSmallInt(SELF_NAME, cnt);
    RequireNonnegativeSmallInt(SELF_NAME, stop);

    // get space for sum vector and zero out
    NEW_GF2VEC(sum, TYPE_LIST_GF2VEC, len);
    NEW_GF2VEC(best, TYPE_LIST_GF2VEC, len);

    // do the recursive work
    AClosVec(veclis, vec, sum, 1, LEN_PLIST(veclis), len, INT_INTOBJ(cnt),
             INT_INTOBJ(stop), len + 1,    // maximal value +1
             best, (Obj)0, (Obj)0);

    return best;
}

static Obj FuncA_CLOS_VEC_COORDS(
    Obj self,
    Obj veclis,    // pointers to matrix vectors and their multiples
    Obj vec,       // vector we compute distance to
    Obj cnt,       // distances list
    Obj stop)      // distances list

{
    Obj  sum;        // sum vector
    Obj  best;       // best vector
    Obj  coords;     // coefficients of mat to get current
    Obj  bcoords;    // coefficients of mat to get best
    Obj  res;        // length 2 plist for results
    UInt len, len2, i;

    len = LEN_GF2VEC(vec);
    len2 = LEN_PLIST(veclis);

    RequireNonnegativeSmallInt(SELF_NAME, cnt);
    RequireNonnegativeSmallInt(SELF_NAME, stop);

    // get space for sum vector and zero out
    NEW_GF2VEC(sum, TYPE_LIST_GF2VEC, len);
    NEW_GF2VEC(best, TYPE_LIST_GF2VEC, len);

    coords = NEW_PLIST(T_PLIST_CYC, len2);
    SET_LEN_PLIST(coords, len2);

    bcoords = NEW_PLIST(T_PLIST_CYC, len2);
    SET_LEN_PLIST(bcoords, len2);

    for (i = 1; i <= len2; i++) {
        SET_ELM_PLIST(coords, i, INTOBJ_INT(0));
        SET_ELM_PLIST(bcoords, i, INTOBJ_INT(0));
    }

    // do the recursive work
    AClosVec(veclis, vec, sum, 1, len2, len, INT_INTOBJ(cnt),
             INT_INTOBJ(stop), len + 1,    // maximal value +1
             best, coords, bcoords);

    res = NEW_PLIST(T_PLIST_DENSE_NHOM, 2);
    SET_LEN_PLIST(res, 2);
    SET_ELM_PLIST(res, 1, best);
    SET_ELM_PLIST(res, 2, bcoords);
    CHANGED_BAG(res);
    return res;
}

/****************************************************************************
**
*F  FuncCOSET_LEADERS_INNER_GF2(<self>,<veclis>,<weight>,<tofind>,<leaders>)
**
** Search for new coset leaders of weight <weight>
*/


static UInt CosetLeadersInnerGF2(
    Obj veclis, Obj v, Obj w, UInt weight, UInt pos, Obj leaders, UInt tofind)
{
    UInt found = 0;
    UInt len = LEN_GF2VEC(v);
    UInt lenw = LEN_GF2VEC(w);
    UInt sy;
    UInt u0;
    Obj  vc;
    UInt i;

    // We know that the length of w does not exceed BIPEB -4 here
    // (or there would not be room in a PLIST for all the coset leaders).
    // We use this to do a lot of GF2 vector operations for w "in-place"
    //
    // Even more in this direction could be done, but this no longer
    // the rate-determining step for any feasible application

    if (weight == 1) {
        for (i = pos; i <= len; i++) {
            u0 = CONST_BLOCKS_GF2VEC(ELM_PLIST(ELM_PLIST(veclis, i), 1))[0];
            BLOCKS_GF2VEC(w)[0] ^= u0;
            BLOCK_ELM_GF2VEC(v, i) |= MASK_POS_GF2VEC(i);

            sy = revertbits(CONST_BLOCKS_GF2VEC(w)[0], lenw);
            if ((Obj)0 == ELM_PLIST(leaders, sy + 1)) {
                NEW_GF2VEC(vc, TYPE_LIST_GF2VEC_IMM, len);
                memcpy(BLOCKS_GF2VEC(vc), CONST_BLOCKS_GF2VEC(v),
                       NUMBER_BLOCKS_GF2VEC(v) * sizeof(UInt));
                SET_ELM_PLIST(leaders, sy + 1, vc);
                CHANGED_BAG(leaders);
                if (++found == tofind)
                    return found;
            }
            BLOCKS_GF2VEC(w)[0] ^= u0;
            BLOCK_ELM_GF2VEC(v, i) &= ~MASK_POS_GF2VEC(i);
        }
    }
    else {
        if (pos + weight <= len) {
            found += CosetLeadersInnerGF2(veclis, v, w, weight, pos + 1,
                                          leaders, tofind);
            if (found == tofind)
                return found;
        }
        u0 = CONST_BLOCKS_GF2VEC(ELM_PLIST(ELM_PLIST(veclis, pos), 1))[0];
        BLOCKS_GF2VEC(w)[0] ^= u0;
        BLOCK_ELM_GF2VEC(v, pos) |= MASK_POS_GF2VEC(pos);
        found += CosetLeadersInnerGF2(veclis, v, w, weight - 1, pos + 1,
                                      leaders, tofind - found);
        if (found == tofind)
            return found;
        BLOCKS_GF2VEC(w)[0] ^= u0;
        BLOCK_ELM_GF2VEC(v, pos) &= ~MASK_POS_GF2VEC(pos);
    }
    TakeInterrupt();
    return found;
}


static Obj FuncCOSET_LEADERS_INNER_GF2(
    Obj self, Obj veclis, Obj weight, Obj tofind, Obj leaders)
{
    Obj  v, w;
    UInt lenv, lenw;

    RequireSmallInt(SELF_NAME, weight);
    RequireSmallInt(SELF_NAME, tofind);

    lenv = LEN_PLIST(veclis);
    NEW_GF2VEC(v, TYPE_LIST_GF2VEC, lenv);
    lenw = LEN_GF2VEC(ELM_PLIST(ELM_PLIST(veclis, 1), 1));
    NEW_GF2VEC(w, TYPE_LIST_GF2VEC, lenw);
    if (lenw > BIPEB - 4)
        ErrorMayQuit("COSET_LEADERS_INNER_GF2: too many cosets to return the "
                     "leaders in a plain list",
                     0, 0);
    return INTOBJ_INT(CosetLeadersInnerGF2(veclis, v, w, INT_INTOBJ(weight),
                                           1, leaders, INT_INTOBJ(tofind)));
}

/****************************************************************************
**
*F  Polynomial Arithmetic Support
*/



/****************************************************************************
**
*F  FuncRIGHTMOST_NONZERO_GF2VEC (<self>, <vec> )
**
*/


static Obj FuncRIGHTMOST_NONZERO_GF2VEC(Obj self, Obj vec)
{
    return INTOBJ_INT(RightMostOneGF2Vec(vec));
}

/****************************************************************************
**
*F  ResizeGF2Vec( <vec>, <newlen>, <clean> )
**
*/


static void ResizeGF2Vec(Obj vec, UInt newlen)
{
    UInt   len;
    UInt * ptr;
    UInt * nptr;
    UInt   off;
    len = LEN_GF2VEC(vec);
    if (len == newlen)
        return;
    if (True == DoFilter(IsLockedRepresentationVector, vec)) {
        ErrorMayQuit("Resize of locked compressed vector is forbidden", 0, 0);
    }


    if (newlen > len) {
        ResizeWordSizedBag(vec, SIZE_PLEN_GF2VEC(newlen));

        // now clean remainder of last block
        if (len == 0)
            ptr = BLOCKS_GF2VEC(vec);
        else {
            ptr = BLOCKS_GF2VEC(vec) + (len - 1) / BIPEB;
            off = BIPEB - ((len - 1) % BIPEB +
                           1);    // number of insignificant bits in last word
            *ptr &= ALL_BITS_UINT >> off;
            ptr++;
        }

        // and clean new blocks -- shouldn't need to do this, but
        // it's very cheap

        // newlen can't be zero here, since it is bigger than len
        nptr = BLOCKS_GF2VEC(vec) + (newlen - 1) / BIPEB;
        while (ptr <= nptr)
            *ptr++ = 0;

        SET_LEN_GF2VEC(vec, newlen);
        return;
    }
    else {
        // clean remainder of new last block, if any
        if (newlen % BIPEB) {
            ptr = BLOCKS_GF2VEC(vec) + (newlen - 1) / BIPEB;
            off = BIPEB - ((newlen - 1) % BIPEB + 1);
            *ptr &= ALL_BITS_UINT >> off;
        }
        SET_LEN_GF2VEC(vec, newlen);
        ResizeWordSizedBag(vec, SIZE_PLEN_GF2VEC(newlen));
        return;
    }
}

/****************************************************************************
**
*F  FuncRESIZE_GF2VEC( <self>, <vec>, <newlen> )
**
*/


static Obj FuncRESIZE_GF2VEC(Obj self, Obj vec, Obj newlen)
{
    RequireMutable(SELF_NAME, vec, "vector");
    RequireNonnegativeSmallInt(SELF_NAME, newlen);
    ResizeGF2Vec(vec, INT_INTOBJ(newlen));
    return (Obj)0;
}


/****************************************************************************
**
*F  ShiftLeftGF2Vec( <vec>, <amount> )
**
*/


static void ShiftLeftGF2Vec(Obj vec, UInt amount)
{
    UInt  len;
    UInt *ptr1, *ptr2;
    UInt  i;
    UInt  block;
    UInt  off;
    if (amount == 0)
        return;
    len = LEN_GF2VEC(vec);
    if (amount >= len) {
        ResizeGF2Vec(vec, 0);
        return;
    }
    if (amount % BIPEB == 0) {
        ptr1 = BLOCKS_GF2VEC(vec);
        ptr2 = ptr1 + amount / BIPEB;
        for (i = 0; i < (len - amount + BIPEB - 1) / BIPEB; i++)
            *ptr1++ = *ptr2++;
    }
    else {
        ptr1 = BLOCKS_GF2VEC(vec);
        ptr2 = ptr1 + amount / BIPEB;
        off = amount % BIPEB;
        for (i = 0; i < (len - amount + BIPEB - 1) / BIPEB - 1; i++) {
            block = (*ptr2++) >> off;
            block |= (*ptr2) << (BIPEB - off);
            *ptr1++ = block;
        }
        // Handle last block separately to avoid reading off end of Bag
        block = (*ptr2++) >> off;
        if (ptr2 < BLOCKS_GF2VEC(vec) + NUMBER_BLOCKS_GF2VEC(vec))
            block |= (*ptr2) << (BIPEB - off);
        *ptr1 = block;
    }
    ResizeGF2Vec(vec, len - amount);
}

/****************************************************************************
**
*F  FuncSHIFT_LEFT_GF2VEC(<self>, <vec>, <amount> )
**
*/


static Obj FuncSHIFT_LEFT_GF2VEC(Obj self, Obj vec, Obj amount)
{
    RequireMutable(SELF_NAME, vec, "vector");
    RequireNonnegativeSmallInt(SELF_NAME, amount);
    ShiftLeftGF2Vec(vec, INT_INTOBJ(amount));
    return (Obj)0;
}

/****************************************************************************
**
*F  ShiftRightGF2Vec( <vec>, <amount> )
**
*/


static void ShiftRightGF2Vec(Obj vec, UInt amount)
{
    UInt  len;
    UInt *ptr1, *ptr2, *ptr0;
    UInt  i;
    UInt  block;
    UInt  off;
    if (amount == 0)
        return;
    len = LEN_GF2VEC(vec);
    ResizeGF2Vec(vec, len + amount);
    if (amount % BIPEB == 0) {
        // move the blocks
        ptr1 = BLOCKS_GF2VEC(vec) + (len - 1 + amount) / BIPEB;
        ptr2 = ptr1 - amount / BIPEB;
        for (i = 0; i < (len + BIPEB - 1) / BIPEB; i++)
            *ptr1-- = *ptr2--;

        // and fill with zeroes
        ptr2 = BLOCKS_GF2VEC(vec);
        while (ptr1 >= ptr2)
            *ptr1-- = 0;
    }
    else {
        ptr1 = BLOCKS_GF2VEC(vec) + (len - 1 + amount) / BIPEB;
        ptr2 = ptr1 - amount / BIPEB;    // this can sometimes be the block
                                         // AFTER the old last block, but this
                                         // must be OK
        off = amount % BIPEB;
        ptr0 = BLOCKS_GF2VEC(vec);
        while (1) {
            block = (*ptr2--) << off;
            if (ptr2 < ptr0)
                break;
            block |= (*ptr2) >> (BIPEB - off);
            *ptr1-- = block;
        }
        *ptr1-- = block;
        while (ptr1 >= ptr0)
            *ptr1-- = 0;
    }
}

/****************************************************************************
**
*F  FuncSHIFT_RIGHT_GF2VEC(<self>, <vec>, <amount>, <zero> )
**
*/


static Obj FuncSHIFT_RIGHT_GF2VEC(Obj self, Obj vec, Obj amount, Obj zero)
{
    RequireMutable(SELF_NAME, vec, "vector");
    RequireNonnegativeSmallInt(SELF_NAME, amount);
    ShiftRightGF2Vec(vec, INT_INTOBJ(amount));
    return (Obj)0;
}

// ReduceCoeffs

/****************************************************************************
**
*F  AddShiftedVecGF2VecGF2( <vec1>, <vec2>, <len2>, <off> )
**
*/


static void AddShiftedVecGF2VecGF2(Obj vec1, Obj vec2, UInt len2, UInt off)
{
    UInt *       ptr1;
    const UInt * ptr2;
    UInt         i;
    UInt         block;
    UInt         shift1, shift2;
    if (off % BIPEB == 0) {
        ptr1 = BLOCKS_GF2VEC(vec1) + off / BIPEB;
        ptr2 = CONST_BLOCKS_GF2VEC(vec2);
        for (i = 0; i < (len2 - 1) / BIPEB; i++)
            *ptr1++ ^= *ptr2++;
        block = *ptr2;
        block &= (ALL_BITS_UINT >> (BIPEB - (len2 - 1) % BIPEB - 1));
        *ptr1 ^= block;
    }
    else {
        ptr1 = BLOCKS_GF2VEC(vec1) + off / BIPEB;
        ptr2 = CONST_BLOCKS_GF2VEC(vec2);
        shift1 = off % BIPEB;
        shift2 = BIPEB - off % BIPEB;
        for (i = 0; i < len2 / BIPEB; i++) {
            *ptr1++ ^= *ptr2 << shift1;
            *ptr1 ^= *ptr2++ >> shift2;
        }

        if (len2 % BIPEB) {
            block = *ptr2;
            block &= ALL_BITS_UINT >> (BIPEB - (len2 - 1) % BIPEB - 1);
            *ptr1++ ^= block << shift1;
            if (len2 % BIPEB + off % BIPEB > BIPEB) {
                assert(ptr1 < BLOCKS_GF2VEC(vec1) +
                                  (LEN_GF2VEC(vec1) + BIPEB - 1) / BIPEB);
                *ptr1 ^= block >> shift2;
            }
        }
    }
}

/****************************************************************************
**
*F FuncADD_GF2VEC_GF2VEC_SHIFTED( <self>, <vec1>, <vec2>, <len2>, <off> )
**
*/


static Obj
FuncADD_GF2VEC_GF2VEC_SHIFTED(Obj self, Obj vec1, Obj vec2, Obj len2, Obj off)
{
    RequireNonnegativeSmallInt(SELF_NAME, off);
    RequireNonnegativeSmallInt(SELF_NAME, len2);
    Int off1 = INT_INTOBJ(off);
    Int len2a = INT_INTOBJ(len2);
    if (len2a >= LEN_GF2VEC(vec2)) {
        ErrorMayQuit(
            "ADD_GF2VEC_GF2VEC_SHIFTED: <len2> must be a non-negative "
            "integer less than the actual length of the vector",
            0, 0);
    }
    if (len2a + off1 > LEN_GF2VEC(vec1))
        ResizeGF2Vec(vec1, len2a + off1);
    AddShiftedVecGF2VecGF2(vec1, vec2, len2a, off1);
    return (Obj)0;
}

/****************************************************************************
**
*F  ProductCoeffsGF2Vec( <vec1>, <len1>, <vec2>, <len2> )
**
*/


static Obj ProductCoeffsGF2Vec(Obj vec1, UInt len1, Obj vec2, UInt len2)
{
    Obj          prod;
    UInt         i, e;
    const UInt * ptr;
    UInt         block = 0;
    UInt         len;
    if (len1 == 0 && len2 == 0)
        len = 0;
    else
        len = len1 + len2 - 1;
    NEW_GF2VEC(prod, TYPE_LIST_GF2VEC, len);

    // better to do the longer loop on the inside
    if (len2 < len1) {
        UInt tmp;
        Obj  tmpv;
        tmp = len1;
        len1 = len2;
        len2 = tmp;
        tmpv = vec1;
        vec1 = vec2;
        vec2 = tmpv;
    }

    ptr = CONST_BLOCKS_GF2VEC(vec1);
    e = BIPEB;
    for (i = 0; i < len1; i++) {
        if (e == BIPEB) {
            block = *ptr++;
            e = 0;
        }
        if (block & ((UInt)1 << e++))
            AddShiftedVecGF2VecGF2(prod, vec2, len2, i);
    }
    return prod;
}

/****************************************************************************
**
*F  FuncPROD_COEFFS_GF2VEC( <self>, <vec1>, <len1>, <vec2>, <len2> )
**
*/


static Obj
FuncPROD_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2)
{
    UInt len1a, len2a;
    Obj  prod;
    UInt last;

    RequireSmallInt(SELF_NAME, len1);
    RequireSmallInt(SELF_NAME, len2);
    len2a = INT_INTOBJ(len2);
    if (len2a > LEN_GF2VEC(vec2))
        ErrorMayQuit("PROD_COEFFS_GF2VEC: <len2> must not be more than the "
                     "actual\nlength of the vector",
                     0, 0);
    len1a = INT_INTOBJ(len1);
    if (len1a > LEN_GF2VEC(vec1))
        ErrorMayQuit("PROD_COEFFS_GF2VEC: <len1> must be not more than the "
                     "actual\nlength of the vector",
                     0, 0);
    prod = ProductCoeffsGF2Vec(vec1, len1a, vec2, len2a);
    last = RightMostOneGF2Vec(prod);
    if (last < LEN_GF2VEC(prod))
        ResizeGF2Vec(prod, last);
    return prod;
}

/****************************************************************************
**
*F  ReduceCoeffsGF2Vec(<vec1>, <vec2>, <len2>, <quotient> )
**
*/


static void ReduceCoeffsGF2Vec(Obj vec1, Obj vec2, UInt len2, Obj quotient)
{
    UInt         len1 = LEN_GF2VEC(vec1);
    UInt         i, j, e;
    const UInt * ptr;
    UInt *       qptr = (UInt *)0;
    if (len2 > len1)
        return;
    i = len1 - 1;
    e = (i % BIPEB);
    ptr = CONST_BLOCKS_GF2VEC(vec1) + (i / BIPEB);
    if (quotient != (Obj)0)
        qptr = BLOCKS_GF2VEC(quotient);
    j = len1 - len2 + 1;
    while (i + 1 >= len2) {
        if (*ptr & ((UInt)1 << e)) {
            AddShiftedVecGF2VecGF2(vec1, vec2, len2, i - len2 + 1);
            if (qptr)
                qptr[(j - 1) / BIPEB] |= MASK_POS_GF2VEC(j);
        }
        assert(!(*ptr & ((UInt)1 << e)));
        if (e == 0) {
            e = BIPEB - 1;
            ptr--;
        }
        else
            e--;
        i--;
        j--;
    }
}

/****************************************************************************
**
*F  FuncREDUCE_COEFFS_GF2VEC( <self>, <vec1>, <len1>, <vec2>, <len2> )
**
*/

static Obj
FuncREDUCE_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2)
{
    UInt last;
    Int  len2a;
    RequireNonnegativeSmallInt(SELF_NAME, len1);
    RequireNonnegativeSmallInt(SELF_NAME, len2);
    if (INT_INTOBJ(len1) > LEN_GF2VEC(vec1))
        ErrorMayQuit("ReduceCoeffs: given length <len1> of left argt "
                     "(%d)\nis longer than the argt (%d)",
                     INT_INTOBJ(len1), LEN_GF2VEC(vec1));
    len2a = INT_INTOBJ(len2);
    if (len2a > LEN_GF2VEC(vec2))
        ErrorMayQuit("ReduceCoeffs: given length <len2> of right argt "
                     "(%d)\nis longer than the argt (%d)",
                     len2a, LEN_GF2VEC(vec2));
    ResizeGF2Vec(vec1, INT_INTOBJ(len1));

    while (0 < len2a) {
        if (CONST_BLOCK_ELM_GF2VEC(vec2, len2a) == 0)
            len2a = BIPEB * ((len2a - 1) / BIPEB);
        else if (CONST_BLOCK_ELM_GF2VEC(vec2, len2a) & MASK_POS_GF2VEC(len2a))
            break;
        else
            len2a--;
    }

    if (len2a == 0) {
        ErrorReturnVoid("ReduceCoeffs: second argument must not be zero", 0,
                        0, "you may 'return;' to skip the reduction");
        return 0;
    }

    ReduceCoeffsGF2Vec(vec1, vec2, len2a, (Obj)0);
    last = RightMostOneGF2Vec(vec1);
    ResizeGF2Vec(vec1, last);
    return INTOBJ_INT(last);
}

/****************************************************************************
**
*F  FuncQUOTREM_COEFFS_GF2VEC( <self>, <vec1>, <len1>, <vec2>, <len2> )
**
*/

static Obj
FuncQUOTREM_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2)
{
    Int len2a;
    Int len1a = INT_INTOBJ(len1);
    Obj quotv, remv, ret;
    RequireNonnegativeSmallInt(SELF_NAME, len1);
    RequireNonnegativeSmallInt(SELF_NAME, len2);
    if (INT_INTOBJ(len1) > LEN_GF2VEC(vec1))
        ErrorMayQuit("QuotremCoeffs: given length <len1> of left argt "
                     "(%d)\nis longer than the argt (%d)",
                     INT_INTOBJ(len1), LEN_GF2VEC(vec1));
    len2a = INT_INTOBJ(len2);
    if (len2a > LEN_GF2VEC(vec2))
        ErrorMayQuit("QuotremCoeffs: given length <len2> of right argt "
                     "(%d)\nis longer than the argt (%d)",
                     len2a, LEN_GF2VEC(vec2));

    while (0 < len2a) {
        if (CONST_BLOCK_ELM_GF2VEC(vec2, len2a) == 0)
            len2a = BIPEB * ((len2a - 1) / BIPEB);
        else if (CONST_BLOCK_ELM_GF2VEC(vec2, len2a) & MASK_POS_GF2VEC(len2a))
            break;
        else
            len2a--;
    }
    if (len2a == 0) {
        ErrorReturnVoid("QuotremCoeffs: second argument must not be zero", 0,
                        0, "you may 'return;' to skip the reduction");
        return 0;
    }

    NEW_GF2VEC(remv, TYPE_LIST_GF2VEC, len1a);
    memcpy(BLOCKS_GF2VEC(remv), CONST_BLOCKS_GF2VEC(vec1),
           ((len1a + BIPEB - 1) / BIPEB) * sizeof(UInt));

    NEW_GF2VEC(quotv, TYPE_LIST_GF2VEC, len1a - len2a + 1);
    ReduceCoeffsGF2Vec(remv, vec2, len2a, quotv);

    ret = NEW_PLIST(T_PLIST_TAB, 2);
    SET_LEN_PLIST(ret, 2);

    SET_ELM_PLIST(ret, 1, quotv);
    SET_ELM_PLIST(ret, 2, remv);

    CHANGED_BAG(ret);

    return ret;
}


/****************************************************************************
**
*F  FuncSEMIECHELON_LIST_GF2VECS( <self>, <mat> )
**
**  Method for SemiEchelonMat for plain lists of GF2 vectors
**
**  Method selection can guarantee us a plain list of characteristic 2
**  vectors
*/


static Obj FuncSEMIECHELON_LIST_GF2VECS(Obj self, Obj mat)
{
    UInt i, len;
    UInt width;
    Obj  row;
    len = LEN_PLIST(mat);
    if (!len)
        return TRY_NEXT_METHOD;
    row = ELM_PLIST(mat, 1);
    if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row))
        return TRY_NEXT_METHOD;
    width = LEN_GF2VEC(row);
    if (width == 0)
        return TRY_NEXT_METHOD;
    for (i = 2; i <= len; i++) {
        row = ELM_PLIST(mat, i);
        if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row) ||
            LEN_GF2VEC(row) != width) {
            return TRY_NEXT_METHOD;
        }
    }
    return SemiEchelonListGF2Vecs(mat, 0);
}

/****************************************************************************
**
*F  FuncSEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS( <self>, <mat> )
**
**  Method for SemiEchelonMatTransformations for plain lists of GF2 vectors
**
**  Method selection can guarantee us a plain list of characteristic 2
**  vectors
*/


static Obj FuncSEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS(Obj self, Obj mat)
{
    UInt i, len;
    UInt width;
    Obj  row;
    len = LEN_PLIST(mat);
    if (!len)
        return TRY_NEXT_METHOD;
    row = ELM_PLIST(mat, 1);
    if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row))
        return TRY_NEXT_METHOD;
    width = LEN_GF2VEC(row);
    if (width == 0)
        return TRY_NEXT_METHOD;
    for (i = 2; i <= len; i++) {
        row = ELM_PLIST(mat, i);
        if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row) ||
            LEN_GF2VEC(row) != width) {
            return TRY_NEXT_METHOD;
        }
    }
    return SemiEchelonListGF2Vecs(mat, 1);
}

/****************************************************************************
**
*F  FuncTRIANGULIZE_LIST_GF2VECS( <self>, <mat> )
**
*/


static Obj FuncTRIANGULIZE_LIST_GF2VECS(Obj self, Obj mat)
{
    UInt i, len;
    UInt width;
    Obj  row;
    len = LEN_PLIST(mat);
    if (!len)
        return TRY_NEXT_METHOD;
    row = ELM_PLIST(mat, 1);
    if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row))
        return TRY_NEXT_METHOD;
    width = LEN_GF2VEC(row);
    if (width == 0)
        return TRY_NEXT_METHOD;
    for (i = 2; i <= len; i++) {
        row = ELM_PLIST(mat, i);
        if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row) ||
            LEN_GF2VEC(row) != width) {
            return TRY_NEXT_METHOD;
        }
    }
    TriangulizeListGF2Vecs(mat, 1);
    return (Obj)0;
}

/****************************************************************************
**
*F  FuncRANK_LIST_GF2VECS( <self>, <mat> )
**
*/


static Obj FuncRANK_LIST_GF2VECS(Obj self, Obj mat)
{
    UInt i, len;
    UInt width;
    Obj  row;
    len = LEN_PLIST(mat);
    if (!len)
        return TRY_NEXT_METHOD;
    row = ELM_PLIST(mat, 1);
    if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row))
        return TRY_NEXT_METHOD;
    width = LEN_GF2VEC(row);
    if (width == 0)
        return TRY_NEXT_METHOD;
    for (i = 2; i <= len; i++) {
        row = ELM_PLIST(mat, i);
        if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row) ||
            LEN_GF2VEC(row) != width) {
            return TRY_NEXT_METHOD;
        }
    }
    return INTOBJ_INT(TriangulizeListGF2Vecs(mat, 0));
}

/****************************************************************************
**
*F  FuncDETERMINANT_LIST_GF2VECS( <self>, <mat> )
**
*/


static Obj FuncDETERMINANT_LIST_GF2VECS(Obj self, Obj mat)
{
    UInt i, len;
    UInt width;
    Obj  row;
    len = LEN_PLIST(mat);
    if (!len)
        return TRY_NEXT_METHOD;
    row = ELM_PLIST(mat, 1);
    if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row))
        return TRY_NEXT_METHOD;
    width = LEN_GF2VEC(row);
    if (width == 0)
        return TRY_NEXT_METHOD;
    for (i = 2; i <= len; i++) {
        row = ELM_PLIST(mat, i);
        if (!IS_MUTABLE_OBJ(row) || !IS_GF2VEC_REP(row) ||
            LEN_GF2VEC(row) != width) {
            return TRY_NEXT_METHOD;
        }
    }
    return (len == TriangulizeListGF2Vecs(mat, 0)) ? GF2One : GF2Zero;
}

/****************************************************************************
**
*F  FuncKRONECKERPRODUCT_GF2MAT_GF2MAT( <self>, <matl>, <matr>)
**
*/


static Obj FuncKRONECKERPRODUCT_GF2MAT_GF2MAT(Obj self, Obj matl, Obj matr)
{
    UInt nrowl, nrowr, nrowp, ncoll, ncolr, ncolp, ncol, i, j, k, l, mutable;
    Obj  mat, type, row, shift[BIPEB];
    UInt *       data;
    const UInt * datar;

    nrowl = LEN_GF2MAT(matl);
    nrowr = LEN_GF2MAT(matr);
    nrowp = nrowl * nrowr;
    ncoll = LEN_GF2VEC(ELM_GF2MAT(matl, 1));
    ncolr = LEN_GF2VEC(ELM_GF2MAT(matr, 1));
    ncolp = ncoll * ncolr;

    mutable = IS_MUTABLE_OBJ(matl) || IS_MUTABLE_OBJ(matr);

    // create a matrix
    mat = NewBag(T_POSOBJ, SIZE_PLEN_GF2MAT(nrowp));
    SET_LEN_GF2MAT(mat, nrowp);
    if (mutable) {
        SET_TYPE_POSOBJ(mat, TYPE_LIST_GF2MAT);
        type = TYPE_LIST_GF2VEC_LOCKED;
    }
    else {
        SET_TYPE_POSOBJ(mat, TYPE_LIST_GF2MAT_IMM);
        type = TYPE_LIST_GF2VEC_IMM_LOCKED;
    }

    // allocate 0 matrix

    for (i = 1; i <= nrowp; i++) {
        NEW_GF2VEC(row, type, ncolp);
        SET_ELM_GF2MAT(mat, i, row);
        CHANGED_BAG(mat);
    }

    // allocate data for shifts of rows of matr
    for (i = 0; i < BIPEB; i++) {
        shift[i] = NewBag(T_DATOBJ, SIZE_PLEN_GF2VEC(ncolr + 2 * BIPEB));
    }

    // fill in matrix
    for (j = 1; j <= nrowr; j++) {
        // create shifts of rows of matr
        data = (UInt *)ADDR_OBJ(shift[0]);
        datar = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(matr, j));
        for (k = 0; k < (ncolr + BIPEB - 1) / BIPEB; k++)
            data[k] = datar[k];
        data[k] = 0;

        for (i = 1; i < BIPEB; i++) {    // now shifts in [1..BIPEB-1]
            data = (UInt *)ADDR_OBJ(shift[i]);
            datar = CONST_BLOCKS_GF2VEC(ELM_GF2MAT(matr, j));
            data[0] = datar[0] << i;
            for (k = 1; k < (ncolr + BIPEB - 1) / BIPEB; k++)
                data[k] = (datar[k] << i) | (datar[k - 1] >> (BIPEB - i));
            data[k] = datar[k - 1] >> (BIPEB - i);
        }
        for (i = 1; i <= nrowl; i++) {
            data = BLOCKS_GF2VEC(ELM_GF2MAT(mat, (i - 1) * nrowr + j));
            ncol = 0;
            for (k = 1; k <= ncoll; k++) {
                l = 0;
                if (CONST_BLOCK_ELM_GF2VEC(ELM_GF2MAT(matl, i), k) &
                    MASK_POS_GF2VEC(k)) {
                    // append shift[ncol%BIPEB] to data
                    datar = (const UInt *)CONST_ADDR_OBJ(shift[ncol % BIPEB]);
                    if (ncol % BIPEB) {
                        data[-1] ^= *datar++;
                        l = BIPEB - ncol % BIPEB;
                    }
                    for (; l < ncolr; l += BIPEB)
                        *data++ = *datar++;
                }
                else {
                    if (ncol % BIPEB)
                        l = BIPEB - ncol % BIPEB;
                    data += (ncolr + BIPEB - 1 - l) / BIPEB;
                }
                ncol += ncolr;
            }
        }
    }

    return mat;
}


/****************************************************************************
**
*F  FuncMAT_ELM_GF2MAT( <self>, <mat>, <row>, <col> )
**
*/

static Obj FuncMAT_ELM_GF2MAT(Obj self, Obj mat, Obj row, Obj col)
{
    UInt r = GetPositiveSmallInt(SELF_NAME, row);
    UInt c = GetPositiveSmallInt(SELF_NAME, col);

    if (LEN_GF2MAT(mat) < r) {
        ErrorMayQuit("row index %d exceeds %d, the number of rows", r,
                     LEN_GF2MAT(mat));
    }

    Obj vec = ELM_GF2MAT(mat, r);

    if (LEN_GF2VEC(vec) < c) {
        ErrorMayQuit("column index %d exceeds %d, the number of columns", c,
                     LEN_GF2VEC(vec));
    }

    return ELM_GF2VEC(vec, c);
}


/****************************************************************************
**
*F  FuncSET_MAT_ELM_GF2MAT( <self>, <mat>, <row>, <col>, <elm> )
**
*/

static Obj
FuncSET_MAT_ELM_GF2MAT(Obj self, Obj mat, Obj row, Obj col, Obj elm)
{
    UInt r = GetPositiveSmallInt(SELF_NAME, row);
    UInt c = GetPositiveSmallInt(SELF_NAME, col);

    if (LEN_GF2MAT(mat) < r) {
        ErrorMayQuit("row index %d exceeds %d, the number of rows", r,
                     LEN_GF2MAT(mat));
    }

    Obj vec = ELM_GF2MAT(mat, r);
    if (!IS_MUTABLE_OBJ(vec)) {
        ErrorMayQuit("row %d is immutable", r, 0);
    }

    if (LEN_GF2VEC(vec) < c) {
        ErrorMayQuit("column index %d exceeds %d, the number of columns", c,
                     LEN_GF2VEC(vec));
    }

    if (EQ(GF2One, elm)) {
        BLOCK_ELM_GF2VEC(vec, c) |= MASK_POS_GF2VEC(c);
    }
    else if (EQ(GF2Zero, elm)) {
        BLOCK_ELM_GF2VEC(vec, c) &= ~MASK_POS_GF2VEC(c);
    }
    else {
        RequireArgumentEx(SELF_NAME, elm, 0,
                          "assigned element must be a GF(2) element");
    }

    return 0;
}


/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*V  GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/

static StructGVarFunc GVarFuncs[] = {

    GVAR_FUNC_1ARGS(CONV_GF2VEC, list),
    GVAR_FUNC_1ARGS(COPY_GF2VEC, list),
    GVAR_FUNC_1ARGS(PLAIN_GF2VEC, gf2vec),
    GVAR_FUNC_1ARGS(PLAIN_GF2MAT, gf2mat),
    GVAR_FUNC_2ARGS(EQ_GF2VEC_GF2VEC, gf2vec, gf2vec),
    GVAR_FUNC_2ARGS(LT_GF2VEC_GF2VEC, gf2vec, gf2vec),
    GVAR_FUNC_2ARGS(EQ_GF2MAT_GF2MAT, gf2mat, gf2mat),
    GVAR_FUNC_2ARGS(LT_GF2MAT_GF2MAT, gf2mat, gf2mat),
    GVAR_FUNC_1ARGS(LEN_GF2VEC, gf2vec),
    GVAR_FUNC_2ARGS(ELM0_GF2VEC, gf2vec, pos),
    GVAR_FUNC_2ARGS(ELM_GF2VEC, gf2vec, pos),
    GVAR_FUNC_2ARGS(ELMS_GF2VEC, gf2vec, poss),
    GVAR_FUNC_3ARGS(ASS_GF2VEC, gf2vec, pos, elm),
    GVAR_FUNC_2ARGS(ELM_GF2MAT, gf2mat, pos),
    GVAR_FUNC_3ARGS(ASS_GF2MAT, gf2mat, pos, elm),
    GVAR_FUNC_3ARGS(SWAP_ROWS_GF2MAT, gf2mat, row1, row2),
    GVAR_FUNC_3ARGS(SWAP_COLS_GF2MAT, gf2mat, col1, col2),
    GVAR_FUNC_2ARGS(UNB_GF2VEC, gf2vec, pos),
    GVAR_FUNC_2ARGS(UNB_GF2MAT, gf2mat, pos),
    GVAR_FUNC_1ARGS(ZERO_GF2VEC, gf2vec),
    GVAR_FUNC_1ARGS(ZERO_GF2VEC_2, len),
    GVAR_FUNC_1ARGS(INV_GF2MAT_MUTABLE, gf2mat),
    GVAR_FUNC_1ARGS(INV_GF2MAT_SAME_MUTABILITY, gf2mat),
    GVAR_FUNC_1ARGS(INV_GF2MAT_IMMUTABLE, gf2mat),
    GVAR_FUNC_1ARGS(INV_PLIST_GF2VECS_DESTRUCTIVE, list),
    GVAR_FUNC_2ARGS(SUM_GF2VEC_GF2VEC, gf2vec, gf2vec),
    GVAR_FUNC_2ARGS(PROD_GF2VEC_GF2VEC, gf2vec, gf2vec),
    GVAR_FUNC_2ARGS(PROD_GF2VEC_GF2MAT, gf2vec, gf2mat),
    GVAR_FUNC_2ARGS(PROD_GF2MAT_GF2VEC, gf2mat, gf2vec),
    GVAR_FUNC_2ARGS(PROD_GF2MAT_GF2MAT, gf2matl, gf2matr),
    GVAR_FUNC_2ARGS(PROD_GF2MAT_GF2MAT_SIMPLE, gf2matl, gf2matr),
    GVAR_FUNC_4ARGS(PROD_GF2MAT_GF2MAT_ADVANCED,
                    gf2matl,
                    gf2matr,
                    greaselevel,
                    blocklevel),
    GVAR_FUNC_3ARGS(ADDCOEFFS_GF2VEC_GF2VEC_MULT, gf2vec, gf2vec, mul),
    GVAR_FUNC_2ARGS(ADDCOEFFS_GF2VEC_GF2VEC, gf2vec, gf2vec),
    GVAR_FUNC_1ARGS(SHRINKCOEFFS_GF2VEC, gf2vec),
    GVAR_FUNC_2ARGS(POSITION_NONZERO_GF2VEC, gf2vec, zero),
    GVAR_FUNC_3ARGS(POSITION_NONZERO_GF2VEC3, gf2vec, zero, from),
    GVAR_FUNC_2ARGS(MULT_VECTOR_GF2VECS_2, gf2vecl, mul),
    GVAR_FUNC_2ARGS(APPEND_GF2VEC, gf2vecl, gf2vecr),
    GVAR_FUNC_1ARGS(SHALLOWCOPY_GF2VEC, gf2vec),
    GVAR_FUNC_1ARGS(NUMBER_GF2VEC, gf2vec),
    GVAR_FUNC_1ARGS(TRANSPOSED_GF2MAT, gf2mat),
    GVAR_FUNC_2ARGS(DIST_GF2VEC_GF2VEC, gf2vec, gf2vec),
    GVAR_FUNC_3ARGS(DIST_VEC_CLOS_VEC, list, gf2vec, list),
    GVAR_FUNC_2ARGS(SUM_GF2MAT_GF2MAT, matl, matr),
    GVAR_FUNC_4ARGS(A_CLOS_VEC, list, gf2vec, intint),
    GVAR_FUNC_4ARGS(A_CLOS_VEC_COORDS, list, gf2vec, intint),
    GVAR_FUNC_4ARGS(COSET_LEADERS_INNER_GF2, veclis, weight, tofind, leaders),
    GVAR_FUNC_1ARGS(CONV_GF2MAT, list),
    GVAR_FUNC_2ARGS(PROD_GF2VEC_ANYMAT, vec, mat),
    GVAR_FUNC_1ARGS(RIGHTMOST_NONZERO_GF2VEC, vec),
    GVAR_FUNC_2ARGS(RESIZE_GF2VEC, vec, newlen),
    GVAR_FUNC_2ARGS(SHIFT_LEFT_GF2VEC, vec, amount),
    GVAR_FUNC_3ARGS(SHIFT_RIGHT_GF2VEC, vec, amount, zero),
    GVAR_FUNC_4ARGS(ADD_GF2VEC_GF2VEC_SHIFTED, vec1, vec2, len2, off),
    GVAR_FUNC_4ARGS(PROD_COEFFS_GF2VEC, vec1, len1, vec2, len2),
    GVAR_FUNC_4ARGS(REDUCE_COEFFS_GF2VEC, vec1, len1, vec2, len2),
    GVAR_FUNC_4ARGS(QUOTREM_COEFFS_GF2VEC, vec1, len1, vec2, len2),
    GVAR_FUNC_1ARGS(SEMIECHELON_LIST_GF2VECS, mat),
    GVAR_FUNC_1ARGS(SEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS, mat),
    GVAR_FUNC_1ARGS(TRIANGULIZE_LIST_GF2VECS, mat),
    GVAR_FUNC_1ARGS(DETERMINANT_LIST_GF2VECS, mat),
    GVAR_FUNC_1ARGS(RANK_LIST_GF2VECS, mat),
    GVAR_FUNC_2ARGS(KRONECKERPRODUCT_GF2MAT_GF2MAT, mat, mat),
    GVAR_FUNC_5ARGS(COPY_SECTION_GF2VECS, src, dest, from, to, howmany),
    GVAR_FUNC_3ARGS(MAT_ELM_GF2MAT, mat, row, col),
    GVAR_FUNC_4ARGS(SET_MAT_ELM_GF2MAT, mat, row, col, elm),
    { 0, 0, 0, 0, 0 }

};


/****************************************************************************
**
*F  InitKernel( <module> )  . . . . . . . . initialise kernel data structures
*/

static Int InitKernel(StructInitInfo * module)
{
    RNheads = 0;
    RNvectors = 0;
    RNcoeffs = 0;
    RNrelns = 0;

    // import type functions
    InitCopyGVar("TYPE_LIST_GF2VEC", &TYPE_LIST_GF2VEC);
    InitCopyGVar("TYPE_LIST_GF2VEC_IMM", &TYPE_LIST_GF2VEC_IMM);
    InitCopyGVar("TYPE_LIST_GF2VEC_IMM_LOCKED",
                          &TYPE_LIST_GF2VEC_IMM_LOCKED);
    InitCopyGVar("TYPE_LIST_GF2VEC_LOCKED",
                          &TYPE_LIST_GF2VEC_LOCKED);
    ImportFuncFromLibrary("IsGF2VectorRep", &IsGF2VectorRep);
    InitCopyGVar("TYPE_LIST_GF2MAT", &TYPE_LIST_GF2MAT);
    InitCopyGVar("TYPE_LIST_GF2MAT_IMM", &TYPE_LIST_GF2MAT_IMM);

    // initialize one and zero of GF2
    ImportGVarFromLibrary("GF2One", &GF2One);
    ImportGVarFromLibrary("GF2Zero", &GF2Zero);

    // init filters and functions
    InitHdlrFuncsFromTable(GVarFuncs);

    InitFopyGVar("IsLockedRepresentationVector",
                 &IsLockedRepresentationVector);

    return 0;
}


/****************************************************************************
**
*F  InitLibrary( <module> ) . . . . . . .  initialise library data structures
*/

static Int InitLibrary(StructInitInfo * module)
{
    // init filters and functions
    InitGVarFuncsFromTable(GVarFuncs);

    return 0;
}


/****************************************************************************
**
*F  InitInfoGF2Vec()  . . . . . . . . . . . . . . . . table of init functions
*/

static StructInitInfo module = {
    // init struct using C99 designated initializers; for a full list of
    // fields, please refer to the definition of StructInitInfo
    .type = MODULE_BUILTIN,
    .name = "vecgf2",
    .initKernel = InitKernel,
    .initLibrary = InitLibrary,
};

StructInitInfo * InitInfoGF2Vec(void)
{
    return &module;
}

Messung V0.5 in Prozent
C=89 H=77 G=83

¤ Dauer der Verarbeitung: 0.59 Sekunden  (vorverarbeitet am  2026-05-06) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.