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

/** @file gen_leech_type.c
The functions in file ``gen_leech_type.c`` implement operations 
for detecting the type of a vector in the Leech lattice modulo 2. 

We use the terminology defined in the 
document *The C interface of the mmgroup project*, 
section *Description of the mmgroup.generators extension*.
*/


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

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




// %%EXPORT_KWD MAT24_API


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


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



/*************************************************************************
*** Auxiliary functions for computing subtype of vector
*************************************************************************/

/// @cond DO_NOT_DOCUMENT 

/**
  @brief Return suboctad type.

  Let ``octad`` be an octad, i.e. a bit vector of length 8. Let
  w = 1 (mod 2) if ``octad`` denotes an octad and ``w = 0`` 
  if ``octad`` denotes a complemented octad. Let ``coc`` be
  an even cocode vector in cocode representation.

  The function returns 0 in bit 1 of the return value if the 
  cocode word ``coc`` can be written as a subset of the octad,
  and 1 in bit 1 otherwise.

  the function returns ``1 + w + bit_weight(coc)/2`` in bit 0
  of the return value.

  Then Leech lattice vector ``x_octad + x_coc`` is of subtype 
  0x22 if the return value is zero. Otherwise it is of
  subtype 0x44 (or 0x46) if bit 1 of the return value is 0
  (or 1).
*/
static inline int suboctad_type(
    uint_fast32_t octad, // An octad as a bit vector of length 8
    uint_fast32_t w,     // 1 for an octad, 0 for acomplemented octad
    uint_fast32_t coc    // even cocode vector in cocode representation       
)
{
    uint_fast32_t cw, lsb, syn, cocodev, sub;

    // Let cw be the halved bit weight of coc
    cw = MAT24_SYNDROME_TABLE[coc & 0x7ff] >> 15;
    // Put cocodev = cocode word of v (in vector rep), such 
    // that the cocode word is a suboctad of octad if possible.
    lsb = mat24_def_lsbit24(octad);
    coc ^= MAT24_RECIP_BASIS[lsb];
    syn = MAT24_SYNDROME_TABLE[coc & 0x7ff];
    cocodev = mat24_def_syndrome_from_table(syn) ^ (1UL << lsb);
    // Set sub = 0 iff cocodev is a subset of octad.
    sub = (octad & cocodev) != cocodev;
    return ((~w ^ cw) & 1) + 2 * sub;
}

/// @endcond  


/*************************************************************************
*** Subtype of a vector in the Leech lattice mod 2
*************************************************************************/



/**
  @brief Return subtype of vector in Leech lattice mod 2

  The function returns the subtype of the vector \f$v_2\f$
  in the Leech lattice modulo 2 as a BCD-coded two-digit
  integer. \f$v_2\f$ must be given in Leech lattice encoding.
  
  The subtype of a vector in the Leech lattice mod 2 is 
  defined in **The mmgroup guide for developers**, 
  section **Computations in the Leech lattice modulo 2**.
*/
// %%EXPORT px
MAT24_API
uint32_t gen_leech2_subtype(uint64_t v2)
// Return ``0x10 * type(v2) + subtype(v2)`` for a vector ``x``
// in the Leech lattice modulo ``2``.
// The type of a vector is half the length of the shortest 
// representative of a vector in the Leech lattice.
// The subtype decsribes the double coset of the vector in
// in ``N_x \ Co_1 / N_x``, where ``Co``_1 is the automorphism 
// group of the Leech lattice modulo ``2``, and ``N_x`` is the 
// automorphism group of a vector ``(2,...,2)`` in the standard 
// basis of the Leech lattice modulo ``N_x`` has structure 
// ``2^11. Mat_24``, with ``Mat_24`` the Mathieu group operating
// on 24 elements.
//
// In :cite`:`Con85` a vector in the Leech lattice is
// denotes by ``x_d * x_delta``, where ``d`` is an element of
// the Golay code and ``delta`` is an element of it cocode. 
// Subtypes can be described as follows:
//
// 0: The set contains an element with ``delta = 0``
// 1: ``delta`` has weight ``1`` for all elements in the set.
// 2: ``d`` or its complement is an octad and ``delta`` is
//     even and contained in that octad.
// 3: ``delta`` has weight ``1`` for all elements in the set.  
// 4: ``d`` or its complement is an octad and ``delta`` is
//     even and not contained in that octad.
// 6: ``d`` has weight 12
// 8: The singleton containing ``(2,...,2)`` 
//
// Valid combinations of type and subtype (hex) are
//
// 00,   20, 21, 22,   31, 33, 34, 36,  
// 40, 42, 43, 44, 46, 48.
{
    static uint8_t tab_odd[4] = {
        0x21, 0x31, 0x43, 0x33
    };
    static uint8_t tab_even_scalar1[7] = {
        0xff, 0xff, 0x34, 0x36, 0x34, 0xff, 0xff
    };
    uint_fast32_t theta, coc, scalar, syn, cw, w, octad;

    theta = MAT24_THETA_TABLE[(v2 >> 12) & 0x7ff]; 
    // put syn = syndrome table[cocode word]
    coc = (v2 ^ theta) & 0xfff;
    // Put scalar = scalar product (code, cocode)
    scalar = (v2 >> 12) &  v2 & 0xfff;
    mat24_def_parity12(scalar);

    syn =  MAT24_SYNDROME_TABLE[coc & 0x7ff];

    
    // Deal with odd cocode first
    if (v2 & 0x800) {
        // Let cw be the weight of the cocode word
        cw =  3 - ((((syn & 0x7fff) + 0x2000) >> 15) << 1);
        return tab_odd[cw-1+scalar]; 
    }

    // Put w = weight(Golay code word of v2) / 4
    w = 0 - ((v2 >> 23) & 1);
    w = (((theta >> 12) & 7) ^ w) + (w & 7);  

    // Let cw be the weight of the cocode word (modulo 4)
    cw = (syn >> 15) << 1; 


    // Deal with even cocode and scalar == 1
    if (scalar) return tab_even_scalar1[w];
   
    switch (w) {
        case 6:
            if (coc == 0) return 0x48;
        case 0: 
            // Compute the exact cocode weight in cw
            cw = (4 - cw) & ((0UL - coc) >> 16);
            return cw << 4;
        case 3:
            return 0x46;
        case 4:
            // Add 1....1 to bit vector x (in vector rep)
            v2 ^= 0x800000; 
        default:   // This must be case 2:
            // Compute subtype with function suboctad_type()
            octad = mat24_def_gcode_to_vect(v2 >> 12); 
            w = suboctad_type(octad, w >> 1, coc);
            return (0x44444222 >> (8*w)) & 0xff;
    }
}



/*************************************************************************
*** Return type of a vector in the Leech lattice mod 2
*************************************************************************/

/**
  @brief Return type of a vector in the Leech lattice mod 2

  This function returns the type of the vector \f$v_2\f$ in the Leech 
  lattice modulo 2. That type may be 0, 2, 3, or 4.

  This function is a bit faster than function ``gen_leech2_subtype()``.
  
*/
// %%EXPORT px
MAT24_API
uint32_t gen_leech2_type(uint64_t v2)
{
    uint_fast32_t theta, syn, scalar, w, coc, octad;

    // Return 3 if scalar product <code, cocode> is odd
    scalar = (uint32_t)((v2 >> 12) &  v2);
    mat24_def_parity12(scalar);
    if (scalar) return 3;

    // Deal with odd cocode words
    if (v2 & 0x800) {   // Deal with odd cocode words
         // Let syn be the syndrome table entry for the cocode part
         theta = MAT24_THETA_TABLE[(v2 >> 12) & 0x7ff];
         syn = MAT24_SYNDROME_TABLE[(theta ^ v2) & 0x7ff];
         // Put w = 0x400 if syn encodes a cocode word of length 1;
         // put w = 0 if syn encodes a cocode word of length 3.
         w = ((syn & 0x3ff) + 0x100) & 0x400;
         // Return 4 if w == 0 and 2 otherwise
         return 4 - (w >> 9);
    }

    // Deal with Golay code word 0 (or Omega)
    if ((v2 & 0x7ff800L) == 0) {
         // The zero vector has type 0
         if ((v2 & 0xffffffUL) == 0) return 0;
         // Let syn be the syndrome table entry for the cocode part;
         // then bit 15 of syn is the halved cocode weight (mod 2).
         syn = MAT24_SYNDROME_TABLE[v2 & 0x7ff];
         // Return 4 if syn encodes a cocode word of length 0 or 4
         // and 2 otherwise
         return 4 - ((syn >> 14) & 2); 
    }

    theta = MAT24_THETA_TABLE[(v2 >> 12) & 0x7ff];

    // Here (theta >> 12) & 7 is the bit weight of 
    // v2 + Omega * b23, where b23 is bit 23 of v2.
    // If bit 12 of theta is odd then v2 is a dodecad
    // and then v2 is of type 4.
    if (theta & 0x1000) return 4;
    // Now v2 is a (possibly complemented) octad.
    // Put w = 1 if v2 is an octad and w = 0 otherwise.
    w = ((theta >> 13) ^ (v2 >> 23)) & 1;
    // XOR v2 with Omega if it has weight 16
    v2 ^= (1 - w) << 23;
    // Let coc be the cocode part of v2 (this is even)
    coc = (v2 ^ theta) & 0x7ff;
    // Compute subtype with function suboctad_type() 
    // return 0 if result of that function 0 and 1 otherwise
    octad = mat24_def_gcode_to_vect(v2 >> 12); 
    return suboctad_type(octad, w, coc) ? 4 : 2;
}

/*************************************************************************
*** Subtype of a type-2 vector in the Leech lattice mod 2
*************************************************************************/


/**
  @brief Compute subtype if vector in Leech lattice mod 2 is of type 2

  This function returns the subtype of the vector \f$v_2\f$ in the 
  Leech lattice modulo 2 if \f$v_2\f$ is of type 2 and 0 otherwise.

  It is faster than function ``gen_leech2_type()``.
  
*/
// %%EXPORT px
MAT24_API
uint32_t gen_leech2_type2(uint64_t v2)
{
    uint_fast32_t theta, syn, scalar, w, coc, octad;
    // Deal with odd cocode words
    if (v2 & 0x800) {   // Deal with odd cocode words
         // Let syn be the syndrome table entry for the cocode part
         theta = MAT24_THETA_TABLE[(v2 >> 12) & 0x7ff];
         syn = MAT24_SYNDROME_TABLE[(theta ^ v2) & 0x7ff];
         // Return 0 if syn does not encode a cocode word of length 1
         if ((syn & 0x3ff) < (24 << 5)) return 0;
         // Put scalar = scalar product <code, cocode> + 1   (mod 2)
         scalar = (v2 >> 12) &  v2 & 0xfff;
         scalar ^= scalar >> 6;
         scalar ^= scalar >> 3;
         scalar = (0x69 >> (scalar & 7)) & 1;
         // Return type 0x21 if scalar product is 0, and 0 otherwise
         return 0x21 & (0 - scalar);
    }
    // Deal with Golay code word 0
    if ((v2 & 0x7ff000L) == 0) {
         // Let syn be the syndrome table entry for the cocode part 
         syn = MAT24_SYNDROME_TABLE[v2 & 0x7ff];
         // Return 0x20 if syn encodes a cocode word of length 2
         // and 0 otherwise
         return 0x20 & (0 - ((syn >> 15) & 1));
    }

    theta = MAT24_THETA_TABLE[(v2 >> 12) & 0x7ff];

    // Here (theta >> 12) & 7 is the bit weight of 
    // v2 + Omega * b23, where b23 is bit 23 of v2.
    // If bit 12 of theta is odd then v2 is a dodecad
    // and hence never short.
    if (theta & 0x1000) return 0;
    // Now v2 is a (possibly complemented) octad.
    // Put w = 1 if v2 is an octad and w = 0 otherwise.
    w = ((theta >> 13) ^ (v2 >> 23)) & 1;
    // XOR v2 with Omega if it has weight 16
    v2 ^= (1 - w) << 23;
    // Let coc be the cocode part of v2 (this is even)
    coc = (v2 ^ theta) & 0x7ff;
    // Compute subtype with function suboctad_type() 
    octad = mat24_def_gcode_to_vect(v2 >> 12); 
    return suboctad_type(octad, w, coc) ? 0 : 0x22;
}



/// @cond DO_NOT_DOCUMENT 
// In the following procedure we'll store 1 << LSTEPS vectors for speed up
#define LSTEPS 6
/// @endcond  


/**
  @brief Count type-2 vectors in an affine subspace of the Leech lattice mod 2

  This function returns the number of type-2 vectors in an affine 
  subspace \f$V\f$  of the Leech lattice mod 2. Subspace \f$V\f$ is
  defined by an array \f$a\f$ of length \f$n\f$ of bit vectors. 
  If \f$a_1,\ldots,a_{n-1}\f$ are linear independent then \f$V\f$ is
  given by:

  \f$V = \{a_0 + \sum_{i=1}^{n-1} \lambda_i a_i \mid \lambda_i=0,1\}\f$.
  
*/
// %%EXPORT px
MAT24_API
uint32_t gen_leech2_count_type2(uint32_t *a, uint32_t n)
{
    uint32_t b[1 << LSTEPS];
    uint_fast32_t count, i, j, l, n0, bigsteps, v;
    
    if (n == 0) return 0;
    b[0] = a[0];
    ++a; --n;
    n0 = n  < LSTEPS ? n : LSTEPS;
    bigsteps = 1 << (n - n0);
    l = 1;  
    for (i = 0; i < n0; ++i) {
        for (j = 0; j < l; ++j) b[l + j] = b[j] ^ a[i];
        l += l;
    }
    a += n0;
    count = v = 0;
    for (i = 1; ; ++i) {
         for (j = 0; j < l; ++j) {
             count += gen_leech2_type2(v ^ b[j]) > 0;
         }
         if (i == bigsteps) break;
         v ^= a[mat24_def_lsbit24(i)];
    }
    return count;
}


#undef LSTEPS

/*************************************************************************
*** Auxiliary functions for reducing a certain type-2 vector  mod 2
*************************************************************************/

/**
  @brief Auxiliary function for function gen_leech2_reduce_type4
  
  The function returns the subtype of a vector \f$v\f$ of type 2 in
  the Leech lattice modulo 2, provided that \f$v + \beta\f$ is of
  type 4. It returns 0 in the special case \f$v = \beta + \Omega\f$
  and a negative value if  \f$v\f$ is not of type 2 or \f$v + \beta\f$
  is not of type 4.

  It is used for rotating a type-4 vector \f$v\f$ which is orthogonal
  to \f$\beta\f$ (in the real Leech lattice) into the \f$v + \Omega\f$.
  That rotation will fix the special short vector \f$\beta\f$.
*/
// %%EXPORT px
MAT24_API
int32_t gen_leech2_start_type24(uint32_t v)
{
    uint_fast32_t vtype, theta, syn, w, coc, octad;

    // Return -1 if the scalar product of v and \beta is -1
    if (v & 0x200000) return -1;
    switch (vtype = gen_leech2_type2(v)) {
        case 0x21:
            // Put cocode vector index into variable 'syn'
            theta = MAT24_THETA_TABLE[(v >> 12) & 0x7ff];
            syn = MAT24_SYNDROME_TABLE[(theta ^ v) & 0x7ff];
            // Return 0 if that index is 2 or 3, and 0x21 otherwise
            return (syn & 0x1e) == 2 ? -1 : 0x21;
        case 0x20:
            // Return -1 (or 0) if v is \beta (or \beta + \Omega)
            if ((v & 0x7fffff) == 0x200)
                return v & 0x800000 ? 0 : -1;
            // Put weight of cocode vector of v + \beta into 
            // variable 'syn'
            theta = MAT24_THETA_TABLE[(v >> 12) & 0x7ff];
            syn = MAT24_SYNDROME_TABLE[(theta ^ v ^ 0x200) & 0x7ff];
            // Return -1 if weight is 2 and vtype otherwise
            return syn & 0x8000 ? -1 : vtype;
        case 0x22:
            // Now v is a (possibly complemented) octad.
            // Put w = 1 if v is an octad and w = 0 otherwise.
            theta = MAT24_THETA_TABLE[(v >> 12) & 0x7ff];
            w = ((theta >> 13) ^ (v >> 23)) & 1;
            // XOR v with Omega if it has weight 16
            v ^= (1 - w) << 23;
            // Let coc be the cocode part of v ^ \beta (this is even)
            coc = (v ^ theta ^ 0x200) & 0x7ff;
            // Compute subtype with function suboctad_type() 
            octad = mat24_def_gcode_to_vect(v >> 12); 
            return suboctad_type(octad, w, coc) ? 0x22 : -1;
        default:
            // Return -1 if v s not of type 2.
            return -1;
    }
}


/*************************************************************************
*** Auxiliary functions for reducing a type-4 vector  mod 2
*************************************************************************/

/**
  @brief Auxiliary function for function gen_leech2_reduce_type4
  

  The function returns the subtype of a vector \f$v\f$ of type 4 in
  the Leech lattice modulo 2. Parameter \f$v\f$ must a vector of
  type 4 in Leech lattice encoding. The function returns the subtype
  of \f$v\f$ that will be used for reduction in
  function ``gen_leech2_reduce_type4``.

  This function takes care of the special vectors \f$\Omega\f$
  and \f$\beta\f$ the Leech lattice modulo 2.

  It is used for rotating a type-4 vector \f$v\f$ into 
  \f$\Omega\f$. If this is possible, that rotation will fix the
  special short vector \f$\beta\f$.

  Therefore the function returns 0 in case \f$v = \Omega\f$. It returns 
  the subtype of  \f$v + \beta\f$ if \f$\beta\f$ and \f$v + \beta\f$
  are of type 2 and orthogonal in the real Leech lattice.

  The function returns a negative value if \f$v\f$ is not of type 4.
*/
// %%EXPORT px
MAT24_API
int32_t gen_leech2_start_type4(uint32_t v)
{
    uint_fast32_t syn, scalar, theta, w, octad, coc, sub;

    v &= 0xffffff;
    if ((v & 0x7ff800) == 0) {
        // Then v or v + Omega is an even cocode element.
        // Return 0 if v == Omega and -1 if v ==  0.
        if ((v & 0x7fffff) == 0) {
            return v & 0x800000 ? 0 : -1;
        }
        // Let w be the cocode weight. Return -2 if w == 2.
        syn = MAT24_SYNDROME_TABLE[coc = v & 0x7ff];
        if (syn & 0x8000)  return -2;
        // Here v has type 4. Let beta be the standard type-2 vector.
        // Return 0x20 if v ^ beta has type 2 and 0x40 otherwise.
        syn = MAT24_SYNDROME_TABLE[coc ^ 0x200];
        return (syn & 0x8000)  ? 0x20 : 0x40;
    }
    // Compute type of v (mod 2) in scalar; return -3 if this is odd
    scalar = (v >> 12) &  v & 0xfff;
    mat24_def_parity12(scalar);
    if (scalar) return -3;

    // Let syn be the syndrome table entry for the cocode part
    theta = MAT24_THETA_TABLE[(v >> 12) & 0x7ff];
    syn = MAT24_SYNDROME_TABLE[coc = (theta ^ v) & 0x7ff];
 
    if (v & 0x800) {
        // The v has an odd cocode element, encoded in 'syn'.
        // Return -2 if syn encodes a cocode word of length 1,
        // since then v is of type 2.
        if ((syn & 0x3ff) >= (24 << 5)) return -2;
        // Here v is of type 4. 
        // Get syndrome table entry of v ^ beta
        syn = MAT24_SYNDROME_TABLE[coc ^ 0x200];
        // Return 0x21 if v ^ beta is of type 2 and 0x43 otherwise.
        if (((syn & 0x3ff) >= (24 << 5)) && (v & 0x200000) == 0)
            return 0x21;
        return 0x43;
    }

    // Here (theta >> 12) & 7 is the bit weight of  v + Omega * b23, 
    // where b23 is bit 23 of v. If bit 12 of theta is odd then the
    // Golay code part of v is a dodecad, and v has subtype 0x46.
    if (theta & 0x1000) return 0x46;

    // Put w = 1 if v is an octad and w = 0 otherwise.
    w = ((theta >> 13) ^ (v >> 23)) & 1;
    // XOR v with Omega if it has weight 16
    v ^= (1 - w) << 23;
    // Let octad be the Golay code part of v; this is an octad.
    octad = mat24_def_gcode_to_vect(v >> 12); 
    // Let coc be the cocode part of v; this is even.
    coc = (v ^ theta) & 0x7ff;

    sub = suboctad_type(octad, w, coc);
    // Return -2 if v is of type 2
    if (sub == 0) return -2;
    // Otherwise return 0x22 if v + beta is of type 2
    if (suboctad_type(octad, w, coc ^ 0x200) == 0) return 0x22;
    // Otherwise return the subtype of v
    return (0x44444222 >> (8 * sub)) & 0xff;    
}




 



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



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




