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 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 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 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")
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")
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")