def suboctad_type(octad, w, coc): """Return suboctad type. Let ``octad`` be an octad, i.e. a bit vector of length 8. Let w = 1 (mod 2) if ``octad`` denotes an octad and ``w = 0`` if ``octad`` denotes a complemented octad. Let ``coc`` be an even cocode vector in cocode representation. The function returns 0 in bit 1 of the return value if the cocode word ``coc`` can be written as a subset of the octad, and 1 in bit 1 otherwise. the function returns ``1 + w + bit_weight(coc)/2`` in bit 0 of the return value. Then Leech lattice vector ``x_octad + x_coc`` is of subtype 0x22 if the return value is zero. Otherwise it is of subtype 0x44 (or 0x46) if bit 1 of the return value is (or 1). """ lsb = mat24.lsbit24(octad) # ls bit of octad syn = mat24.cocode_syndrome(coc, lsb) # cocode syndrome wsub = octad & syn == syn # wsub = 1 if coc is suboctad cw = mat24.cocode_weight(coc) >> 1 # cw = cocode_weight(v) / 2 return 2 * (1 - wsub) + ((w ^ cw ^ 1) & 1)
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 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)
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 __len__(self): return mat24.cocode_weight(self.value)