コード例 #1
0
def test_cocode():
    print("")
    for i in range(200):
        # Test power map, inveriosn, sign, theta, and conversion to GCode
        n1 = randint(0, 0x1fff)
        p1 = PLoop(n1)
        ccvector = randint(0, 0xffffff)
        coc = mat24.vect_to_cocode(ccvector)
        cclist = [i for i in range(24) if (ccvector >> i) & 1]
        cc1 = Cocode(cclist)
        cc2 = Cocode(coc)
        if i < 1:
            print("\nTesting", GcVector(ccvector), ", cocode =", cc1)
        assert cc1 == cc2
        u = Parity(mat24.scalar_prod(p1.value, cc1.value))
        assert p1 & cc1 == u == cc1 & p1 == u * 1 == u + 0
        par = Parity(randint(0, 1))
        assert cc1 + par == par + cc1 == cc1.value // 0x800 + par
        assert cc1 % 2 == Parity(cc1)
        assert len(cc1) == mat24.cocode_weight(cc1.value)
        if len(cc1) < 4:
            syndrome = mat24.cocode_syndrome(cc1.value)
            assert cc1.syndrome().value == syndrome
            syn_from_list = sum(1 << i
                                for i in GcVector(ccvector).syndrome_list())
            assert syn_from_list == syndrome
        i = randint(0, 23)
        assert cc1.syndrome(i).value == mat24.cocode_syndrome(cc1.value, i)
        syndrome_list = cc1.syndrome(i).bit_list
        assert len(cc1) == len(syndrome_list)
        assert syndrome_list == mat24.cocode_to_bit_list(cc1.value, i)
コード例 #2
0
def ref_gen_leech2_reduce_n(v, verbose=0):
    vtype = gen_leech2_subtype(v)
    subtype = vtype & 0xf

    out = []

    if subtype & 1:
        coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
        syn = mat24.cocode_syndrome(coc)
        src = mat24.vect_to_list(syn, mat24.bw24(syn))
        assert len(src) in [1, 3]
        lst = [1, 2, 3] if subtype == 3 else [0]
        apply_perm(v, src, lst, len(src), out)
        v = gen_leech2_op_atom(v, out[0])
        out.append(0xC0000000 + ((v >> 12) & 0x7ff))
        v = gen_leech2_op_atom(v, out[1])
        out.append(0xB0000000 + ((v >> 13) & 0x800))
    elif subtype == 6:
        gv = (v >> 12) & 0xfff
        vect = mat24.gcode_to_vect(gv)
        src = mat24.vect_to_list(vect, mat24.bw24(vect))
        assert len(src) == 12
        dest = STD_DODECAD
        if (vtype == 0x36):
            coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
            w = mat24.bw24(mat24.cocode_as_subdodecad(coc, gv))
            if w & 2:
                dest = CPL_DODECAD
        pi = mat24.perm_from_dodecads(dest, src)
        out.append(0xA0000000 + mat24.perm_to_m24num(pi))
        op_y_x(v, TABLE_DODECAD, out)
    elif subtype in [2, 4]:
        if vtype == 0x34:
            find_octad_permutation_odd(v, out)
        else:
            find_octad_permutation(v, out)
        op_y_x(v, TABLE_OCTAD, out)
    elif subtype in [0, 8]:
        if ((v & 0x7ff) == 0):
            out.append(0xA0000000)
            out.append(0xC0000000)
            x = 0x800 if v & 0x1800000 == 0x1800000 else 0
            out.append(0x90000000 + x)
        else:
            syn = mat24.cocode_syndrome(v & 0x7ff, 0)
            src = mat24.vect_to_list(syn, mat24.bw24(syn))
            j = mat24.bw24(syn) & 2
            lst, y0 = ([2, 3], 0x200) if j else ([0, 1, 2, 3], 0x400)
            apply_perm(v, src, lst, len(lst), out)
            v = gen_leech2_op_atom(v, out[0])
            y = y0 if v & 0x800000 else 0
            out.append(0xC0000000 + y)
            v = gen_leech2_op_atom(v, out[1])
            x = y0 if v & 0x1000000 else 0
            out.append(0xB0000000 + x)
    else:
        raise ValueError("Bad subtype " + hex(vtype))
    assert len(out) == 3
    return vtype, np.array(out, dtype=np.uint32)
コード例 #3
0
def suboctad_type(octad, w, coc):
    """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 
    (or 1).   
    """
    lsb = mat24.lsbit24(octad)  # ls bit of octad
    syn = mat24.cocode_syndrome(coc, lsb)  # cocode syndrome
    wsub = octad & syn == syn  # wsub = 1 if coc is suboctad
    cw = mat24.cocode_weight(coc) >> 1  # cw = cocode_weight(v) / 2
    return 2 * (1 - wsub) + ((w ^ cw ^ 1) & 1)
コード例 #4
0
ファイル: cocode.py プロジェクト: Martin-Seysen/mmgroup
    def syndrome(self, i=None):
        """Return syndrome of cocode element as a bit vector.

        :param i: ``None`` (default) or an integer ``0 <= i < 24`` 
                  used to select a syndrome.
                 
        :return: Syndrome of a Golay cocode element as a bit
                 vector of type |GcVector|.

        :raise:
           *  ValueError if argument ``i`` is ``None`` and the
              syndrome is not unique.

        Any Golay cocode element has either a unique shortest
        representative of bit weight ``<= 3`` or precisely six
        shortest representatives of bit weight ``4`` which form
        a partition of the underlying set of the code. Such a
        partition is called a *tetrad*. 

        In coding theory, a shortest representative of a cocode 
        element is called a *syndrome*.
             
        If the syndrome is unique, the function returns that 
        syndrome. Otherwise it returns the syndrome containing
        bit at position ``i``.
        """
        if i is None: i = 24
        return GcVector(mat24.cocode_syndrome(self.value, i))
コード例 #5
0
def find_octad_permutation_odd(v, result, verbose=0):
    """ Find a suitable permutation for an octad.

    Similar to function ``find_octad_permutation`` in module
    ``mmgroup.dev.generators.gen_leech_reduce_n``.
    Here ``v, o, c`` are as in that function; but the scalar
    product of ``o`` and ``c`` must be 1. Apart from that
    operation is as in function ``find_octad_permutation``.

    We compute a permutation that maps octad ``o`` to the standard
    octad (0,1,2,3,4,5,6,7). If the cocode part ``c`` of ``v`` is 
    not a suboctad of octad ``o`` then we map (one shortest 
    representative of) ``c`` into the set (0,1,2,3,...7,8). 
    """
    coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
    w = mat24.gcode_weight(v >> 12)
    vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
    src = mat24.vect_to_list(vect, 5)
    if mat24.cocode_weight(coc) == 4:
        sextet = mat24.cocode_to_sextet(coc)
        for i in range(0, 24, 4):
            syn = (1 << sextet[i]) | (1 << sextet[i + 1])
            syn |= (1 << sextet[i + 2]) | (1 << sextet[i + 3])
            special = syn & vect
            if special & (special - 1):
                break
    else:
        syn = mat24.cocode_syndrome(coc, 24)
    src.append(mat24.lsbit24(syn & ~vect))
    return apply_perm(v, src, OCTAD_PLUS, 6, result, verbose)
コード例 #6
0
ファイル: test_reduce.py プロジェクト: Martin-Seysen/mmgroup
def xi_reduce_odd_type4(v, verbose=0):
    r"""Compute power of :math:`\xi` that reduces a vector ``v``

    Let ``v`` be a vector in the Leech lattice mod 2 in Leech
    lattice encoding. We assume that ``v`` is of subtype 0x43.

    We compute an exponent ``e`` such that :math:`\xi^e` maps 
    ``v`` to a vector of subtype 0x42 or 0x44.

    The function returns ``e`` if ``v`` is mapped to type 0x42
    and ``0x100 + e`` if ``v`` is mapped to type 0x44.  A negative
    return value indicates that no such exponent ``e`` exists.
    """
    assert v & 0x800  # Error if cocode part ov v is even
    coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
    # Obtain cocode as table of bit fields of 5 bits
    tab = mat24.syndrome_table(coc & 0x7ff)
    # Check if the syndrome bits are in 3 different MOG columns.
    # We first XOR bit field i with bit field (i-1)(mod 3)
    # and then zero the lowest two bits of each bit field.
    tab ^= ((tab >> 5) & 0x3ff) ^ ((tab & 0x1f) << 10)
    tab &= 0x739c
    # Now all three bit fields are nonzero iff the syndrome bits
    # are in three differnt columns. Next add 32 - 4 to each bit
    # field in order to produce a carry if the field is nonzero.
    tab += 0x739c
    # Next we isolate the three carry bits
    tab &= 0x8420
    # Return -1 if all carry bits are set, i.e all syndrome bits
    # are in different columns.
    if (tab == 0x8420):
        return -1
    # Let scalar be the scalar product of the Golay part of v
    # with the standard tetrad \omega
    scalar = (v >> 22) & 1
    # Exponent for element \xi of G_x0 is 2 - scalar
    exp = 2 - scalar
    if verbose:
        w = gen_leech2_op_atom(v, 0x60000000 + exp)
        print(
            "Reducing c = %s, subtype %s, t=%s, e=%d, to v = %s, subtype %s" %
            (hex(mat24.cocode_syndrome(coc, 0)), hex(gen_leech2_subtype(v)),
             hex(tab), exp, hex(
                 mat24.gcode_to_vect(w >> 12)), hex(gen_leech2_subtype(w))))
    # Return exponent for \xi in the lower 4 bits of the retrun value;
    # Return 0 in bit 8 if all syndrome bits of v are in the same
    # MOG column and 1 in bit 8 otherwise.
    return ((tab != 0) << 8) + exp
コード例 #7
0
ファイル: test_reduce.py プロジェクト: Martin-Seysen/mmgroup
def find_octad_permutation(v, result, verbose=0):
    coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
    w = mat24.gcode_weight(v >> 12)
    vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
    src = mat24.vect_to_list(vect, 5)
    syn = mat24.cocode_syndrome(coc, src[0]) & ~vect
    if syn:
        v5 = (1 << src[0]) | (1 << src[1]) | (1 << src[2])
        v5 |= syn
        special = mat24.syndrome(v5, 24)
        src = src[:3]
        src.append(mat24.lsbit24(special & vect))
        src.append(mat24.lsbit24(vect & ~(special | v5)))
        src.append(mat24.lsbit24(syn))
        syn &= ~(1 << src[-1])
        src.append(mat24.lsbit24(syn))
    return apply_perm(v, src, OCTAD, len(src), result, verbose)
コード例 #8
0
ファイル: cocode.py プロジェクト: Martin-Seysen/mmgroup
    def syndrome_list(self, i=None):
        """Return syndrome of cocode element as list of bit positions.

        :param i: ``None`` (default) or an integer ``0 <= i < 24`` 
                  used to select a syndrome.
                 
        :return: Syndrome of a Golay cocode element as a list
                 of at most four bit positions.

        :raise:
            * ValueError if argument ``i`` is ``None`` and the
              syndrome is not unique.

        The syndrome of the Golay cocode element is calculated
        in the same way as in method **syndrome**. But here
        the result is returned as an ordered list of bit positions
        corresponding to the bits which are set in the syndrome.
        """
        if i is None: i = 24
        syn = mat24.cocode_syndrome(self.value, i)
        return [i for i in range(24) if (syn >> i) & 1]
コード例 #9
0
def leech2_start_type4(v):
    """Return subtype of a Leech lattice frame ``v`` used for reduction

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

    In that function we take care of the special case that ``v + v0``
    is of type 2 for a specific short vector ``v0``. 
    
    A simpler (but slower) implementation of thhis function is:

    If ``v ^ v0`` is of type 2 the return the subtype of ``v ^ v0``.
    Otherwise return the subtype of ``v``.

    The function returns 0 if ``v`` is equal to  ``Omega`` and
    a negative value if ``v`` has not type 4.

    This is a refernece implementation for function 
    ``gen_leech2_start_type4()`` in file ``gen_leech.c``.
    """
    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 0 if v & 0x800000 else -1
        # Let w be the cocode weight. Return -2 if w == 2.
        if mat24.cocode_weight(v) != 4:
            return -2
        # Here v has type 4. Let v23 be the standard type-2 vector.
        # Return 0x20 if v ^ v23 has type 2 and 0x40 otherwise.
        return 0x20 if mat24.cocode_weight(v ^ 0x200) == 2 else 0x40
    if mat24.scalar_prod(v >> 12, v):
        # Then v has type 3 and we return -3
        return -3
    if v & 0x800:
        # Then the cocode word 'coc' of v is odd.
        coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
        syn = mat24.cocode_syndrome(coc)
        # If 'coc' has weight 1 then v is of type 2 and we return -2.
        if (syn & (syn - 1)) == 0:
            return -2
        # Here v is of type 4.
        # Return 0x21 if v ^ v23 is of type 2 and 0x43 otherwise.
        if (syn & 0xc) == 0xc and (v & 0x200000) == 0:
            return 0x21
        return 0x43
    # Let w be the weight of Golay code part divided by 4
    w = mat24.gcode_weight(v >> 12)
    if w == 3:
        # Then the Golay code part of v is a docecad and we return 0x46.
        return 0x46
    # Here the Golay code part of v is a (possibly complemented) octad.
    # Add Omega to v if Golay part is a complemented octad.
    v ^= (w & 4) << 21
    # Put w = 1 if that part is an octad and w = 0 otherwise.
    w = (w >> 1) & 1

    # Let 'octad' be the octad in the Golay code word in vector rep.
    octad = mat24.gcode_to_vect(v >> 12)
    coc = v ^ mat24.ploop_theta(v >> 12)  # cocode element of v
    # Return -2 if v is of type 2.
    sub = suboctad_type(octad, w, coc)
    if sub == 0:
        return -2
    # Return 0x22 if v ^ v23 is shsort
    if suboctad_type(octad, w, coc ^ 0x200) == 0:
        return 0x22
    # Otherwise return the subtype of v
    return 0x44 if sub & 2 else 0x42
コード例 #10
0
ファイル: test_reduce.py プロジェクト: Martin-Seysen/mmgroup
def reduce_type4_std(v, verbose=0):
    r"""Map type-4 vector in Leech lattice to standard vector

    This is (almost) a python implementation of the C function
    ``gen_leech2_reduce_type4`` in file ``gen_leech.c``.
   
    Let ``v \in \Lambda / 2 \Lambda`` of type 4 be given by 
    parameter ``v`` in Leech lattice encoding. 

    Let ``Omega`` be the type- vector in the Leech  lattice 
    corresponding to the standard coordinate frame in the Leech
    lattice.
   
    Then the function constructs a ``g \in G_{x0}`` 
    that maps ``v`` to ``Omega``.
 
    The element ``g`` is returned as a word in the generators
    of ``G_{x0}`` of length ``n \leq 6``. Each atom of the 
    word ``g`` is encoded as  defined in the header 
    file ``mmgroup_generators.h``. 

    The function stores ``g`` as a word of generators in the
    array ``pg_out`` and returns the length  ``n``  of that
    word. It returns a negative number in case of failure, 
    e.g. if ``v`` is not of type 4.

    We remark that the C function ``gen_leech2_reduce_type4`` 
    treats certain type-4  vectors ``v`` in a special way
    as indicated in function ``reduce_type4``.
    """
    if verbose:
        print("Transforming  type-4 vector %s to Omega" % hex(v & 0x1ffffff))
    vtype = gen_leech2_subtype(v)
    result = []
    for _i in range(5):
        coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
        if verbose:
            vt = gen_leech2_subtype(v)
            coc_anchor = 0
            if vt in [0x42, 0x44]:
                w = mat24.gcode_weight(v >> 12)
                vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
                coc_anchor = mat24.lsbit24(vect)
            coc_syn = Cocode(coc).syndrome_list(coc_anchor)
            gcode = mat24.gcode_to_vect(v >> 12)
            print("Round %d, v = %s, subtype %s, gcode %s, cocode %s" %
                  (_i, hex(v & 0xffffff), hex(vt), hex(gcode), coc_syn))
        assert vtype == gen_leech2_subtype(v)
        if vtype == 0x48:
            if verbose:
                res = list(map(hex, result))
                print("Transformation is\n", res)
            return np.array(result, dtype=np.uint32)
        elif vtype == 0x40:
            if v & 0x7ffbff:
                syn = mat24.cocode_syndrome(coc, 0)
                src = mat24.vect_to_list(syn, 4)
                v = apply_perm(v, src, LSTD, 4, result, verbose)
                #print("after type 40", hex(v),  Cocode(v).syndrome(0))
            exp = 2 - ((v >> 23) & 1)
            vtype = 0x48
        elif vtype in [0x42, 0x44]:
            exp = xi_reduce_octad(v)
            if exp < 0:
                v = find_octad_permutation(v, result, verbose)
                exp = xi_reduce_octad(v)
                assert exp >= 0
            vtype = 0x40
        elif vtype == 0x46:
            exp = xi_reduce_dodecad(v, verbose)
            if exp < 0:
                vect = mat24.gcode_to_vect(v >> 12)
                src = mat24.vect_to_list(vect, 4)
                v = apply_perm(v, src, LSTD, len(src), result, verbose)
                exp = xi_reduce_dodecad(v, verbose)
                assert exp >= 0
            vtype = 0x44
        elif vtype == 0x43:
            exp = xi_reduce_odd_type4(v, verbose)
            if exp < 0:
                vect = mat24.gcode_to_vect(v >> 12)
                syn = mat24.cocode_syndrome(coc, 24)
                src = mat24.vect_to_list(syn, 3)
                #print("coc list", src)
                v = apply_perm(v, src, LSTD[1:], len(src), result, verbose)
                exp = xi_reduce_odd_type4(v, verbose)
                assert exp > 0
            vtype = 0x42 + ((exp & 0x100) >> 7)
            exp &= 3
        else:
            raise ValueError("WTF")
        if exp:
            exp = 0xE0000003 - exp
            v_old = v
            v = gen_leech2_op_atom(v, exp)
            assert v & 0xfe000000 == 0, (hex(v_old), hex(exp), hex(v))
            result.append(exp)
    raise ValueError("WTF1")
コード例 #11
0
ファイル: test_reduce.py プロジェクト: Martin-Seysen/mmgroup
def reduce_type2_ortho(v, verbose=0):
    r"""Map (orthgonal) short vector in Leech lattice to standard vector

    This is a python implementation of the C function
    ``gen_leech2_reduce_type2_ortho`` in file ``gen_leech.c``.
   
    Let ``v \in \Lambda / 2 \Lambda`` of type 2 be given by 
    parameter ``v`` in Leech lattice encoding. 

    In the real Leech lattice, (the origin of) the vector ``v`` must
    be orthogonal to the standard short vector ``beta``. Here ``beta``
    is the short vector in the Leech  lattice  propotional
    to  ``e_2 - e_3``, where ``e_i`` is  the ``i``-th basis vector
    of ``\{0,1\}^{24}``.
   
    Let ``beta'`` be the short vector in the Leech lattice propotional
    to  ``e_2 + e_3``.  Then the function constructs a ``g \in G_{x0}`` 
    that maps ``v`` to ``beta'`` and fixes ``beta``.
 
    The element ``g`` is returned as a word in the generators
    of ``G_{x0}`` of length ``n \leq 6``. Each atom of the 
    word ``g`` is encoded as  defined in the header 
    file ``mmgroup_generators.h``. 

    The function stores ``g`` as a word of generators in the
    array ``pg_out`` and returns the length  ``n``  of that
    word. It returns a negative number in case of failure, 
    e.g. if ``v`` is not of type 2,  or not orthogonal 
    to ``beta'`` in the real Leech lattice.
    """
    vtype = gen_leech2_subtype(v)
    if (vtype >> 4) != 2:
        raise ValueError("Vector is not short")
    if gen_leech2_type(v ^ 0x200) != 4:
        raise ValueError("Vector not orthogonal to standard vector")
    result = []
    for _i in range(4):
        if verbose:
            coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
            vt = gen_leech2_subtype(v)
            coc_anchor = 0
            if vt in [0x22]:
                w = mat24.gcode_weight(v >> 12)
                vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
                coc_anchor = mat24.lsbit24(vect)
            coc_syn = Cocode(coc).syndrome_list(coc_anchor)
            gcode = mat24.gcode_to_vect(v >> 12)
            print("Round %d, v = %s, subtype %s, gcode %s, cocode %s" %
                  (_i, hex(v & 0xffffff), hex(vt), hex(gcode), coc_syn))
        assert vtype == gen_leech2_subtype(v)
        if vtype == 0x21:
            exp = xi_reduce_odd_type2(v)
            vtype = 0x22
        elif vtype == 0x22:
            exp = xi_reduce_octad(v)
            if exp < 0:
                w = mat24.gcode_weight(v >> 12)
                vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
                if vect & 0x0c:
                    vect &= ~0x0c
                    src = mat24.vect_to_list(vect, 2) + [2, 3]
                    dest = [0, 1, 2, 3]
                else:
                    src = [2, 3] + mat24.vect_to_list(vect, 3)
                    v5 = (1 << src[2]) | (1 << src[3]) | (1 << src[4])
                    v5 |= 0x0c
                    special = mat24.syndrome(v5, 24)
                    src.append(mat24.lsbit24(special & vect))
                    dest = [2, 3, 4, 5, 6, 7]
                v = apply_perm(v, src, dest, len(src), result, verbose)
                exp = xi_reduce_octad(v)
                assert exp >= 0
            vtype = 0x20
        elif vtype == 0x20:
            if ((v & 0xffffff) == 0x800200):
                return np.array(result, dtype=np.uint32)
            syn = (mat24.cocode_syndrome(v, 0)) & ~0xc
            if syn and syn != 3:
                src = mat24.vect_to_list(syn, 2) + [2, 3]
                v = apply_perm(v, src, [0, 1, 2, 3], 4, result, verbose)
            exp = 2 - ((v >> 23) & 1)
        else:
            raise ValueError("WTF")
        if exp:
            exp = 0xE0000003 - exp
            v = gen_leech2_op_atom(v, exp)
            result.append(exp)
    raise ValueError("WTF1")
コード例 #12
0
ファイル: test_reduce.py プロジェクト: Martin-Seysen/mmgroup
def reduce_type2(v, verbose=1):
    r"""Map (orthgonal) short vector in Leech lattice to standard vector

    This is a python implementation of the C function
    ``gen_leech2_reduce_type2`` in file ``gen_leech.c``.
   
    Let ``v \in \Lambda / 2 \Lambda`` of type 2 be given by 
    parameter ``v`` in Leech lattice encoding. 

    Let ``beta`` be the short vector in the Leech  lattice propotional
    to  ``e_2 - e_3``, where ``e_i`` is  the ``i``-th basis vector
    of ``\{0,1\}^{24}``.
   
    Then the function constructs a ``g \in G_{x0}`` 
    that maps ``v`` to ``beta``.
 
    The element ``g`` is returned as a word in the generators
    of ``G_{x0}`` of length ``n \leq 6``. Each atom of the 
    word ``g`` is encoded as  defined in the header 
    file ``mmgroup_generators.h``. 

    The function stores ``g`` as a word of generators in the
    array ``pg_out`` and returns the length  ``n``  of that
    word. It returns a negative number in case of failure, 
    e.g. if ``v`` is not of type 2.
    """
    vtype = gen_leech2_subtype(v)
    if (vtype >> 4) != 2:
        raise ValueError("Vector is not short")
    result = []
    for _i in range(4):
        if verbose:
            coc = (v ^ mat24.ploop_theta(v >> 12)) & 0xfff
            vt = gen_leech2_subtype(v)
            coc_anchor = 0
            if vt in [0x22]:
                w = mat24.gcode_weight(v >> 12)
                vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
                coc_anchor = mat24.lsbit24(vect)
            coc_syn = Cocode(coc).syndrome_list(coc_anchor)
            gcode = mat24.gcode_to_vect(v >> 12)
            print("Round %d, v = %s, subtype %s, gcode %s, cocode %s" %
                  (_i, hex(v & 0xffffff), hex(vt), hex(gcode), coc_syn))
        assert vtype == gen_leech2_subtype(v)
        if vtype == 0x21:
            exp = xi_reduce_odd_type2(v)
            vtype = 0x22
        elif vtype == 0x22:
            exp = xi_reduce_octad(v)
            if exp < 0:
                w = mat24.gcode_weight(v >> 12)
                vect = mat24.gcode_to_vect((v ^ ((w & 4) << 21)) >> 12)
                src = mat24.vect_to_list(vect, 4)
                dest = [0, 1, 2, 3]
                v = apply_perm(v, src, dest, 4, result, verbose)
                exp = xi_reduce_octad(v)
                assert exp >= 0
            vtype = 0x20
        elif vtype == 0x20:
            exp = 0
            # map v to stadard cocode word [2,3]
            if v & 0x7fffff != 0x200:
                syn = (mat24.cocode_syndrome(v, 0))
                src = mat24.vect_to_list(syn, 2)
                v = apply_perm(v, src, [2, 3], 2, result, verbose)
            # correct v2 if v2 is the cocode word [2,3] + Omega
            if v & 0x800000:
                atom = 0xC0000200
                # operation y_d such that d has odd scalar
                # product with cocode word [2,3]
                v = gen_leech2_op_atom(v, atom)
                result.append(atom)
            assert v & 0xffffff == 0x200
            return np.array(result, dtype=np.uint32)
        else:
            raise ValueError("WTF")
        if exp:
            exp = 0xE0000003 - exp
            v = gen_leech2_op_atom(v, exp)
            result.append(exp)
    raise ValueError("WTF1")