/////////////////////////////////////////////////////////////////////////////
// This C file has been created automatically. Do not edit!!!
/////////////////////////////////////////////////////////////////////////////

/** @file leech3matrix.c

  File ``leech3matrix.c`` contains  functions for computing with
  matrices corresponding to the part with tag 'A' of a vector
  of the representation of the monster modulo 3. Note that this
  part has a natural interpretation as a symmetric matrix on the
  Leech lattice.

  For these computations we deal with ``i0`` times ``i1``
  matrices ``m`` for ``i0 <= 24``, ``i1 <= 48``, Such a matrix
  is stored in an array ``a`` of integers of type ``uint64_t``
  of length 24 * 3. Here the entry ``m[i,j]`` is stored
  in ``a[3*i + j/16]``, bits ``4 * (j % 16),..., 4 * (j % 16) + 3``.
  We call ``a`` the **matrix mod 3** encoding of the matrix ``m``.

  Unless otherwise stated, we assume that the lower two bits of such
  a bit field have arbitrary values, and that the higher two bits
  of that bit field are zero.

  There are functions for loading such a matrix ``m`` from a
  vector in a represenation of the  monster, for elechonization
  of ``m``, for computing the kernel of ``m`` etc.
*/

/*************************************************************************
** External references 
*************************************************************************/

/// @cond DO_NOT_DOCUMENT 
#include <string.h>
#include "mat24_functions.h"
#define MMGROUP_GENERATORS_INTERN
#include "mmgroup_generators.h"
#define CLIFFORD12_INTERN
#include "clifford12.h"
/// @endcond  


// %%EXPORT_KWD CLIFFORD12_API

// %%GEN h
// %%GEN ch
#ifdef __cplusplus
extern "C" {
#endif
// %%GEN c


/*************************************************************************
*** Basic definitions
*************************************************************************/

/// @cond DO_NOT_DOCUMENT 


#define NEG_MASK_MOD3 0x3333333333333333ULL


/** @brief Reduce a bit field of integers modulo 3

  We assume that an array of integers (mod 3) is stored in an
  integer ``a`` of type ``uint64_t``. Here each entry of that
  array is stored in a field of 4 bits.

  We assume that in each entry the lower 3 bits may be set, and
  we reduce each entry to a length of 2 bits. The result is stored
  in ``a``. 
*/
#define REDUCE_MOD3(a) \
 (a) = (((a) + (((a) >> 2) & 0x1111111111111111ULL)) & NEG_MASK_MOD3)


/** @brief Final reduction of a bit field of integers modulo 3

  We assume that an array of integers (mod 3) is stored in an
  an integer ``a`` of type ``uint64_t``. Here each entry of that
  array is stored in a filed of 4 bits.

  We assume that in each entry the lower 2 bits may be set, and
  we reduce each entry of value 3 to 0. The result is stored
  in ``a``.

*/
#define REDUCE_FINAL_MOD3(a, tmp) \
 tmp = (a) & ((a) >> 1) & 0x5555555555555555ULL; \
 (a) ^=  tmp ^ (tmp << 1)


/** @brief Expand a bit field of integers modulo 3

  We assume that an array of integers (mod 3) is stored in an
  integer ``a`` of type ``uint64_t``. Here each entry of that
  array is stored in a field of 2 bits. 

  We expand the lower 16 bit fields from a length of 2 to a
  length of 4, and store the result in ``a``.  
*/
#define EXPAND_3_15(a) \
    (a) = ((a) & 0xffffULL) \
        +  (((a) & 0xffff0000ULL) << 16); \
    (a) = ((a) & 0xff000000ffULL) \
        +  (((a) & 0xff000000ff00ULL) << 8); \
    (a) = ((a) & 0xf000f000f000fULL) \
        +  (((a) & 0xf000f000f000f0ULL) << 4); \
    (a) = ((a) & 0x303030303030303ULL) \
        +  (((a) & 0xc0c0c0c0c0c0c0cULL) << 2)

/** @brief Compress a bit field of integers modulo 3

  We assume that an array of integers (mod 3) is stored in an
  integer ``a`` of type ``uint64_t``. Here each entry of that 
  array is stored in a field of 4 bits. 

  We assume that in each entry the lower 2 bits may be set. We 
  compress the bit fields of length 4 to adjacent bit fields of
  length 2 and store the result in the lower hals of ``a``.  
*/
#define COMPRESS_15_3(a) \
    (a) = ((a) & 0x303030303030303ULL) \
        +  (((a) >> 2) & 0xc0c0c0c0c0c0c0cULL); \
    (a) = ((a) & 0xf000f000f000fULL) \
        +  (((a) >> 4) & 0xf000f000f000f0ULL); \
    (a) = ((a) & 0xff000000ffULL) \
        +  (((a) >> 8) & 0xff000000ff00ULL); \
    (a) = ((a) & 0xffffULL) \
        +  (((a) >> 16) & 0xffff0000ULL)


/// @endcond 





/*************************************************************************
*** Echelonize a 24 times 24 times matrices mod 3
*************************************************************************/

// %%WITH N_COL = 3


/// @cond DO_NOT_DOCUMENT 

/** @brief Auxiliary function for function ``leech3matrix_echelon``.

   Here ``p_a`` is a submatrix of a matrix ``a`` in  **matrix mod 3**
   encoding  as documented in the header of this file. ``p_a`` should
   point to a row ``i`` of matrix ``a`` and ``p_end`` should point
   behind the last row of matrix ``a``. Then we pivot over the
   given ``column``.

   This means that we look for the first row ``k`` with a nonzero
   entry in that column. Then we perform row operations with that row
   in order to zero all aother rows >= i of the matrix. Finally, we
   exchange row ``i`` with row ``k``.
*/
static inline uint32_t pivot3(uint64_t *p_a, uint64_t *p_end, uint32_t column)
{
     
    uint64_t sign_pivot, sign, tmp;
    uint64_t  *p_pivot, *p_row;
    uint_fast32_t col_ofs = column >> 4, col_sh = (column & 15) << 2;

    for (p_pivot = p_a; p_pivot < p_end; p_pivot += 3) {
        sign_pivot = (p_pivot[col_ofs] >> col_sh) + 1;
        if (sign_pivot & 2) goto pivot_found;
    }
    return 0;

pivot_found:
    ++sign_pivot;
    for (p_row = p_pivot + 3; p_row < p_end; p_row += 3) {
        sign =  (p_row[col_ofs] >> col_sh) + 1;
        if (sign & 2) {
            sign = (0 - ((sign + sign_pivot) & ONE)) & NEG_MASK_MOD3;
            p_row[0] += (p_pivot[0] ^ sign);
            REDUCE_MOD3(p_row[0]);
            p_row[1] += (p_pivot[1] ^ sign);
            REDUCE_MOD3(p_row[1]);
            p_row[2] += (p_pivot[2] ^ sign);
            REDUCE_MOD3(p_row[2]);
        }
    }

    tmp = p_a[0]; p_a[0] = p_pivot[0]; p_pivot[0] = tmp;
    tmp = p_a[1]; p_a[1] = p_pivot[1]; p_pivot[1] = tmp;
    tmp = p_a[2]; p_a[2] = p_pivot[2]; p_pivot[2] = tmp;
    return 3;
}


/// @endcond

/** @brief Echelonize a matrix of integers mod 3.

   Here ``a`` is a matrix in  **matrix mod 3** encoding as documented
   in the header of this file. That matrix is transformed to row
   echelon form. We echelonize columns 0,...,23 of matrix ``a`` in
   that order. The matrix is not converted to reduced echelon form.
*/

// %%EXPORT px
CLIFFORD12_API
void leech3matrix_echelon(uint64_t *a)
{
    uint64_t *p_a = a, *p_end = a +  72;
    uint_fast32_t col;
    for (col = 0; col < 24; ++col) {
        p_a += pivot3(p_a, p_end, col);
    }
}






/*************************************************************************
*** Compress a 24 times 24 times matrices mod 3
*************************************************************************/


/** @brief compress a matrix in *matrix mod 3*  encoding

   Let ``a`` be an 24 times 48 matrix in *matrix mod 3*  encoding.
   We consider ``a`` as a pair of two matrices ``Ah, Al``,
   with``Al`` in columns 0,...,23 and ``Ah`` in columns 24,...,47
   of ``a``.

   We store ``Ah`` in the entries of ``v`` with odd indices
   and ``Al`` in the entries of ``a`` with even indices.
   Here column ``j`` of a row of ``Ah`` or ``Al`` is reduced
   modulo 3 (so it has value 0, 1, or 2) and that value
   is stored in bits ``2*j+1`` and ``2*j`` of the corresponding
   entry of ``v``.

   The overlapping ``v == a`` is legal; any other kind of
   overlappig between ``v`` and ``a`` is illegal.

*/
// %%EXPORT px
CLIFFORD12_API
void leech3matrix_compress(uint64_t *a, uint64_t *v)
{
    uint64_t v0, v1, tmp;
    uint_fast32_t i, j = 0;

    for (i = 0; i < 48; i += 2) {
        v0 = a[j]; tmp = a[j+1]; v1 = a[j+2];
        COMPRESS_15_3(v0);
        COMPRESS_15_3(tmp);
        COMPRESS_15_3(v1);
        v0 += (tmp & 0xffff) << 32;
        v1 = (v1 << 16) + (tmp >> 16);
        REDUCE_FINAL_MOD3(v0, tmp);
        REDUCE_FINAL_MOD3(v1, tmp);
        v[i] = v0; v[i+1] = v1;
        j += 3;
    }
}



/*************************************************************************
*** subtract diagonal matrix from a 24 times 24 times matrices mod 3
*************************************************************************/

/** @brief Subtract diagonal matrix from matrix in *matrix mod 3*  encoding.

   Let ``a`` be an 24 times 48 matrix in *matrix mod 3*  encoding.
   
   We subtract a diagonal matrix from ``a``. More precisely, we 
   subtract the integer ``diag`` from all entries ``a[i, i+offset]``,
   for ``i = 0,...,23``.
*/
// %%EXPORT px
CLIFFORD12_API
void leech3matrix_sub_diag(uint64_t *a, uint64_t diag, uint32_t offset)
{
    uint_fast32_t col_ofs, col_sh;
    uint64_t *p_a, *p_end = a + 24 * 3;
    diag %= 3;
    if (diag == 0) return;
    diag = 3ULL - diag;
    for (p_a = a; p_a < p_end; p_a += 3) {
        col_ofs = offset >> 4, col_sh = (offset & 15) << 2;
        p_a[col_ofs] += diag << col_sh;
        REDUCE_MOD3(p_a[col_ofs]);
        ++offset;
    }
}



/*************************************************************************
*** Rank and kernel of a 24 times 24 times matrices mod 3
*************************************************************************/

/** @brief Rank and kernel of a ``24 times 24`` matrix modulo 3

   Let ``r`` be the rank of the ``24 times 24`` matrix ``b = a - d * 1``.
   Here the entries of that matrix are taken modulo 3, ``d`` is an 
   integer, and ``1`` is the unit matrix. 
   Input ``a`` is a 24 times 24 matrix in  **matrix mod 3** encoding 
   as documented in the header of this file. 

   Let ``r`` be the rank of matrix ``b`` with entries taken modulo 3.
   If matrix ``b`` has rank 23 then its kernel is one dimensional. In 
   that case the kernel contains two nonzero vectors ``+-w``, and we
   define ``w`` to be one of these vectors. Otherwise we let ``w`` be 
   the zero vector.

   The function returns the value ``(r << 48) + w``, with ``w`` the
   vector defined above given in *Leech lattice mod 3 encoding* as 
   described in *The C interface of the mmgroup project*. 

   Input ``a`` is destroyed.
*/
// %%EXPORT px
CLIFFORD12_API
uint64_t leech3matrix_rank(uint64_t *a, uint32_t d)
{
    uint64_t i;

    // We now consider a as a pair of two matrices Ah, Al, with
    // Al in columns 0,...,23 and Ah in columns 24,...,47.
    // Store b = b - d * 1 in Al and the unit matrix 1 in Ah.
    for (i = 0; i < 72; i += 3) {
        a[i+1] &= 0xffffffffULL;
        a[i+2] = 0;
    }
    leech3matrix_sub_diag(a, d, 0);
    leech3matrix_sub_diag(a, 2, 24);
    // Echelonize the pair (Ah, Al) simultaneously, so that 
    // Al is in (non-reduced) echelon form. Then the ``24-r``
    // rows with highest indices of Ah contain the kernel of A'.
    leech3matrix_echelon(a);
    // Store Ah in the entries of ``a`` with odd indices and
    // Al in the entries of ``a`` with even indices.
    leech3matrix_compress(a, a);
    // Compute the rank of Al in i
    for (i = 2 * 24; i > 0; i -= 2) if (a[i-2]) goto rank_computed;
    i = 0;
  rank_computed:
    i >>= 1; 
    // Return i << 48 if i != 23
    if (i != 23) return i << 48;
    // Return (24 << 48) + w  if  i == 23. Here w is row 23 of 
    // matrix Ah converted to *Leech lattice mod 3 encoding*.
    return (23ULL << 48ULL) + xsp2co1_from_vect_mod3(a[2*23 + 1]);
}




// %%END WITH   # N_COL = 3


/*************************************************************************
*** Functions for bit matrices
*************************************************************************/







/**
 @brief Add an equation to a system of linear bit equations
 
 The idea behind this function is that an external process generates
 rows of a bit matrix with ``ncols`` columns, with ``0 < ncols <= 32``.
 This function checks such a row ``a`` and accepts it, if it linearly
 independent of all previously accepted rows. Thus at most ``ncols``
 rows can be accepted. The ``nrows`` already accepted rows are  stored
 in the array ``m``. The function returns  ``1`` if row ``a`` is
 accepted and ``0``  otherwise. A negative return value indicates
 an error. The size of the array ``m`` should be at least ``ncols``.
 
 Let ``A`` be the ``ncols`` times ``ncols`` matrix of all accepted
 rows ``a[i]``, ``0 <= i < ncols``; and let  ``I`` be the ``ncols``
 time ``ncols`` unit matrix. We left multiply ``A`` with a
 matrix ``T`` such that ``T * A = I``. Thus ``T = A**(-1)``.
 Technically, we perform row operations on the matrix ``A[:nrows]``
 containing the first ``nrows`` lines already accepted, such
 that ``T * A[:rnows]`` is in **reduced echelon form**. We also
 perform the same row operations on the unit matrix to obtain ``T``.
 We store ``T[:rnows]`` in columns ``0,...,ncols-1`` of matrix ``M``
 and ``T*A[:rnows]`` in columns ``ncols,...,2*ncols-1`` of
 matrix ``M``.
 
 One may use function ``leech2matrix_solve_eqn`` for solving a
 system of linear equations obtained in that way.
*/
// %%EXPORT px
CLIFFORD12_API
int32_t leech2matrix_add_eqn(uint64_t *m, uint32_t nrows, uint32_t ncols, uint64_t a)
{
    // Our general strategy is to keep the matrix ``TA``in the upper
    // columns of ``m`` in reduced echelon form after the insertion  
    // of a vector ``a``. Therefore we apply row operations to ``TA``. 
    // When entring the i-th row, we also enter the i-th row of the
    // unit matrix ``I`` into the matrix stored in the lower ``ncols``
    // columns of ``m``. Then subsequent row operations apply to both,
    // the upper and the lower columns of matrix ``m``.

    uint_fast32_t row, col;       // Counters for rows and columns of ``TA``
    uint_fast32_t a_row = nrows;  // Row where to insert the (pivoted) ``a``
    uint64_t mask = ONE << ncols; // Mask for column ```col`` of ``TA``
    uint64_t a_mask = 0 - ONE;    // Mask for lowest bit of (pivoted) ``a``,
                                  // (-1) means 'no such bit found'
    // Check buffer overflow
    if (ncols > 32 || nrows > ncols) return ERR_QSTATE12_BUFFER_OVFL;
 
    // Shift vector ``a`` into the position for entering it into ``TA``.
    // Store row ``nrows`` of the unit matrix in the lower columns of ``a``.
    a = ((a & ((ONE << ncols) - 1)) << ncols) | (ONE << nrows);
 
    // Run through the columns of ``TA``. If a row of ``TA`` has a 
    // lowest bit in that column then pivot ``a`` with that row.
    // If ``a`` has a lowest bit set in that column (after pivoting)
    // then set ``a_mask`` appropriately to indicate that column.
    for (col = row = 0; col < ncols && row < nrows; ++col) {
        if (m[row] & mask) {
            a ^= (a & mask) ? m[row] : 0; 
            ++row;
        } 
        else if (a & mask & a_mask) {
            a_row = row; a_mask = mask;
        }            
        mask <<= 1;        
    }
    // All rows of ``TA`` done. Proceed with remaining columns as above.
    for ( ; col < ncols && a_mask == (0 - ONE); ++col) {
        if (a & mask) a_mask = mask; 
        mask <<= 1;        
    }
    
    // Return 0 if no bit is set in the (pivoted) ``a``.
    if (a_mask == (0 - ONE)) return 0;
    
    // Insert the pivoted ``a`` into the correct row of ``TA``
    for (row = nrows; row > a_row; --row)  m[row] = m[row-1];
    m[a_row] = a;
    
    // Pivot the lower rows of ``TA`` with ``a``.
    for (row = 0; row < a_row; ++row) {
        m[row] ^=  (m[row] & a_mask) ? a : 0;
    }    
    return 1;     
}



/**
 @brief Solve a system of linear bit equations
 
 Let ``A`` be a nonsingular  ``ncols`` times ``ncols`` bit matrix
 stored in the array ``m`` in the special form as described in 
 function ``leech2matrix_add_eqn``.
 
 The function returns the solution ``w`` of the equation
 ``w * A = v``.

 Caution:

 Here ``m`` is of of type ``uint32_t *``, but the corresponding
 parameter in function ``leech2matrix_add_eqn`` is of type
 ``uint64_t *``. This simplifies the use of this function in
 most pplications. 
  
*/
// %%EXPORT px
CLIFFORD12_API
uint32_t leech2matrix_solve_eqn(uint32_t *m, uint32_t ncols, uint64_t v)
{
    uint_fast32_t row = 0;
    uint64_t mask = ONE, w = 0;
    
    for (row = 0; row < ncols; ++row) {
        w ^=  (v & mask) ? m[row] : 0; 
        mask <<= 1;
    }
    return  (uint32_t)(w & (mask - 1));     
}






/*************************************************************************
** Basis of a subspace of the Leech lattice modulo 2
*************************************************************************/

/// @cond DO_NOT_DOCUMENT 

/** @brief  Workhorse for function ``leech2_matrix_basis``

  This function does the job of function ``leech2_matrix_basis``
  except for the final echelonization of the basis.
*/
static inline uint32_t 
get_leech2_basis(uint32_t *v2, uint32_t n, uint64_t *basis, uint32_t d)
{
    uint32_t i, j, w, k = 0;
    uint8_t pos[24];

    // Compute a basis of the space generated by  v2[0],...,v2[n-1]  in 
    // basis[0],...,basis[k-1]. Store index of the least significant
    // bit of the i-th basis vector in pos[i].
    // Put mask[i] = 1 << pos[i].
    // Set bit m in 'bitmask' if m is an entry in array pos[0,...,k-1].
    for (i = 0; i < n; ++i) {
        w = v2[i] & 0xffffffUL;
        for (j = 0; j < k; ++j) {
             w ^= (0 - ((w >> pos[j]) & 1UL)) & basis[j];
        }
        if (w == 0) continue;
        j = w & (0 - w); 
        pos[k] = (uint8_t)(mat24_def_lsbit24_pwr2(j));
        basis[k] = w;
        if (++k >= d) break;
    }
    return k;    
}


/// @endcond 


/** @brief  Subspace generated by vectors of Leech lattice modulo 2

  Compute a basis of the subspace of the Leech lattice modulo 2
  generated by the vectors ``v2[0],...,v2[n-1]``.

  The function returns the dimension ``k`` of that subspace and
  computes a basis of that subspace in ``basis[i], 0 <= i < k``.

  Here ``d`` must be an upper bound for the dimension ``k``.
  If ``k`` is unknown, one should put ``d = 24``.

  Bits 23,...,0  of the output matrix are echelonized in a special
  way.  Here the columns are processed in the order:

  11, 22, 21, ..., 13, 12, 10, 9, ..., 1, 0, 23.

  One of the advantages of this echelonization is that the
  vector \f$\Omega\f$ (encoded as 0x800000) will occur in the
  basis if it is in the subspace, and that there are many even
  vectors (i.e. vectors orthogonal to \f$\Omega\f$) in the basis.
*/
// %%EXPORT px
CLIFFORD12_API
uint32_t leech2_matrix_basis(uint32_t *v2, uint32_t n, uint64_t *basis, uint32_t d)
{
    uint32_t dim = get_leech2_basis(v2, n, basis, d);

    // Echelonize the final result as documented above.
    bitmatrix64_xch_bits(basis, dim, 12, 0x800);
    bitmatrix64_rot_bits(basis, dim, 1, 12,0);
    bitmatrix64_echelon_h(basis, dim, 24, 24);
    bitmatrix64_rot_bits(basis, dim, 11, 12,0);
    bitmatrix64_xch_bits(basis, dim, 12, 0x800);
    return dim;    
}



/*************************************************************************
*** Orthogonal complement in Leech lattice mod 2
*************************************************************************/


/**
   @brief Compute standard orthogonal complement in Leech lattice mod 2

   Let \f$A = a_0\ldots, a_{k-1}\f$ be a matrix of \f$k\f$ vectors
   in the Leech lattice mod 2 stored in the array ``a``. The function
   returns a basis  \f$B = b_0\ldots, b_{23}\f$ of the Leech lattice
   mod 2 in the array ``b``, and it returns a number \f$m\f$ such that
   the vectors \f$b_m\ldots, b_{23}\f$ are a basis of the orthogonal
   complement of the space generated by the row vectors of \f$A\f$.

   If the vectors  \f$(a_0\ldots, a_{k-1})\f$ are linear independent
   then the function returns \f$m = k\f$, and vector \f$b_i, i < k\f$
   is orthogonal to all vectors  \f$a_j\f$ with \f$j \neq i\f$.

   The basis \f$B = b_0\ldots, b_{23}\f$ is stored in the array ``b``.

   We require \f$k \leq 24\f$. The function returns \f$m \geq 0\f$
   in case of success a negative value in case of failure.
*/
// %%EXPORT px
CLIFFORD12_API
int32_t leech2_matrix_orthogonal(uint64_t *a, uint64_t *b, uint32_t k)
{
   uint64_t x;
   uint32_t i, m;

   if (k > 24) return ERR_QSTATE12_PARAM;

   // We store a 24 times k matrix Bh in columns 24,...,24+k-1 of 
   // the array b and a 24 times 24 matrix Bl in columns 0,...,23
   // of the array b.

   // Put Bl = A^T (with A^T the transposed matrix of A)
   bitmatrix64_t(a, k, 24, b);

   // Let Q be the scalar product matrix for the Leech lattice mod 2.
   // Put Bh = Q * A^T, i.e. exchange row i of A^T with row i+12.
   for (i = 0; i < 12; ++i) {
       x = b[i]; b[i] = b[i+12] << 24; b[i+12] = x << 24;
   }

   // Store the unit matrix in Bl 
   for (i = 0; i < 24; ++i)  b[i] |= 1ULL << i;

   // Echelonize Bh. This corresponds to left multiplication with a
   // nonsingular matrix B. W also multiply Bl (containing the unit
   // matrix) with B. So we have  Bl = B, Bh = B * Q * A^T,  and Bh 
   // is echelonized, containing m nonzero rows  and 24 - m zero rows. 
   // Thus B is the result, with the orthogonal complement of A in 
   // rows m,...,23 of B.  
   //
   // Remark: If the rows of A are linear independent then the upper
   //         k rows of  B * Q * A^T  form a unit matrix.
   m = bitmatrix64_echelon_l(b, 24, 24, k);

   // Output B = Bl and return m
   for (i = 0; i < 24; ++i) b[i] &= 0xffffffUL;
   return m;
}


/*************************************************************************
** Radical of a subspace of the Leech lattice modulo 2
*************************************************************************/

/** @brief Radical of subspace generated by vectors of Leech lattice mod 2

  Compute the radical of the subspace of the Leech lattice modulo 2
  generated by the vectors ``v2[0],...,v2[n-1]``. Here the radical
  is the intersection of the space generated by ``v2[0],...,v2[n-1]``
  with the orthogonal complement of that space.

  Input parameters ``v2, n,`` and ``d`` are as in
  function ``leech2_matrix_basis``. A basis of the radical
  of the space is computed in ``basis``. The basis is echelonized
  as in function ``leech2_matrix_basis``. The function returns the
  dimension ``k`` of radical spanned by that basis.
*/
// %%EXPORT px
CLIFFORD12_API
uint32_t leech2_matrix_radical(uint32_t *v2, uint32_t n, uint64_t *basis, uint32_t d)
{
    uint64_t span[24], ortho[24];
    int_fast32_t dim, i, res;

    dim = get_leech2_basis(v2, n, span, d);
    if (dim < 0) return dim;
    leech2_matrix_orthogonal(span, ortho, dim);
    bitmatrix64_echelon_h(span, dim, 24, 24);
    bitmatrix64_echelon_h(ortho + dim, 24 - dim, 24, 24);
    res = bitmatrix64_cap_h(span, ortho + dim, dim, 24 - dim, 24, 24);
    if (res < 0) return res;
    for (i = 0; i < res; ++i) basis[i] = span[i + dim - res];

    // Echelonize the final result as documented above.
    bitmatrix64_xch_bits(basis, res, 12, 0x800);
    bitmatrix64_rot_bits(basis, res, 1, 12,0);
    bitmatrix64_echelon_h(basis, res, 24, 24);
    bitmatrix64_rot_bits(basis, res, 11, 12,0);
    bitmatrix64_xch_bits(basis, res, 12, 0x800);
    return res;
}

/*************************************************************************
** List vectors in a subspace of the Leech lattice modulo 2
*************************************************************************/


/** @brief List vectors in a subspace of the Leech lattice modulo 2

  The function computes all ``2**dim`` vectors of the subspace ``V`` 
  of the Leech lattice modulo 2 given by the basis

  ``basis[0], ..., basis[dim - 1]``  .

  These vectors are written into the array ``v2``. The function
*/
// %%EXPORT px
CLIFFORD12_API
uint32_t leech2_matrix_expand(uint64_t *basis, uint32_t dim, uint32_t *v2)
{
    int_fast32_t i, j, len = 1;
    v2[0] = 0;
    for (i = dim - 1; i >= 0; --i) {
         uint32_t w = (uint32_t)(basis[i]) & 0xffffff;
         for (j = 0; j < len; ++j) v2[len + j] = w ^ v2[j];
         len += len;
    } 
    return len;
}

/*************************************************************************
*** End of of C code
*************************************************************************/


//  %%GEN h
//  %%GEN c



// %%GEN ch
#ifdef __cplusplus
}
#endif




