Beispiel #1
0
def make_theta_table():
    r"""Creates the theta function for the Parker Loop
    theta() is a function from the Golay code C to the Golay cocode C*.

    Multiplication '(*)' in the Parker loop is defined by:

           a (*) b = (a ^ b) * (-1) ** scalar(theta(a),b) ,

    Where '^' is the vector addition in GF(2)**12, and  scalar(.,.)
    is the scalar product defined on C x C*.     

    More specifically, theta is a quadratic form from C onto C*. The 
    basis cc_i, i=0,...,11 of the cocode defined here is reciprocal to 
    the basis c_i, i=0,...,11 of the cocode defined here. 
    Define   theta(i)[j] = theta(i) * c_j.   Then 

            theta(i)  = sum[1 << theta(i)[j] for j in range(12) ]. 
 
    To define theta as a quadratic form, it suffices to define theta 
    on the basis vectors. We define theta on the basis vectors as
    given by function theta_to_basis_vector(v).

    There is a symmetric bilinear form B : from C x C onto C*
    associated with theta on all pairs of basis vectors satisfying:

             B(x,y) = theta(x+y) + theta(x) + theta(y)   .        
             B(x,y) = x :math:`\cap` Y

    Here :math:`\cap means intersection (i.e. bitwise 'and' in 
    GF(2)**24) of two Golay code words. This allows us to compute 
    theta(x), for all Golay code words, if theta is given on a 
    basis of the Golay code.
    """
    assert Mat24Tables.gcode_to_vect(0x800) == 0xffffff
    theta_table = numpy.zeros(0x800, dtype = uint16)

    thetas = theta_basis_vectors()
    for i in range(11):
         theta_table[1 << i] = Mat24Tables.vect_to_cocode(thetas[i])
 
    for i in range(0x800):
        if (i & (i-1)) != 0:    # i.e. if i is not 0 or a power of 2
            i0 = 1 << v2(i) 
            i1 = i ^ i0
            cap = Mat24Tables.gcode_to_vect(i0) 
            cap &= Mat24Tables.gcode_to_vect(i1)
            cc = Mat24Tables.vect_to_cocode(cap)
            theta_table[i] = theta_table[i0] ^ theta_table[i1] ^ cc
    return theta_table
Beispiel #2
0
def superoctads(contained, not_contained, partial = [], weight = 0):
    """Return a specific list of octads
    
    The function returns a specific list of octads, where each 
    octad is given as a 24-bit integer describing a bit vector in 
    ``vector`` representation.
    
    An octad is included in the list if it satisfies the following
    requiremets.
     
      * All entries in the list ``contained ``must be contained 
        in the octad.
        
      * No entry in the list ``not_contained`` may be containe 
        in the octad.

      * Precisely ``weight`` entries of the list ``partial``
        must be in the octad.

    Each parameter ``contained `, ``not_contained``, or ``weight``
    may be a list of different integers < 24 or a 24-bit integer
    representing a bit vetor.    
    """
    if not isinstance(contained, int): 
        contained =  list_to_set24(contained)   
    if not isinstance(not_contained, int): 
        not_contained =  list_to_set24(not_contained)  
    if not isinstance(partial, int): 
        partial =  list_to_set24(partial)  
    return [x for x in octad_list() if (x & contained == contained)
        and (x & not_contained == 0)
        and (gc.bw24(x & partial) == weight) 
    ]
Beispiel #3
0
def augment_theta_table(theta_table):
    """store bitweight of Golay code word i in table[i/2], bits 14..12"""
    for i in range(0x800):
        w = bw24(Mat24Tables.gcode_to_vect(i))
        assert w in [0,8,12,16]
        theta_table[i] |=  (w >> 2) << 12
    return  theta_table
Beispiel #4
0
def odd_syn(v):
    """Return Golay cocode syndrom of a bit vector v

    The bit vector v must have odd parity.
    """
    coc = gc.vect_to_vintern(v)
    t = gc.syndrome_table[coc & 0x7ff ]
    return ( (1 << (t & 31)) ^ (1 << ((t >> 5) & 31)) ^
             (1 << ((t >> 10) & 31)) )
Beispiel #5
0
def py_mat24_int_to_perm(n):
    """Return the k-th permutation p in the Mathieu group Mat24   

    Here the elements of the Mathieu group Mat24 are numbererd
    in lexicographic order.

    Any integer 0 <= n < 244823040 is evaluated in mixed-radix with 
    bases  24, 23, 22, 21, 20, 3, 16, with valence decreasing from 
    left to right. The first five digits determine the images of
    the first five elements of the permutation. The next digit
    determines the image of entry 5. That entry has 3 possible 
    images, depending on the syndrome of the images of the first
    five elements. The final digit determines the image of element 8, 
    i.e.  the first element not in the standard octad. 

    The images of the remaining elements 6, 7 and 9,...,23  are 
    determined by calling function complete_heptad()

    This implementation of the function is easy to understand but
    not fast. Function ``mat24_int_to_perm`` is a faster version of
    this function.
    """
    assert 0 <= n < MAT24_ORDER
    # Compute the output permutation in ``p``
    p = [None] * 24
    # List of elements to be permuted by Mat24
    p_list = list(range(24))
    # Convert n to mixed-radix digit list ``n_list`` as described above.
    n_list = split_n_mat24(n)
    # Compute the images of the first five numbers 0,...,4 under p
    # from the the first five digits of the digit list.
    # After assigning an image, delete that image from ``n_list``,
    # in order to avoid repetitions.
    for i in range(5):
        index = n_list[i] 
        p[i] = p_list[index]
        del p_list[index]
    # Compute the syndrome these five images in the list ``syn``.
    # That syndrome has length 3.  
    bitmap = sum(1 << i for i in p[:5])
    cocode = gc.vect_to_cocode(bitmap)
    syn_tab = gc.syndrome_table[cocode & 0x7ff]
    syn = [(syn_tab >> i) & 31 for i in [0, 5, 10]] 
    # Select image of the number 5 from that syndrome,
    # using entry 5 f the digit list ``n_list``
    p[5] = syn[n_list[5]]
    # Let p_list be the list of number 0 <= i < 24 that are not images
    # any of the numbers of [0,1,2,3,4] and not in the syndrome.
    bitmap |= sum(1 << i for i in syn)
    p_list = [i for i in range(24) if ((1 << i) & bitmap) == 0]
    # Select image of the number 8 from that list,
    # using entry 6 f the digit list ``n_list``
    p[8] = p_list[n_list[6]]
    mat24_complete_heptad(p)
    return p
Beispiel #6
0
def octad_list():
    """Return the sorted list of all octads
    
    Each octad is given as a 24-bit integer describing a bit 
    vector in `vector`` representation. Octads are sorted 
    lexicographically, so lower bits of the integer are sorted
    with higher priority.        
    """
    global _OCTAD_LIST
    if _OCTAD_LIST is not None:
        return _OCTAD_LIST[:]
    l_oct = [set24_to_list(gc.octad_to_vect(o)) for o in range(759)]
    l_oct.sort()
    _OCTAD_LIST = [list_to_set24(l) for l in l_oct]
    return _OCTAD_LIST[:]
Beispiel #7
0
class Mat24(Mat24Tables): 
    r"""Provide functions for the Mathieu group Mat24 and the Parker loop.

    These functions are exported as class methods. They are considered as
    pure python substitutes for the functions in the ``mmgroup.mat24``
    extension.

    So they can be used in an early stage of the build process where that
    extension is not yet available. The are also used for testing the
    ``mmgroup.mat24`` package.

    See module ``mmgroup.dev.mat24.mat24_doc`` for an overview of the
    functionality of the ``mmgroup.mat24`` extension. 

    This class is also a table-providing class used by the code
    generator for generating C code containing the functionality
    of the  ``mmgroup.mat24`` extension. For details, see section 
    *How the code generator is used* in 
    *The mmgroup guide for developpers*. 
    """
    ## Create tables for faster computetion
    MAT24_ORDER =  244823040 
    matrix_to_perm_ = MatrixToPerm(Mat24Tables.basis[12:])
    heptad_completer = HeptadCompleter(Mat24Tables)
    theta_table = make_augmented_theta_table()
    autpl_qf_table = make_autpl_qf_table(theta_table)
    autpl_qf_table64 = make_autpl_qf_table(theta_table, 64)
    verbose = False
    basis_weights_8 = Mat24Tables.basis_weights_8()

    # recip_basis(i & 31) shall not fail in C 
    recip_basis_c = numpy.append(Mat24Tables.recip_basis.copy(), [0]*8)

    ## Collect tables and coding functions for generating C code
    tables = {
           "Mat24_enc_table0"    : Mat24Tables.enc_table0,
           "Mat24_enc_table1"    : Mat24Tables.enc_table1,
           "Mat24_enc_table2"    : Mat24Tables.enc_table2,
           "Mat24_dec_table0"    : Mat24Tables.dec_table0,
           "Mat24_dec_table1"    : Mat24Tables.dec_table1,
           "Mat24_dec_table2"    : Mat24Tables.dec_table2,
           "Mat24_basis"         : Mat24Tables.basis,
           "Mat24_recip_basis"   : recip_basis_c,
           "Mat24_syndrome_table"    : Mat24Tables.syndrome_table,
           "Mat24_oct_enc_table"     : Mat24Tables.oct_enc_table,
           "Mat24_oct_enc_offset"    : Mat24Tables.oct_enc_offset,
           "Mat24_oct_dec_table"     : Mat24Tables.oct_dec_table, 
           "Mat24_theta_table"       : theta_table,
           "Mat24_autpl_qf_table"    : autpl_qf_table,
           "Mat24_autpl_qf_table64"  : autpl_qf_table64,
           "Mat24_doc"               : Mat24__doc__, 
           "INT_BITS"                : config.INT_BITS,
           "Mat24_basis_weights_8"   : basis_weights_8,
    }

    directives = {}

    _subgenerators = [
            Lsbit24Function, 
            matrix_to_perm_,
            heptad_completer,
            BitMatrixMulFix(),
            BitMatrixMulTransp(),
    ]

    for gen in _subgenerators:
        tables.update(gen.tables())
        directives.update(gen.directives())


    @classmethod
    def str_basis(cls, with_reciprocal_basis = False):
        def show(text, basis):
            s = text + "\n"
            for i,x in enumerate(basis): 
                if i % 6 == 0: s += "    "
                s +=  "%06x " % x
                if i % 6 == 5: s += "\n"
            return s
        s = "We list the basis vectors of the Golay code and of its cocode."
        s += """

Basis vectors have indices 0,...,11. Each basis vector is displayed 
as a hexadecimal number with bit i (of valence 2**i) corresponding  
to component i of the basis vector in GF(2)^24 for i = 0,...,23.
Golay cocode vectors are to be understood modulo the Golay code. 

"""
        s +=  show( "Golay cocode basis", cls.basis[:12] )
        s +=  show( "Golay code basis" , cls.basis[12:] )
        if with_reciprocal_basis:
             s += show( "Reciprocal basis", cls.recip_basis )
        return s
      
    @classmethod
    def show_basis(cls, with_reciprocal_basis = True):
        print(cls.str_basis(with_reciprocal_basis))

    ###########################################################################
    # Parker Loop
    ###########################################################################

    @classmethod
    def ploop_theta(cls, v1):
        """Return the theta function for the Parker loop.

        theta is a quadratic from from the Golay code C to the cocode C*.
        Here parameter v1 of function theta is represented as a Golay code 
        word. The result of the function is represented as a Golay cocode 
        word. The cocycle of the Parker loop is given by:

             cocycle(v1,v2) =   scalar(theta(v1), v2)
        
        with  scalar(.,.) the scalar product.
        """
        return cls.theta_table[v1 & 0x7ff] & 0xfff

    @classmethod
    def ploop_cocycle(cls, v1, v2):
        """Return the cocycle of the Parker loop.

        Then the Parker Loop product is given by

             v1 (*) v2  =  v1 ^ v2 * (-1)**cocycle(v1, v2) . 
        """
        s = cls.ploop_theta(v1) & v2 & 0xfff
        s ^= s >> 6
        s ^= s >> 3
        s = 0x96 >> (s & 7)
        return s & 1 


    @classmethod
    def mul_ploop(cls, v1, v2):
        """Return the Parker loop product v1 (*) v2

        Here v1 and v2 are integers coded as follows:
        bit 0,...,11:   representation as Golay code word
        bit 12:         Parker loop sign
        otther bits:    ignored
        """

        return v1 ^ v2 ^ (cls.ploop_cocycle(v1, v2) << 12)


    @classmethod
    def pow_ploop(cls, v1, u_exp):
        """Return power v1 ** u_exp of the Parker loop element v1."""
        return (v1 & -(u_exp & 1)) ^ (
             cls.theta_table[v1 & 0x7ff] & ((u_exp & 2) << 11) )


    @classmethod
    def ploop_comm(cls, v1, v2):
        """Return commutator of Golay code word v1 and v2.

        This is 0 if the intersection of the vectors v1 and v2 has
        bit weight 0 mod 4 and 1 is that intersection has bit weight 
        2 mod 4. v1 and v2 are in 'gvect' or 'ploop' representation.
        """
        cap = cls.gcode_to_vect(v1) & cls.gcode_to_vect(v2)
        return (cls.bw24(cap) >> 1) & 1

    @classmethod
    def ploop_assoc(cls, v1, v2, v3):
        """Return associator of Golay code words v1, v2 and v3
 
        This the parity of the intersection of the vectors v1, v2 and 
        v3.  v1, v2 and v3 are in 'gvect' or 'ploop' representation.
        """
        assoc = (cls.gcode_to_vect(v1) & cls.gcode_to_vect(v2)
                & cls.gcode_to_vect(v3))
        return cls.bw24(assoc) & 1


    @classmethod
    def ploop_cap(cls, v1, v2):
        """Return intersection of two Golay code words as cocode word.

        v1 and v2 are in 'gvect' or 'ploop' representation, the result
        is returned in 'cocode' representation.
        """
        return ( cls.theta_table[(v1 ^ v2) & 0x7ff] 
                  ^  cls.theta_table[v1 & 0x7ff] 
                  ^  cls.theta_table[v2 & 0x7ff]  ) & 0xfff

    @classmethod
    def ploop_solve(cls, a):
        """Return cocode element that kills signs of Parker loop elements
 
        Here 'a' is an array of Parker loop elements. The function tries 
        to find a cocode element that makes all these Parker loop 
        elements positive, when operating on them as a diagonal 
        automorphism. The function returns the least cocode element in 
        lexical order satisfying that condition. For that order we 
        assume that lower bits have higher valence.
        If no such cocode element exists, ValueError is raised.
        """
        a1 = [x & 0x1fff for x in a]
        basis, columns = pivot_binary_low(a1)
        res = 0
        for b, col in zip(basis, columns):
            res |= ((b >> 12) & 1) << col 

    ###########################################################################
    # Mathieu group M24: conversion between representations
    ###########################################################################
    


    @classmethod
    def perm_complete_heptad(cls, p_io):
        """Complete a permutation p given by p_io to an element of Mat24.

        p must be a list of length 24. Entries p[i], i = 0,1,2,3,4,5,8.
        must make up a valid umbral heptad, i.e. a heptad not contained 
        in an octad. p[0],...,p[5] must be contained in an octad, p[8]
        must not be contained in that octad. The other entries of 
        input p are ignored.

        It can be shown that such a permutation p can be completed to 
        a unique element of Mat24.

        The function returns 0 in case of success and raises ValueError
        otherwise. In case of success, p_io is completed to an element of
        the Mathieu group Mat24. 
        """
        if cls.heptad_completer.complete_heptad(p_io) != 0:
            raise ValueError("Could not complete permutation in Mat24")


    @classmethod
    def perm_check(cls, p1):
        """Check if permutation p1 is in in the Mathieu group Mat24.

        The function returns zero iff this is the case.
        """
        p2 = list(p1[:])
        if  cls.perm_complete_heptad(p2):
             return -1
        return  p2 != list(p1[:])

    @classmethod
    def perm_complete_octad(cls, p_io):
        """Complete an octad given by 6 elements of it. 
        
        This is a simplified version of function 
        perm_complete_heptad().

        We complete an octad from entries p_io[i], i = 0,1,2,3,4,5.
        We store the remaining entries of the octad in p_io[6],
        p_io[7]. The order of these two entries is such that there
        exists a permutation in Mat24 that maps from the (ordered) 
        standard octad  0,...,7  to p_io[0],...,p_io[7].
        If p_io[5] is None, that it is set to the lowest possible
        value such that there is an octad  p_io[0],...,p_io[7].
        """
        assert len(p_io) >= 8
        p = list(p_io[:8]) + [None] * 16
        v = sum([1 << i for i in p[:5]])
        syn = cls.syndrome(v)
        if p_io[5] in (24, None):
            p[5] = cls.lsbit24(syn)
        p[8] = cls.lsbit24((v | syn) ^ 0xffffff)
        cls.perm_complete_heptad(p)
        p_io[6:8] = p[6:8]

    @classmethod
    def perm_from_heptads(cls, h1, h2):
        """Try to find a permutation p that maps heptad h1 to h2

        h1 and h2 must be lists of length 7 defining two umbral heptads,
        i.e. heptads not contained in an octad. If a permutation p in
        the Mathieu group Mat24 that maps h1 to h2 exists, it is unique. 

        The function returns p if such a p exists an is unique and
        it returns None otherwise.
        """
        return cls.heptad_completer.perm_from_heptads(h1, h2)

    @classmethod
    def m24num_to_perm(cls, u_m24):
        """Return permutation with number u_m24 in the Mathieu group Mat24.

        The inverse of this function is member function Mat24_perm_to_int()
        This is just a short and convenient way to number elements of Mat24.
        Input u_m24 = 0 gives the identity permutation.

        0 <= u_m24 < 244823040 = order(Mat24) must hold.

        For internal operation see
        mat24Heptad.HeptadCompleter.int_to_perm
        """
        p = cls.heptad_completer.int_to_perm(u_m24)
        return p

    @classmethod
    def perm_to_m24num(cls, p1):
        """Convert permutation p1 in the Mathieu group Mat24 to an integer.

        This reverses member function int_to_perm(). The input permutation
        is not checked.
        """
        return cls.heptad_completer.perm_to_int(p1[:])
            

    @classmethod
    def perm_to_matrix(cls, p1):
        """Convert a permutation p1 in  Mat24 to a matrix.

        The matrix is a 12 x 12 bit matrix acting on the Golay code
        vectors by right multiplication.

        Permutation p is not checked to be a member of the Mathieu group.
        """
        mat = [cls.recip_basis[p1[i]] >> 12 for i in range(24)]
        return bit_mat_mul(cls.basis[12:], mat)


    @classmethod
    def matrix_to_perm(cls, m1):
        """Convert element of Mat24 from matrix to permutation.

        The matrix m1 is a 12 x 12 bit matrix acting on the Golay code
        vectors by right multiplication. The matrix is not checked.
    
        The permutation is represented as a list.
        """
        basis = [cls.gcode_to_vect(v & 0xfff) for v in m1]
        return cls.matrix_to_perm_.compute(basis)


    #####################################################################
    # Mathieu group M24: operation of group elements
    #####################################################################

    @classmethod
    def op_vect_perm(cls, v1, p1):
        """Apply a permutation p1 to a vector v1 in GF(2)**24

        Here p1 is the permutation that maps i to p1[i]  for i=0,...,23.
        """      
        return sum([ ((v1 >> i) & 1) << p1[i] for i in range(24) ])


    @classmethod
    def op_gcode_matrix(cls, v1, m1):
        """Apply the 12 x 12 bit matrix m1 to a Golay code vector

        Here application means right multiplication v1 * m1. The code
        vector v1 is given in 'gcode' representation.
        """    
        return reduce(
                __xor__, [x for i,x in enumerate(m1) if v1 & (1<<i)], 0 )


    @classmethod
    def op_gcode_perm(cls, v1, p1):
        """Apply a permutation p1 to a Golay code vector v1
  
        Here p1 is the permutation that maps i to p1[i] for i=0,...,23,
        representing an element of the Mathieu group M24.
        
        Golay code vector v1 is given in gcode representation.
        """    
        v1 = cls.gcode_to_vect(v1)
        v1 = cls.op_vect_perm(v1, p1)
        return  cls.vect_to_vintern(v1) >> 12


    @classmethod
    def op_cocode_perm(cls, c1, p1):
        """Apply a permutation p to a Golay cocode vector c1

        Here p1 is the permutation that maps i to p1[i]  for i=0,...,23,
        representing an element of the Mathieu group M24.

        Golay cocode vector c1 is given in cocode representation.
        """
        v = c1
        y = - (((v >> 11) + 1) & 1)          # y = 0 if v is odd else -1
        v ^= cls.recip_basis[0] & y         # make v odd
        res = cls.recip_basis[p1[0]] & y     # .. and adjust result
        syn = cls.syndrome_table[v & 0x7ff ]  # get syndrome
        res ^=  cls.recip_basis[p1[syn & 31]] # do 1st syndrome vector
        syn = (syn >> 5) & 0x3ff             # mask out 2nd, 3rd synd. vector
        syn &=  ((syn + 0x100) >> 10) - 1    # kill syn if v >= 24*32
        res ^=  cls.recip_basis[p1[syn & 31]] ^ cls.recip_basis[p1[syn >> 5]]
                                             #  do 1st and 2nd syndrome vector
        return res & 0xfff


    @classmethod
    def mul_perm(cls, p1, p2):
        """Return p1 * p2, with p1, p2 in the Mathieu group M24

        p1, p2 are represented as permutations
        """
        return [ p2[p1[i]] for i in range(24) ]
 
    @classmethod
    def inv_perm(cls, p1):
        """Return inverse of p1, with p1 in the Mathieu group M24

        p1, is represented as a permutations
        """
        l = [None] * 24
        for i, x in enumerate(p1): l[x] =  i
        return l

             
    ###########################################################################
    # Automorphisms of the Parker Loop
    ###########################################################################



    @classmethod
    def autpl_set_qform(cls, m_io):
        """Recompute quadratic form on Parker loop automorphism m_io

        This functions augments the Parker loop automorphism m_io by
        a quadratic form qf. The form qf simplifies the application
        of m_io to Parker loop elements and also the multiplication
        of  Parker loop automorphisms. The form qf is stored in bits
        13,...,24 of the entries of m_io. 

        At present the documatation of the mathematical background
        behind that form is out of the scope of the module.
        """
        for i in range(12):
            qq = cls.ploop_theta(1 << i) & ((1 << i) - 1)
            s = cls.ploop_theta(m_io[i])
            for j in range(i):
                t =  s & m_io[j] 
                t ^= t >> 6
                t ^= t >> 3
                qq ^= ((0x96 >> (t & 7)) & 1) << j
            m_io[i] = (m_io[i] & 0x1fff) ^ (qq << 13)
        return m_io

    @classmethod
    def perm_to_autpl(cls, c1, p1):
        """Combine Mat24 and cocode element to Parker loop automorphism

        Given an element p1 of the Mathieu group Mat24 (in permutation 
        representation) and a Golay cocode element c1 (in cocode 
        representation), the function returns a Parker loop automorphism 
        m as a 12 x (12+13) matrix, i.e. in 'autpl' representation.
        m contains the 12 images of the basis vectors of the Parker loop
        and a quadratic form for simplfying its operation on Pl.
        """
        m = cls.perm_to_matrix(p1)
        for i in range(12):
            m[i] ^= ((c1 >> i) & 1) << 12
        return  cls.autpl_set_qform(m)

    @classmethod
    def cocode_to_autpl(cls,  c1):
        """Convert cocode element c1 to Parker loop automorphism

        Same as perm_to_autpl(c1, p), with p the identity permutation
        """
        return [(1 << i) + (((c1 >> i) & 1) << 12) for i in range(12)]

    autpl_to_perm = matrix_to_perm 

    @classmethod
    def autpl_to_cocode(cls, m1):
        """Extract cocode vector c from Parker loop automorphism m1

        Then m1 = perm_to_autpl(c, p), where p is the permutation
        obtained by calling autpl_to_perm(m1).

        Note that m1 = cocode_to_autpl(c) *  perm_to_autpl(0, p).
        """
        return sum( ((m1[i] >> 12) & 1) << i for i in range(12) )
       

    @classmethod
    def op_ploop_autpl(cls, v1, m1):
        """Apply Parker loop automorphism m1 to Parker Loop element v1

        Here m1 is a Parker loop autmorphism (in autpl representation)
        and v1 is a cocde vector (in cocode representation).
        The function returns the resluting cocode vector  v1 * m1.
        """
        v = v1
        t = v & 0x1000
        for i in range(12):
            t ^= m1[i] & -((v >> i) & 1) 
        v = (t >> 13) & v 
        v ^= v >> 6
        v ^= v >> 3 
        v = (0x96 >> (v & 7)) & 1
        return (t & 0x1fff) ^ (v << 12)

    @classmethod
    def mul_autpl(cls, m1, m2): 
        """Return product m1 * m2 of Parker loop automorphisms m1, m2

        Here  m1, m2  and the result is in 'autpl' representation.
        """
        m3 = [cls.op_ploop_autpl(m1[i], m2) for i in range(12)]
        return cls.autpl_set_qform(m3)

    @classmethod
    def inv_autpl(cls, m1): 
        """Return inverse of Parker loop automorphism m1

        Here m1 and the inverse of it is in 'autpl' representation.
        """
        p = cls.matrix_to_perm(m1)
        p = cls.inv_perm(p)
        mi = cls.perm_to_matrix(p)
        m0 = cls.mul_autpl(mi, m1)
        for i in range(12):
            assert mi[i] & -0x1000 == 0, map(hex, mi)
            assert m0[i] & 0xfff == 1 << i
            mi[i] ^= m0[i] & 0x1000
        return cls.autpl_set_qform(mi)

    @classmethod
    def perm_to_iautpl(cls, c1, p1):
        """Return (inverse of p1, inverse of element of perm_to_autpl(c1, p1))
     
        This will be optimized in the fast version.  
        """
Beispiel #8
0
def mat24_perm_to_int(p1):
    """Convert permutation p1 in the Mathieu group Mat24 to an integer.

    This reverses member function mat24_int_to_perm(). The input 
    permutation is not checked.

    The function returns an undefined integer if permutation
    p1 is not in the Mathieu group.
    """
    # We reverse to operation of function ``mat24_int_to_perm``.
    # We compute the digits of the result n in mixed-radix
    # representation as described in function ``mat24_int_to_perm``.
    # Digits are taken from the images p1[m], m = 0,1,2,3,4,5,8 in 
    # that order.
    # Get first digit k from p1[0]
    n = k = p1[0]
    # We also accumulate the images p1[0],...,p1[4] in a bitmap
    bitmap = 1 << k

    # For obtaining the next digits n_m from  p1[m], m = 1,2,3, we
    # put  n_m = p1[m] - d[m]. Here d[m] is a difference that must 
    # be subtracted n_m in order to ensure 0 <= n_m < 24-m.
    # Computation of d[m] is a bit tricky. We keep the array 
    # d[m], 0 <= m < 24 in the 64-bit integer d as a bit field, 
    # reserving two bits at positions 2*m, 2*m+1 for d[m]. After
    # selecting the image k = p1[m], we put n_m = k - d[k]. Then we
    # have to replace d[u] by d[u + 1] + 1 for u > k. We don't 
    # change d[u] for u < k. Since a permutation has no repetitions, 
    # we may ignore d[k]. We start with d[u] = 0 for all u. 
    # After putting n_0 = p1[0], we put d[u] = 1 for u >= n_0.  
    d = DFIELD1 << (2*k)
    for i in [23, 22, 21]:
        # Store current entry of p1 in k and adjust bitmap
        k = p1[24-i]
        bitmap |= 1 << k 
        # Set digit n_k = k - d[k] and compute next step for n
        n = i * n + k - ((d >> (2*k)) & 3)
        # Adjust bit field d: replace d[u] by d[u + 1] + 1 for u >= k.
        # Unfortunately, we would get an overflow in the last round. So
        # in the last round we replace replace d[u] by d[u + 1] instead,
        # and we remember the last value k in the variable ``last``.         
        if i > 21:
            d += DFIELD1 << (2*k) 
        else:
            last = k

    # Obtain digit n_4 from p[4]. This works in the same way as
    # assigning the previous imgaes; but here we have to increment
    # d[k] by one in case  k >= last.
    k = p1[4]
    bitmap |= 1 << k 
    n = 20 * n + k - ((d >> (2*k)) & 3) - (k >= last)

    # Now we have obtained the the digis n_m, 0 <= m < 5, from the
    # images p[m], 0 <= m < 5. An we have computed the bitmap of these 
    # images in ``bitmap``.  Next we compute the syndrome of these five
    # images in ``syn``. Here integer ``syn`` is to be interpreted as a 
    # list of three bit fields of length 5. Each field contains an 
    # entry of the syndrome. These entries are ordered. 
    # Also let syn1 = syn[1] be the middle entry of that list.
    cocode = gc.vect_to_cocode(bitmap)
    syn = gc.syndrome_table[cocode & 0x7ff]
    syn1 = (syn >> 5) & 31

    # Compute next digit n_5 = k from p[5]. Put k = 2 if p1[5] > syn1,
    # k = 1 if p1[5] == syn1, and  k = 0 if p1[5] < syn1.
    k = int(p1[5] > syn1) + int(p1[5] >= syn1)
    # Enter that digit into the accumulated value n
    n = 3 * n + k

    # Enter all entries of the syndrome into the bitmap
    bitmap |= (1 << (syn & 31)) | (1 << syn1)
    bitmap |= (1 << ((syn >> 10) & 31))

    # Delete all bits at positions >= p1[8] from the bitmap. The the
    # last digit of n ist the bit weight of that bit map.
    d = gc.bw24(((1 << p1[8]) - 1) & bitmap)
    # Enter the last digit into n
    n = 16 * n + p1[8] - d
    # Change n to zero if it is too large
    n & ((n >= MAT24_ORDER) - 1); 
    return n
Beispiel #9
0
def mat24_int_to_perm(n):
    """Return the k-th permutation in the Mathieu group Mat24   

    Here the elements of the Mathieu group Mat24 are numbererd
    in lexicographic order, starting with 0. 

    This is a fast version of function ``py_mat24_int_to_perm``.
    There is also a C version of this function. 
    """
    # See function ``py_mat24_int_to_perm`` for a simpler implementation
    # We document the tricks used to accelerate that implementation.
    assert 0 <= n < MAT24_ORDER
    # Compute the output permutation in ``p``
    p = [None] * 24

    # Compute ``n1`` such that ``k = n1 >> SH`` is the current digit in 
    # the mixed-radix representation of n as described in function    
    # ``py_mat24_int_to_perm``. For obtaining the next digit we subtract
    # k << SH from ``n1`` and then we  multiply ``n1`` by ``i``, 
    # for i = 23, 22, 21, 20, 3, 16 in that order. 
    n1 = FACTOR24 * n
    # Let k be the first digit of n. Store this in p[0] 
    p[0] = k = n1 >> SH  
    n1 -= k << SH      # process n1 for next digit
    # We also accumulate the images p[0],...,p[4] in a bitmap
    bitmap = 1 << k

    # For assigning the next images p[m], m = 1,2,3, we take the
    # m-th digit n_m from n and we put p[m] = n_m + d[m]. Here d[m]
    # is a difference that must be added to  n_m in order to avoid
    # repetitions in the images of p[m], 0 <= m < 5.  
    # Computation of d[m] is a bit tricky. We keep the array 
    # d[m], 0 <= m < 24 in the 64-bit integer d as a bit field, 
    # reserving two bits at positions 2*m, 2*m+1 for d[m]. After
    # selecting the image k = n_m, we put p[m] = k + d[k]. Then we
    # have to replace d[u] by d[u + 1] + 1 for u >= k. We don't 
    # change d[u] for u < j. We start with d[u] = 0 for all u. 
    # After putting p[0] = k, we put d[u] = 1 for u >= k.  
    d = DFIELD1 << (2*k)
    for i in [23, 22, 21]:
        # Obtain next digit k of n and adjust n1
        n1 = i * n1
        k = n1 >> SH
        n1 -= k << SH
        # put p[24-i] = j = k  - d[k]
        p[24-i] = j = k + ((d >> (2*k)) & 3)
        # Adjust bit field d: replace d[u] by d[u + 1] + 1 for u >= k.
        # Unfortunately, we would get an overflow in the last round. So
        # in the last round we replace replace d[u] by d[u + 1] instead,
        # and we remember the last value k in the variable ``last``. 
        mask = (1 << (2*k)) - 1
        if i > 21:
            d = (((d + DFIELD1) >> 2) & ~mask) + (d & mask) 
        else:
            d = ((d >> 2) & ~mask) + (d & mask) 
            last = k
        # Enter the image j into the bitmap
        bitmap |= 1 << j 

    # Assign the image p[4]. This works in the same way as assigning
    # the previous imgaes; but here we have to increment d[k] by one
    # in case  k >= last.
    n1 = 20 * n1
    k = n1 >> SH
    n1 -= k << SH
    p[4] = k + ((d >> (2*k)) & 3) + (k >= last)
    bitmap |= 1 << p[4] 

    # Now we have assigned the images p[m], 0 <= m < 5. An we have 
    # computed the bitmap of these images in ``bitmap``.  Next we 
    # compute the syndrome of these five images in ``syn``. Here
    # integer ``syn`` is to be interpreted as a list of three bit
    # fields of length 5. Each field contains an entry of the
    # syndrome. These entries are ordered. 
    cocode = gc.vect_to_cocode(bitmap)
    syn = gc.syndrome_table[cocode & 0x7ff]

    # Get next digit k from n. Assign the k-th entry of the
    # syndrome to p[5]
    k = (3 * n1) >> SH
    p[5] = (syn >>  (5 * k)) & 31 
   
    # Enter all entries of the syndrome into the bitmap
    bitmap |= (1 << (syn & 31)) | (1 << ((syn >> 5) & 31))
    bitmap |= (1 << ((syn >> 10) & 31))
    # Complement the bitmap. So the bitmap has 16 bits set.
    bitmap ^= 0xffffff

    # Compute ordered list of positions of the bits set in the bitmap    
    j = 0
    p1 = [None] * 24
    for i in range(24):
        p1[j] = i;              # write index i to output pos.
        j += (bitmap >> i) & 1; # increment output pos. if bitmap[i]=1

    # Let k (where k = n % 16) be the last digit of n. Assign the k-th
    # entry of that list to p[8].
    p[8] = p1[n & 15]

    # Now we have assigned p[m], m = 0,1,2,3,4,5,8; and we procceed
    # as in in function ``py_mat24_int_to_perm``.
    mat24_complete_heptad(p)
    return p
Beispiel #10
0
    p_io[23] = lsb24(sALN & ~sACE & ~sJLM);
    return err;

#######################################################################
#######################################################################
# Function based on function complete_heptad()
#######################################################################
#######################################################################


#######################################################################
# Compute the n-th element of the Mathieu group Mat24
#######################################################################


STD_OCTAD = gc.vect_to_octad(0xff)




def split_n_mat24(n):
    """Auxiliary function for function ``py_mat24_int_to_perm``

    This function converts the integer 0 <= n < 244823040 to
    mixed-radix notation with bases [16, 3, 20, 21, 22, 23, 24].
    It returns the list of the 8 corresponding digits, with the
    highest digit first.
    """
    n_list = []
    for d in [16, 3, 20, 21, 22, 23, 24]:
        n, r = divmod(n, d)