def inv_op_unit(self, tag, d, j): if tag == 'X': tag1 = 'X' d1 = d ^ self.lin_d[0] j1 = j sign = (self.sign_XYZ[d] & 1) sign ^= (self.lin_i[0] >> j) & 1 if self.odd: cc = m24.vect_to_cocode(1 << j) sign ^= m24.scalar_prod(d, cc) elif tag in 'ZY': s = self.odd ^ (tag == 'Y') tag1 = 'ZY'[s] s += 1 d1 = d ^ self.lin_d[s] j1 = j sign = (self.sign_XYZ[d] >> s) & 1 sign ^= (self.lin_i[s] >> j) & 1 elif tag == 'T': tag1 = 'T' d1 = d te = self.s_T[d] so_exp = _as_suboctad(self.f, d) assert te & 0x3f == so_exp, (hex(te), hex(so_exp)) j1 = j ^ (te & 0x3f) sign = m24.suboctad_scalar_prod(j, (te >> 8) & 0x3f) sign ^= (te >> 14) & 1 sign ^= m24.suboctad_weight(j) & self.odd & 1 assert ((te >> 15) ^ self.odd) & 1 == 0 else: raise ValueError("Illegal tag " + str(tag)) return sign & 1, tag1, d1, j1
def mul_Tx(tag, octad, sub, g): d = m24.octad_to_gcode(octad) c = m24.suboctad_to_cocode(sub, d) e = g.pl s = m24.ploop_comm(d, e) s ^= m24.scalar_prod(e, c) return s, tag, octad, sub
def test_cocode(): print("") for i in range(200): # Test power map, inveriosn, sign, theta, and conversion to GCode n1 = randint(0, 0x1fff) p1 = PLoop(n1) ccvector = randint(0, 0xffffff) coc = mat24.vect_to_cocode(ccvector) cclist = [i for i in range(24) if (ccvector >> i) & 1] cc1 = Cocode(cclist) cc2 = Cocode(coc) if i < 1: print("\nTesting", GcVector(ccvector), ", cocode =", cc1) assert cc1 == cc2 u = Parity(mat24.scalar_prod(p1.value, cc1.value)) assert p1 & cc1 == u == cc1 & p1 == u * 1 == u + 0 par = Parity(randint(0, 1)) assert cc1 + par == par + cc1 == cc1.value // 0x800 + par assert cc1 % 2 == Parity(cc1) assert len(cc1) == mat24.cocode_weight(cc1.value) if len(cc1) < 4: syndrome = mat24.cocode_syndrome(cc1.value) assert cc1.syndrome().value == syndrome syn_from_list = sum(1 << i for i in GcVector(ccvector).syndrome_list()) assert syn_from_list == syndrome i = randint(0, 23) assert cc1.syndrome(i).value == mat24.cocode_syndrome(cc1.value, i) syndrome_list = cc1.syndrome(i).bit_list assert len(cc1) == len(syndrome_list) assert syndrome_list == mat24.cocode_to_bit_list(cc1.value, i)
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
def mul_Xp(tag, d, i, g): eps, pi, rep = g.cocode, g.perm, g.rep d1 = m24.op_ploop_autpl(d, rep) i1 = pi[i] s = d1 >> 12 if eps & 0x800: # if eps is odd: s ^= m24.scalar_prod(d, m24.vect_to_cocode(1 << i)) s ^= m24.pow_ploop(d, 2) >> 12 return s, tag, d1 & 0x7ff, i1
def __and__(self, other): if import_pending: complete_import() if isinstance(other, GCode): return PLoopIntersection(self, other) elif isinstance(other, Cocode): return Parity(mat24.scalar_prod(self.value, other.value)) elif isinstance(value, GcVector): return GcVector(mat24.gcode_to_vect(self.value) & other.value) else: return NotImplemented
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))
def sign_t_YZ(d, i): return (m24.scalar_prod(d, m24.vect_to_cocode(1 << i)) ^ (m24.pow_ploop(d, 2)) >> 12)
def sign_t_XY(d, i): return m24.scalar_prod(d, m24.vect_to_cocode(1 << i))
def mul_Cy(tag, i, j, g): c = m24.vect_to_cocode((1 << i) + (1 << j)) e = g.pl s = m24.scalar_prod(e, c) tag = C - s return s, tag, i, j
def mul_Ay(tag, i, j, g): c = m24.vect_to_cocode((1 << i) ^ (1 << j)) e = g.pl s = m24.scalar_prod(e, c) if i == j: assert s == 0 return s, tag, i, j
def __and__(self, other): if isinstance(other, GCode): return Parity(mat24.scalar_prod(self.value, other.value)) else: return NotImplemented
def mul_Yy(tag, d, i, g): e = g.pl & 0xfff s = m24.scalar_prod(e, m24.vect_to_cocode(1 << i)) s ^= m24.ploop_comm(d, e) return s, Y, d & 0x7ff, i
def mul_Bx(tag, i, j, g): c = m24.vect_to_cocode((1 << i) ^ (1 << j)) e = g.pl s = m24.scalar_prod(e, c) return s, tag, i, j
def mul_Zx(tag, d, i, g): e = g.pl ed = m24.mul_ploop(m24.pow_ploop(e, 3), d) s = m24.scalar_prod(e, m24.vect_to_cocode(1 << i)) s = (ed >> 12) return s & 1, Z, ed & 0x7ff, i
def mul_Zy(tag, d, i, g): e = g.pl de = m24.mul_ploop(d, e) s = m24.scalar_prod(e, m24.vect_to_cocode(1 << i)) s ^= de >> 12 return s, Z, de & 0x7ff, i
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
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)