Example #1
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 #2
0
def random_dodecad():
    while True:
        gc = random.randint(0, 0xfff)
        if mat24.gcode_weight(gc) == 3:
            v = mat24.gcode_to_vect(gc)
            w, l = mat24.vect_to_bit_list(v)
            assert w == 12
            l = l[:12]
            random.shuffle(l)
            return l
Example #3
0
 def __pow__(self, other):
     if isinstance(other, Integral):
         return PLoop(mat24.pow_ploop(self.value, other & 3))
     elif isinstance(other, PLoop):
         comm = mat24.ploop_comm(self.value, other.value) << 12
         return PLoop(self.value ^ comm)
     elif isinstance(other, Parity):
         if mat24.gcode_weight(self.value) & 1:
             raise ValueError("Parker Loop element has order > 2")
         return PLoop(mat24.pow_ploop(self.value, other.value))
     else:
         return NotImplemented
Example #4
0
 def __truediv__(self, other):
     if isinstance(other, Integral):
         other = abs(other)
         if other == 1:
             return self
         elif other == 2:
             return Parity(0)
         elif other == 4:
             return Parity(mat24.gcode_weight(self.value) & 1)
         else:
             raise ValueError(ERR_DIV4 % type(self))
     else:
         return NotImplemented
Example #5
0
    def split_octad(self):
        """Split Parker loop element ``a`` into central element and octad

        :return: a triple ``(es, eo, o)`` with  
                 ``a = (-1)**e1 * PLoopOmega**eo * o``.

        Here ``o`` is either the neutral Parker loop element
        ``PLoopOne`` or Parker loop element corresponding to a
        positive octad.  ``es`` and ``eo`` are ``0`` or ``1``.
        An *octad* is a Golay code word 
        (of type |GCode|)  of weight ``8``.

        :raise:
          * Raise ValueError if this is not possible.
        """
        v = self.value
        e1, eo, w = (v >> 12) & 1, 0, mat24.gcode_weight(v)
        if mat24.gcode_weight(v) > 3:
            v, eo, w = v ^ 0x800, 1, 6 - w
        if w <= 2:
            return e1, eo, PLoop(v & 0xfff)
        raise ValueError("Cannot convert Golay code word to octad")
Example #6
0
    def split_octad(self):
        """Split an octad from the Golay code word ``g``. 

        :return: A triple ``(0, eo, o)`` with  ``g  =  Omega * eo + o``.

        Here ``Omega`` is the Golay code word containing  one bits only,
        ``eo`` is ``0`` or ``1``, and ``v`` is a Golay code word 
        of type |GCode| which is either the zero code word or an
        octad, i.e. a code word of weight ``8``.

        This method is for compatibility with the corresponding method 
        in class |PLoop|.

        :raise:
          * ValueError if this is not possible.
        """
        v = self.value
        eo, w = 0, mat24.gcode_weight(v)
        if mat24.gcode_weight(v) > 3:
            v, eo, w = v ^ 0x800, 1, 6 - w
        if w <= 2:
            return 0, eo, GCode(v & 0xfff)
        raise ValueError("Cannot convert Golay code word to octad")
Example #7
0
 def __truediv__(self, other):
     if isinstance(other, PLoop):
         return PLoop(
             mat24.mul_ploop(self.value, mat24.pow_ploop(other.value, 3)))
     elif isinstance(other, Integral):
         if abs(other) == 1:
             return PLoop(self.value ^ ((other & 2) << 11))
         elif abs(other) == 2:
             return Parity(0)
         elif abs(other) == 4:
             return Parity(mat24.gcode_weight(self.value) & 1)
         else:
             raise TypeError(ERR_DIV4 % type(self))
     else:
         return NotImplemented
Example #8
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)
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 #10
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 #11
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 #12
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 #13
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 #14
0
 def __len__(self):
     return mat24.gcode_weight(self.value) << 2
Example #15
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)