Example #1
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)
Example #2
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)
Example #3
0
    def mmdata(self):
        """Return internal representation of corresponding monster element.

        That internal representation is returned as a numpy array 
        of 32-bit integers.
        """
        v = self.value
        x = (v >> 12) & 0x1fff
        d = (mat24.ploop_theta(v >> 12) ^ v) & 0xfff
        return np.array([0x30000000 + x, 0x10000000 + d], dtype=np.uint32)
Example #4
0
 def __and__(self, other):
     if isinstance(other, XLeech2):
         ov = other
     elif isinstance(other, (GCode, PLoop)):
         d = other.value & 0xfff
         ov = (d << 12) ^ mat24.ploop_theta(d)
     elif isinstance(ploop, Cocode):
         ov = ploop.value & 0xfff
     else:
         return NotImplemented
     return Parity(gen_leech2_scalprod(self.value, ov))
Example #5
0
    def isplit(self):
        r"""Split element into a product :math:`x_d \cdot x_\delta`

        The method returns a pair  :math:`(d,  \delta)` such that
        :math:`x_d \cdot x_\delta` is equal to the given element
        of  :math:`Q_{x0}`.

        Here :math:`(d,  \delta)` is returned as a pair of integers.
        """
        v = self.value
        x = (v >> 12) & 0x1fff
        d = (mat24.ploop_theta(v >> 12) ^ v) & 0xfff
        return x, d
Example #6
0
def apply_perm(v, src, dest, n, log_list, verbose=0):
    r"""Apply permutation to vector in Leech lattice mod 2.
  
    The function computes a permutation :math:`\pi` that maps
    the entries of the array ``src`` of length ``n`` to
    the entries of the array ``dest`` (of the same length) in
    the given order. 

    Let :math:`v_2` be the vector in the Leech lattice mod  2 given 
    by parameter ``v2``. The function returns :math:`v_2 x_\pi`.
    Parameter ``v2`` and the return value are given in Leech
    lattice encoding.
  
    Parameter ``p_res`` points to an integer where the function 
    stores the element :math:`x_\pi` as a generator of the
    monster group as as described  in file ``mmgroup_generators.h``.
    That generator is stored with tag  ``MMGROUP_ATOM_TAG_IP`` so
    that we can compute the inverse of :math:`\pi` very 
    efficiently. 

    We compute the inverse of the lowest permutation (in lexical
    order) that maps ``dest[:n]`` to ``src[:n]``.
    """
    res, p = mat24.perm_from_map(dest[:n], src[:n])
    assert res > 0, (res, dest[:n], src[:n])
    p_inv = mat24.inv_perm(p)
    p_num = mat24.perm_to_m24num(p)
    log_list.append(0xA0000000 + p_num)
    xd = (v >> 12) & 0xfff
    xdelta = (v ^ mat24.ploop_theta(xd)) & 0xfff
    m = mat24.perm_to_matrix(p_inv)
    xd = mat24.op_gcode_matrix(xd, m)
    xdelta = mat24.op_cocode_perm(xdelta, p_inv)
    v_out = (xd << 12) ^ xdelta ^ mat24.ploop_theta(xd)
    if verbose:
        print("Apply permutation (mapping v to gcode %s):\n%s" %
              (hex(mat24.gcode_to_vect(v_out >> 12)), p_inv))
    return v_out
Example #7
0
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
Example #8
0
def MM_to_Q_x0(g):
    if check_mm_in_g_x0 is None:
        import_mm_order_functions()
    g = MM0('a', g.mmdata)
    if check_mm_in_g_x0(g) is None:
        raise ValueError(ERR_XL_IN_Q)
    g.reduce()
    res = 0
    for atom in g.mmdata:
        tag = (atom >> 28) & 0x0f
        if res == 0 and tag == 3:
            res = ((atom & 0x1fff) << 12) ^ mat24.ploop_theta(atom)
        elif tag == 1:
            res ^= atom & 0xfff
        elif tag:
            raise ValueError(ERR_XL_IN_Q)
    return res
Example #9
0
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)
Example #10
0
def iter_q(tag, r):
    if isinstance(r, Integral):
        e = r & 0x1ffffff
    elif isinstance(r, str):
        e = randint(r == 'n', 0x1ffffff)
        if len(r) != 1 or not d in "rn":
            raise ValueError(ERR_ATOM_VALUE % tag)
    else:
        try:
            e = r.as_Q_x0_atom()
            assert isinstance(e, Integral)
        except:
            raise TypeError(ERR_Q_x0)
    d = (e >> 12) & 0x1fff
    delta = (e ^ ploop_theta(d)) & 0xfff
    yield tag_dict['x'] + d
    yield tag_dict['d'] + delta
Example #11
0
    def theta(self, g2=None):
        """Return cocycle of Golay code words.

        The cocycle ``theta`` maps a pair of Golay code words 
        to an integer modulo ``2``. 
        It is linear in its second argument, so it
        may also be considered as a mapping from the Golay code
        to the cocode of the Golay code.


        :param g2:  ``None`` (default) or another Golay code word of
                    type |GCode|.
        :returns:
            * If ``g2`` is a code word of type |GCode|, we return
              the value ``g1.theta(g2) = theta(g1, g2)`` 
              as a |Parity| object.
            * If ``g2`` is ``None`` (default), we return the value
              ``g1.theta() = theta(g1)``  as a |Cocode| object.
              Note that  ``g1.theta(g2) == g1.theta() & g2 .``

        The importance of the ``theta`` function comes from the
        fact that the multiplication of elements of the Parker loop
        is based on the cocycle. We embed the set of Golay code words  
        into  the set of positive Parker loop elements, which are 
        instances of class |PLoop|. 
 
        Let ``g1`` and ``g2`` be Golay code words of type |GCode|.
        Then  ``PLoop(g1)`` and ``PLoop(g2)`` are the corresponding
        positive Parker loop elements,  and  ``g1.theta(g2)`` is an 
        integer  modulo ``2`` of type |Parity|. We have:  
       
        ``PLoop(g1) * PLoop(g2) == (-1)**g1.theta(g2) * PLoop(g1 + g2) .``
        """
        th = mat24.ploop_theta(self.value)
        if g2 == None:
            complete_import()
            return Cocode(th)
        if isinstance(g2, GCode):
            return Parity(mat24.scalar_prod(g2.value, th))
        err = "Types %s is illegal for method theta()"
        raise TypeError(err % type(g2))
Example #12
0
def find_in_Q_x0(w):
    global err_in_g_x0_py
    w_x = mm_aux_mmv_extract_sparse_signs(15, w, 
        ORDER_TAGS[OFS_TAGS_X:], 24)
    if w_x < 0:
        err_in_g_x0_py = 7
        return None
    x = leech2matrix_solve_eqn(ORDER_TAGS[OFS_SOLVE_X:], 24, w_x)
    w_sign = ((x >> 12) & 0x7ff) ^ (x & 0x800)
    aa = np.array(ORDER_TAGS[OFS_TAG_SIGN:] ^ (w_sign << 14),
        dtype = np.uint32)
    sign = mm_aux_mmv_extract_sparse_signs(15, w, aa, 1)
    if sign < 0:
        err_in_g_x0_py = 8
        return None
    x &= 0xffffff
    sign ^= uint64_parity(x & (x >> 12) & 0x7ff)
    x ^=  (sign & 1) << 24
    x ^= ploop_theta(x >> 12)
    #print("final x =", hex(x))
    return x
Example #13
0
def xi_reduce_dodecad(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 0x46.

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

    The function returns ``e`` if such an eponent exists.  A negative
    return value indicates that no such exponent ``e`` exists.
    """
    # Let ``vect`` be the Golay code part of v as a bit vector.
    vect = mat24.gcode_to_vect(v >> 12)
    # Set bit 4*i of s if all bits 4*i, 4*i+1, 4*i+2, 4*i+3 of
    # ``vect`` are equal, otherwise clear bit 4*i, for 0 <= i < 6.
    s1 = vect | (vect >> 2)
    s1 = s1 | (s1 >> 1)
    s0 = vect & (vect >> 2)
    s0 = s0 & (s0 >> 1)
    s = (s0 | ~s1) & 0x111111
    # If the Golay code part of v is a docecad then either no or two
    # bits in s are set. Fail if no bit in s is set.
    if (s == 0):
        return -1
    # Here two bits of s (in two different MOG columns) are set.
    # Set all bits in a MOG column if one bit is set in that column.
    # Thus the bits being set in s form a grey even octad.
    s *= 15
    # Let 'coc' be the cocode part of v
    coc = v ^ mat24.ploop_theta(v >> 12)
    # Compute scalar product of octad s and ``coc`` in ``scalar``
    tab = mat24.syndrome_table((mat24.recip_basis[0] ^ coc) & 0x7ff)
    scalar = s ^ (s >> (tab & 31)) ^ (s >> ((tab >> 5) & 31))
    scalar ^= (s >> ((tab >> 10) & 31))
    scalar &= 1
    # The requested exponent is now equal to ``2 - scalar``.
    exp = 2 - scalar
    return exp
Example #14
0
 def __init__(self, value):
     if import_pending:
         complete_import()
     if isinstance(value, Integral):
         self.value = value & 0xfff
     elif isinstance(value, Cocode):
         self.value = value.value
     elif isinstance(value, GcVector):
         self.value = mat24.vect_to_cocode(value.value)
     elif isinstance(value, XLeech2):
         v = value.value
         self.value = (mat24.ploop_theta(v >> 12) ^ v) & 0xfff
     elif isinstance(value, str):
         if len(value) == 1 and value in "reo":
             self.value = randint(0, 0xfff)
             if "o" in value: self.value |= 0x800
             if "e" in value: self.value &= 0x7ff
         else:
             raise ValueError(ERR_RAND % 'Cocode')
     else:
         vector = as_vector24(value)
         self.value = mat24.vect_to_cocode(vector)
Example #15
0
def elem_to_word(elem, verbose=1):
    assert isinstance(elem, Xsp2_Co1)
    assert isinstance(verbose, int), verbose
    group = elem.group
    len_a = 0
    a0 = np.zeros(16, dtype=np.uint32)
    img_Omega = elem.xsp_conjugate(0x800000)

    if verbose:
        print("Convert element g of G_x0 to word. Element is:")
        print(elem)
        print("g conjugates 0x800000 to %s" % hex(img_Omega))

    len_a = gen_leech2_reduce_type4(img_Omega, a0)
    a0 = list(a0[:len_a])
    elem_reduced = elem.copy().mul_data(a0)

    if verbose:
        print("Word w0 stabilizing Omega:")
        print(" ".join([hex(x) for x in a0]))
        print("After multiplication with w0, the element is:")
        print(elem_reduced)

    a1 = list(monomial_to_word(elem_reduced, verbose > 1))
    elem_reduced = elem_reduced.mul_data(a1)

    x = elem_reduced.as_xsp()
    x ^= mat24.ploop_theta(x >> 12)
    a = []
    if (x & 0x1fff000):
        a.append(0x30000000 + (x >> 12))
    if (x & 0xfff):
        a.append(0x10000000 + (x & 0xfff))
    a += [x ^ 0x80000000 for x in (a0 + a1)[::-1]]
    a = np.array(a, dtype=np.uint32)
    if verbose:
        print("Word is:\n " + str(MM.from_data(a)))
    return a
Example #16
0
def value_from_ploop(ploop=0, cocode=None, *args):
    c = Cocode(cocode).ord if cocode else 0
    if isinstance(ploop, Integral):
        d = ploop & 0x1ffffff
    elif isinstance(ploop, PLoop):
        d = ploop.value & 0x1fff
        d = (d << 12) ^ mat24.ploop_theta(d)
    elif isinstance(ploop, XLeech2):
        d = ploop.value
    elif isinstance(ploop, Cocode):
        d = ploop.value & 0xfff
    elif isinstance(ploop, AbstractMMGroupWord):
        d = MM_to_Q_x0(ploop)
    elif isinstance(ploop, str):
        if len(ploop) == 1 and ploop in "BCTXES":
            d = 0
            a = tuple_to_sparse(0xff, ploop, cocode, *args)
            if len(a) == 1:
                a0 = a[0]
                d = mm_aux_index_sparse_to_leech2(a0)
                a0 &= 0xff
                if a0 == 0xfe:
                    d ^= 0x1000000
                elif a0 != 1:
                    d = 0
            if d:
                return d
        if ploop == "r":
            if cocode is None:
                return randint(0, 0x1ffffff)
            elif cocode in [0, 2, 3, 4]:
                return rand_xleech2_type(cocode)
        raise ValueError(ERR_XL_TUPLE)
    else:
        return TypeError(ERR_XL_TYPE % type(ploop))
    return d ^ c
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
Example #18
0
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")
Example #19
0
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")
Example #20
0
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")
Example #21
0
def op_xy(v, eps, e, f):
    """Multiply unit vector v with group element

    This function multplies a (multiple of a) unit vector v
    with the group element

        g  =  d_<eps> * (x_<e>)**(-1)  * (y_<f>)**(-1) .
   
    It returns the vector w = v * g. This function uses the same 
    formula for calculating  w = v * g,  which is used in the 
    implementation of the monster group for computing
    v = w * g ** (-1).

    Input vector v  must be given as a tuple as described in class
    mmgroup.structures.abstract_mm_rep_space.AbstractMmRepSpace.
    Output vector is returned as a tuple of the same shape.
    """
    if len(v) == 3:
        v = (1,) + v
    v_value, v_tag, v_d, v_j = v
    parity = (eps >> 11) & 1  # parity of eps
    if v_tag == 'X':
        w_d = v_d ^ (f & 0x7ff)
        sign = v_d >> 12
        d = v_d & 0x7ff
        c =  m24.vect_to_cocode(1 << v_j)
        sign +=  m24.gcode_weight(e ^ f) 
        sign += m24.gcode_weight(f) 
        sign += m24.gcode_weight(d) * (parity + 1)
        sign += m24.gcode_weight(d ^ e ^ f)
        sign += m24.scalar_prod(e, c)
        cc = c if parity else 0 
        cc ^= eps ^ m24.ploop_theta(f) ^ m24.ploop_cap(e, f) 
        sign += m24.scalar_prod(d, cc)
        sign += f >> 12
        return (-1)**sign * v_value, 'X', w_d, v_j
    elif v_tag in 'YZ':
        tau = v_tag == 'Y'
        sigma = (tau + parity) & 1
        w_tag = "ZY"[sigma]
        sign = (v_d >> 12) + ((v_d >> 11) & tau)
        w_d = (v_d ^ e ^ (f & ~-sigma)) & 0x7ff
        #print("YZ, w_d", hex(w_d), hex(v_d ^ (e & 0x7ff) ^ (f & sigma_1)), err)
        # Next we check the sign
        d = v_d & 0x7ff
        c =  m24.vect_to_cocode(1 << v_j)
        sign += m24.ploop_cocycle(f, e) * (sigma + 1)
        sign += m24.gcode_weight(f) * (sigma)
        sign += m24.gcode_weight(d ^ e)  
        sign += m24.gcode_weight(d ^ e ^ f)  
        sign += m24.scalar_prod(f, c)
        cc = eps ^ m24.ploop_theta(e) 
        cc ^=  m24.ploop_theta(f) * ((sigma ^ 1) & 1)
        sign += m24.scalar_prod(d, cc)
        sign += (e >> 12) + (f >> 12) * (sigma + 1)
        sign += ((e >> 11) & sigma)
        return (-1)**sign * v_value, w_tag, w_d, v_j
    elif v_tag == 'T':
        d = m24.octad_to_gcode(v_d)
        w_j = v_j  ^ as_suboctad(f, d)
        sign = m24.gcode_weight(d ^ e) + m24.gcode_weight(e)
        sign +=  m24.scalar_prod(d, eps)
        sign += m24.suboctad_scalar_prod(as_suboctad(e ^ f, d), v_j)
        sign += m24.suboctad_weight(v_j) * parity
        return (-1)**sign * v_value, 'T', v_d, w_j
    elif v_tag in 'BC':
        m = v_tag == 'C'
        c = m24.vect_to_cocode((1 << v_d) ^ (1 << v_j))
        n = m ^ m24.scalar_prod(f, c)
        w_tag = "BC"[n]
        w_i, w_j = max(v_d, v_j), min(v_d, v_j)
        sign = m * parity + m24.scalar_prod(e ^ f, c)
        return (-1)**sign * v_value, w_tag, w_i, v_j
    elif v_tag == 'A':
        w_i, w_j = max(v_d, v_j), min(v_d, v_j)
        c = m24.vect_to_cocode((1 << v_d) ^ (1 << v_j))
        sign = m24.scalar_prod(f, c)
        return (-1)**sign * v_value,'A', w_i, v_j
    else:
        raise ValueError("Bad tag " + v_tag)
Example #22
0
def test_Parker_loop():
    print("\nTesting operation on Parker loop")
    for i in range(200):
        # Test power map, inveriosn, sign, theta, and conversion to GCode
        n1 = randint(0, 0x1fff)
        p1 = PLoop(n1)
        assert p1.ord == n1 == p1.gcode + 0x1000 * (1 - p1.sign) / 2
        if (i < 2):
            print("Testing Parker loop element", p1, ", GCode = ", GCode(p1))
        assert len(p1) == mat24.gcode_weight(n1) << 2
        assert p1.theta() == Cocode(mat24.ploop_theta(n1))
        assert p1 / 4 == p1.theta(p1) == Parity(mat24.ploop_cocycle(n1, n1))
        assert p1**2 == PLoopZ(p1 / 4) == (-PLoopZ())**(p1 / 4)
        assert p1**(-5) == PLoopZ(p1 / 4) * p1 == (-1)**(p1 / 4) * p1 == 1 / p1
        assert (1 / p1).ord ^ n1 == (mat24.gcode_weight(n1) & 1) << 12
        assert -1 / p1 == -p1**3 == -(1 / p1)
        assert p1 * (-1 / p1) == PLoopZ(1) == -PLoopZ()
        assert abs(p1).ord == GCode(p1).ord == p1.ord & 0xfff
        assert p1 != GCode(p1)
        assert +p1 == 1 * p1 == p1 * 1 == p1
        assert p1 != -p1 and p1 != ~p1
        assert (-p1).ord == p1.ord ^ 0x1000
        assert (~p1).ord == p1.ord ^ 0x800
        s, o, p1_pos = p1.split()
        assert s == (p1.ord >> 12) & 1
        assert o == (p1.ord >> 11) & 1
        assert p1.sign == (-1)**s
        assert p1_pos.ord == p1.ord & 0x7ff
        assert PLoopZ(s, o) * p1_pos == p1
        assert PLoopZ(0, o) * p1_pos == abs(p1)
        assert PLoopZ(s + 1, o) * p1_pos == -p1
        assert -p1 == -1 * p1 == p1 * -1 == p1 / -1 == -1 / p1**-5
        assert PLoopZ(s, 1 + o) * p1_pos == ~p1
        assert PLoopZ(1 + s, 1 + o) * p1_pos == ~-p1 == -~p1 == ~p1 / -1
        assert 2 * p1 == GCode(0) == -2 * GCode(p1)
        assert -13 * p1 == GCode(p1) == 7 * GCode(p1)
        if len(p1) & 7 == 0:
            assert p1**Parity(1) == p1
            assert p1**Parity(0) == PLoop(0)
        else:
            with pytest.raises(ValueError):
                p1**Parity(randint(0, 1))
        assert p1.bit_list == mat24.gcode_to_bit_list(p1.value & 0xfff)
        assert p1.bit_list == GcVector(p1).bit_list
        assert p1.bit_list == GCode(p1).bit_list
        assert PLoop(GcVector(p1) + 0) == PLoop(GCode(p1) + 0) == abs(p1)
        assert p1 + 0 == 0 + p1 == GCode(p1) + 0 == 0 + GCode(p1)
        assert Cocode(GcVector(p1)) == Cocode(0)
        assert p1 / 2 == Parity(0)

        # Test Parker loop multiplication and commutator
        n2 = randint(0, 0x1fff)
        p2 = PLoop(n2)
        coc = Cocode(mat24.ploop_cap(n1, n2))
        if (i < 1):
            print("Intersection with", p2, "is", coc)
        p2inv = p2**-1
        assert p1 * p2 == PLoop(mat24.mul_ploop(p1.ord, p2.ord))
        assert p1 / p2 == p1 * p2**(-1)
        assert p1 + p2 == p1 - p2 == GCode(p1 * p2) == GCode(n1 ^ n2)
        assert (p1 * p2) / (p2 * p1) == PLoopZ((p1 & p2) / 2)
        assert p1 & p2 == coc
        assert p1.theta() == Cocode(mat24.ploop_theta(p1.ord))
        assert p1.theta(p2) == Parity(mat24.ploop_cocycle(p1.ord, p2.ord))
        assert (p1 & p2) / 2 == p1.theta(p2) + p2.theta(p1)
        assert p1 & p2 == p1.theta() + p2.theta() + (p1 + p2).theta()
        assert int((p1 & p2) / 2) == mat24.ploop_comm(p1.ord, p2.ord)
        assert GcVector(p1 & p2) == GcVector(p1) & GcVector(p2)
        assert ~GcVector(p1 & p2) == ~GcVector(p1) | ~GcVector(p2)
        assert Cocode(GcVector(p1 & p2)) == p1 & p2

        # Test associator
        n3 = randint(0, 0x1fff)
        p3 = PLoop(n3)
        assert p1 * p2 * p3 / (p1 * (p2 * p3)) == PLoopZ(p1 & p2 & p3)
        assert int(p1 & p2 & p3) == mat24.ploop_assoc(p1.ord, p2.ord, p3.ord)
        i = randint(-1000, 1000)
        par = Parity(i)
        s3 = ((p3 & p1) & p2) + par
        assert s3 == ((p3 & p1) & p2) + par
        assert s3 == i + (p1 & (p2 & p3))
        assert s3 == par + (p1 & (p2 & p3))

        # Test some operations leading to a TypeError
        with pytest.raises(TypeError):
            p1 & p2 & p3 & p1
        with pytest.raises(TypeError):
            coc & coc
        with pytest.raises(TypeError):
            GCode(p1) * GCode(p2)
        with pytest.raises(TypeError):
            1 / GCode(p2)
        with pytest.raises(ValueError):
            coc / 4
        with pytest.raises(TypeError):
            p1 * coc
        with pytest.raises(TypeError):
            coc * p1
        types = [GcVector, GCode, Cocode, PLoop]
        for type_ in types:
            with pytest.raises(TypeError):
                int(type_(0))

    print("Parker Loop test passed")
Example #23
0
def ploop_to_xsp2co1(g, pl):
    res = g.word_type(group=g)
    value = (c.value & 0x1fff)
    value = (value << 12) ^ mat24.ploop_theta(value)
    chk_qstate12(xsp2co1_elem_xspecial(res._data, value))
    return res
Example #24
0
 def str(self):
     v = self.value
     x = (v >> 12) & 0x1fff
     d = (mat24.ploop_theta(v >> 12) ^ v) & 0xfff
     return "XL2<x_%s*d_%s>" % (ihex(x, 3), ihex(d, 3))