Ejemplo n.º 1
0
def rule_xx(group, word):
    global n_rules
    n_rules += 1
    x1, x2 = word[0], word[1]
    delta = AutPLoopAtom('p', mat24.ploop_cap(x1.pl, x2.pl), 0)
    x = xy_Atom(x1.tag, mat24.mul_ploop(x1.pl, x2.pl))
    return [delta, x]
Ejemplo n.º 2
0
def mul_Ty(tag, octad, sub, g):
    d = m24.octad_to_gcode(octad)
    c = m24.suboctad_to_cocode(sub, d)
    e = g.pl
    c1 = m24.ploop_cap(d, e) ^ c
    sub1 = m24.cocode_to_suboctad(c1, d)
    s = m24.scalar_prod(e, c)
    return s, tag, octad, sub1
Ejemplo n.º 3
0
def index_suboctad(tag, i, index_type_T=3, a_indices_T=None):
    """Convert an index specifying an suboctad number

    0 <= 'i' < 64 is an index specifying the number of a suboctad
    in the Golay cocode. Here a suboctad is a Golay cocode word
    which can be represented a subset of of an octad. For each
    octad there is a lexicographic numbering of its suboctad, and
    index 'i' refers to that lexicographic numbering. 

    This index type occurs as the second index of tag T only,
    so the first index of that tag gives us a reference octad. 
    If 'i' is of type Cocode or GcVector, corresponding to a 
    Golay cocode word, that cocode word is taken if it fits into 
    the reference octad; otherwise we raise ValueError. 

    The function returns triple

      (index_type, a_indices, sign).

    Here index_type indicates whether the index has been selected
    ar random, or whether it refers to a slice, as in function 
    index_I().

    The index or the indices making up the slice are returned in
    the numpy array 'a_indices', as in function index_I(). In any
    case the numbers in that array are suboctad numbers.

    Parameters ('index_type_T', 'a_indices_T') must be the values 
    (index_type, a_indices) returned by function index_T(), when
    called with the first index for tag T.
    
    The second index of tag T is of this type. Parameter 'tag' is
    for compatibility with similar functions; it must be 'T'.		 
    """
    if isinstance(i, Integral):
        if 0 <= i < 64:
            return 0, i, 0
        raise IndexError(INDEX_ERROR_RANGE % ("Second ", tag))
    elif isinstance(i, str):
        if i in ["r", "n"]:
            return INDEX_IS_RANDOM, randint(0, 63), 0
        raise IndexError(INDEX_ERROR_RAND % tag)
    elif isinstance(i, slice):
        return INDEX_IS_SLICE, a_slice(i, 64), 0
    elif isinstance(i, (GCode, Cocode, GcVector)):
        if index_type_T == 0:
            gcode = mat24.octad_to_gcode(a_indices_T) & 0xfff
            if isinstance(i, GCode):
                cocode = mat24.ploop_cap(gcode, i)
            else:
                cocode = Cocode(i).cocode
            sub = mat24.cocode_to_suboctad(cocode, gcode)
            return 0, sub, 0
        err = "Second vector index for tag T must be integer here"
        raise TypeError(err)
    elif isinstance(i, Iterable):
        return index_iterable(index, 64, tag, 2)
    raise TypeError(INDEX_ERROR_TYPE % ("Second ", type(i), tag))
Ejemplo n.º 4
0
def rule_xy(group, word):
    global n_rules
    n_rules += 1
    x, y = word[0], word[1]
    delta = AutPLoopAtom('p', mat24.ploop_cap(x.pl, y.pl), 0)
    comm = mat24.ploop_comm(x.pl, y.pl) << 12
    x1 = xy_Atom(x.tag, x.pl ^ comm)
    y1 = xy_Atom(y.tag, y.pl ^ comm)
    return [delta, y1, x1]
Ejemplo n.º 5
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")
Ejemplo n.º 6
0
def _as_suboctad(v1, o):
    d = m24.octad_to_gcode(o)
    c = m24.ploop_cap(v1, d)
    return m24.cocode_to_suboctad(c, d)
Ejemplo n.º 7
0
 def __init__(self, v1, v2):
     assert isinstance(v1, GCode) and isinstance(v2, GCode)
     self.v1, self.v2 = v1.value, v2.value
     self.value = mat24.ploop_cap(self.v1, self.v2)
Ejemplo n.º 8
0
def SubOctad(octad, suboctad=0):
    """Creates a suboctad as instance of class |XLeech2|

    :param octad:

      The first component of the pair *(octad, suboctad)* to be 
      created.

    :type octad: same as in function
      :py:class:`~mmgroup.Octad`

    :param suboctad:
    
      The second component of the pair 
      *(octad, suboctad)* to be created.

    :type suboctad: see table below for legal types


    :return: 

     The suboctad given by the pair *(octad, suboctad)* 

    :rtype: an instance of class |XLeech2|

    :raise:
        * TypeError if one of the arguments *octad* or *suboctad* 
          is not of correct type.
        * ValueError if argument *octad* or *suboctad* does not
          evaluate to an octad or to a correct suboctad,
          respectively.
    

    A *suboctad* is an even cocode element that can be represented
    as a subset of the octad given by the argument *octad*. 

    The raison d'etre of function ``SubOctad`` is that pairs
    *(octad, suboctad)* are used for indexing vectors in the
    representation of the monster group. Here we want to 
    number the octads from ``0`` to ``758`` and the suboctads
    form ``0`` to ``63``, depending on the octad. Note that
    every octad has ``64``  suboctads.

    Depending on its type parameter **suboctad** is  interpreted as follows:

    .. table:: Legal types for parameter ``suboctad``
      :widths: 20 80

      ===================== ================================================
      type                  Evaluates to
      ===================== ================================================
      ``int``               Here the suboctad with the number given 
                            in the argument is 
                            taken.  That numbering depends on the octad 
                            given in   the argument ``octad``. 
                            ``0 <= suboctad < 64`` must hold.                           

      ``list`` of ``int``   Such a list is converted to a bit vector
                            as in class |GcVector|,
                            and the cocode element corresponding to that
                            bit vector is taken.

       class |GCode|        The intersection of the octad given as the 
                            first argument and the Golay code word given
                            as the second argument is taken. 
  
       class |GcVector|     This is converted to a cocode element,
                            see class |Cocode|, and that cocode element 
                            is taken.

       class |Cocode|       That cocode element is taken as the suboctad.


      ``str``               Create random element depending on the string
                             | ``'r'``: Create arbitrary suboctad
      ===================== ================================================

    The numbering of the suboctads

    Suboctads are numbered for 0 to 63. Let ``[b0, b1,..., b7]`` be the 
    bits set in the octad of the pair ``(octad, suboctad)`` in natural 
    order. The following table shows the suboctad numbers for some 
    suboctads given as cocode elements. More suboctad numbers can be 
    obtained by combining suboctads and their corresponding numbers 
    with ``XOR``.

    .. table:: Suboctad numbers of some cocode elements
      :widths: 16 16 16 16 18 18

      =========== =========== =========== =========== =========== =========== 
      ``[b0,b1]`` ``[b0,b2]`` ``[b0,b3]`` ``[b0,b4]`` ``[b0,b5]`` ``[b0,b6]``
      ``s  = 1``  ``s  = 2``  ``s  = 4``  ``s  = 8``  ``s = 16``  ``s = 32``
      =========== =========== =========== =========== =========== =========== 

    E.g. ``[b0, b5, b6, b7]`` is equivalent to ``[b1, b2, b3, b4]`` 
    modulo the Golay code and has number ``s = 1 ^ 2 ^ 4 ^ 8 = 15``.

    """
    ploop = Octad(octad)
    gcode = ploop.value & 0xfff
    if isinstance(suboctad, str):
        suboctad_ = randint(0, 63)
    elif isinstance(suboctad, Integral):
        suboctad_ = suboctad & 0x3f
    elif isinstance(suboctad, GCode):
        value = mat24.ploop_cap(gcode, suboctad.value)
        suboctad_ = mat24.cocode_to_suboctad(value, gcode)
    else:
        value = Cocode(suboctad).cocode
        suboctad_ = mat24.cocode_to_suboctad(value, gcode)
    cocode = mat24.suboctad_to_cocode(suboctad_, gcode)
    if import_pending:
        complete_import()
    result = XLeech2(ploop, cocode)
    subtype = result.xsubtype
    assert subtype in [0x22, 0x42], (hex(subtype), hex(ploop), hex(cocode),
                                     hex(result.value))
    # complent a complement of an octad
    if subtype == 0x42:
        result.value ^= 0x800000
    return result
Ejemplo n.º 9
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)
Ejemplo n.º 10
0
def as_suboctad(v1, d):
    c = m24.ploop_cap(v1, d)
    return m24.cocode_to_suboctad(c, d)