def iter_rand_mm(quality): r"""Return a random element of the monster group The function returns a random element of the monster group. Here ``quality`` means a measure for the quality of the randimization process, where a higher value menas that the distribution of the elements is closer to uniform. If ``quality`` is an integer ``k`` then a product containing ``k`` powers of the triality element it generated. Here the default value creates an almost uniform distribution. In future versions the default value of parameter ``quality`` may correspond to the generation of a truly uniform distribution. """ a = np.zeros(10, dtype=np.uint32) seed = rand_get_seed() len_a = xsp2co1_rand_word_G_x0(a, seed) if not 0 <= len_a <= 10: raise ValueError(ERR_RAND_INTERN) yield from a[:len_a] for k in range(quality): yield 0x50000001 + gen_rng_modp(2, seed) c = 0 while gen_leech2_type(c) != 4: c = gen_rng_modp(0x1000000, seed) len_a = gen_leech2_reduce_type4(c, a) mm_group_invert_word(a, len_a) if not 0 <= len_a <= 6: raise ValueError(ERR_RAND_INTERN) yield from a[:len_a]
def invariant_type(g): iv, _1, ortho = Xsp2_Co1(g)._involution_invariants() iv_len = 12 while iv_len and iv[iv_len - 1] == 0: iv_len = iv_len - 1 v0, v1 = (int(iv[0]) >> 24) & 7, (int(iv[1]) >> 24) & 7 ct2 = invariant_count_type2(iv) return iv_len, v0, v1, gen_leech2_type(ortho), ct2
def type2_ortho_testdata(ntests): """Yields special type-2 vectors in the Leech lattice mod 2 These type-2 vectors are orthogonal to the vector BETA in the real Leech lattice and given in **Leech lattice encoding**. """ for v in type2_testdata(2 * ntests): if gen_leech2_type(v ^ BETA) == 4: yield v
def type(self): r"""Return the type of the element of :math:`Q_{x0}`. This is equal to the type of the corresponding vector :math:`v` in the Leech lattice :math:`\Lambda` modulo 2. The type of a vector :math:`v \in \Lambda / 2 \Lambda` is the halved norm of the shortest vector in the set :math:`v + 2 \Lambda`. That type is equal to 0, 2, 3 or 4. """ return gen_leech2_type(self.value)
def xsp2xco1_v2type(vtype): global v2_types try: return xsp2xco1_xsp2(v2_types[vtype]) except KeyError: assert vtype in [2, 3, 4] for i in range(10000): v = randint(0, 0xffffff) if gen_leech2_type(v) == vtype: v2_types[vtype] = xsp2xco1_xsp2(v) return v2_types[vtype] raise ValueError("No Leech lattice vector of type", vtype)
def type_Q_x0(self): r"""Return type of element if it is in the subgroup :math:`Q_{x0}` If the element is in the subgroup :math:`Q_{x0}` of the monster then the function returns the type of the vector in the Leech lattice modulo 2 corresponding to this element. That type is 0, 2, 3, or 4. The function raises ValueError if the element is not in the subgroup :math:`Q_{x0}`. """ v = self.as_Q_x0_atom() return gen_leech2_type(v)
def rand_xleech2_type(vtype): if vtype in [3, 4]: for i in range(1000): v = randint(0, 0x1ffffff) if gen_leech2_type(v) == vtype: return v raise ValueError(ERR_XL_RAND) if vtype == 0: return 0 if vtype == 2: ve = randint(300, 98579) vs = mm_aux_index_extern_to_sparse(ve) sign = randint(0, 1) return mm_aux_index_sparse_to_leech2(vs) ^ (sign << 24) raise ValueError(ERR_XL_RAND)
def test_reduce_type_4(ntests=500, verbose=0): """Test function ``reduce_type4`` """ for n, v in enumerate(type4_testdata(ntests)): if verbose: print(" \nTest %d, v = %s, subtype =%s" % (n + 1, hex(v), hex(gen_leech2_subtype(v)))) op = reduce_type4(v, verbose) w = gen_leech2_op_word(v, op, len(op)) assert w & 0xffffff == 0x800000, hex(w) if gen_leech2_type(v ^ BETA) == 2: b = gen_leech2_op_word(BETA, op, len(op)) assert b & 0xffffff == BETA, hex(b) a = np.zeros(6, dtype=np.uint32) l = gen_leech2_reduce_type4(v, a) if l < 0: err = "Error %s in function gen_leech2_reduce_type4" raise ValueError(err % hex(l & 0xffffffff)) a = a[:l] assert list(a) == list(op), ((a), (op))
def find_type4_testcases(ncases = 1): data = [ ([0x800000, 0x800700, 0], 0, 0x800000), ] for a, v2, v_best in data: yield np.array(a, dtype = np.uint32), v2, v_best for i in range(500): a = [rand_type_40_vector()] + [randint(0x1000, 0x7fffff) for i in range(4)] best = a[0] if gen_leech2_type(a[0]) == 4 else None shuffle(a) yield np.array(a, dtype = np.uint32), 0, best lengths = list(range(20, 100, 3)) + list(range(2000, 2100,7)) for i in lengths: a = np.random.randint(0, 0xffffff, i, dtype = np.uint32) yield a, 0, None for i in range(1000): v2, a = rand_type2_type4_list(3, 5) yield a, v2, None
def iter_c(tag, r): if isinstance(r, str): if r == 'r': c = rand_type4_vector() else: raise ValueError(ERR_LEECH2) elif isinstance(r, Integral): c = r & 0xffffff else: try: c = r.as_Q_x0_atom() assert isinstance(c, Integral) except: raise TypeError(ERR_LEECH2) if gen_leech2_type(c) != 4: raise ValueError(ERR_LEECH2) a = np.zeros(6, dtype=np.uint32) len_a = gen_leech2_reduce_type4(c, a) mm_group_invert_word(a, len_a) yield from a[:len_a]
def check_leech2_subtype(x, t_expected): """Test computation of subtype of vector in Leech lattice mod 2 Given a vector ``x`` in the Leech lattice mod 2 in **Leech lattice encoding**, the function checkse if the subtype of ``x`` is correctly computed as the value ``t_expected``. Therefore it computes the subtype with function ``gen_leech2_subtype`` in file ``gen_leech.c`` and checks it against ``subtype``. This function also checks function ``gen_leech2_type2``. """ t = gen_leech2_subtype(x) ok = t == t_expected if not ok: print("Error: expected Leech type: %s, obtained: %s" % (hex(t_expected), hex(t))) display_leech_vector(x) err = "Error in computing Leech type" raise ValueError(err) expected_type2 = t_expected if (t_expected >> 4) == 2 else 0 found_type2 = gen_leech2_type2(x) ok = expected_type2 == found_type2 if not ok: print("Error: x = %s, Leech type: %s" % (hex(x), hex(t_expected)), expected_type2, hex(found_type2)) err = "Function gen_leech2_subtype2 failed" raise ValueError(err) alt_found_type2 = alternative_type2(x) is_type2 = (t_expected >> 4) == 2 ok = is_type2 == alt_found_type2 if not ok: print("Error: x = %s, Leech type: %s" % (hex(x), hex(t_expected)), is_type2, alt_found_type2) err = "Function xsp2co1_leech2_count_type2 failed" #raise ValueError(err) if not is_type2: assert not found_type2 assert gen_leech2_type(x) == t >> 4
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 eval_type4(v, v2 = 0): value = VALUE_T4[gen_leech2_subtype(v)] if v2 & 0xffffff and gen_leech2_type(v ^ v2) != 2: value = 5 return min(0x5000000, (v & 0xffffff) + (value << 24))
def do_test_involution_invariants(g, ref_invariants, verbose=0): errors = 0 error_text = None def check(condition, bit, text=None): nonlocal errors, error_text if not condition: errors |= 1 << bit if not error_text: error_text = text g.reduce() if verbose: print("g =", g) gg = Xsp2_Co1(g) ref_ord, ref_chi, ref_involution_invariants = ref_invariants ref_chi = ref_chi[:4] invar, v1, v0 = gg._involution_invariants() ## invar[0] = int(invar[0]) & 0x3ffffff # this produces an error errors = 0 check(ref_ord[0] == gg.order(), 0, "order of g") check(ref_ord[1] == XLeech2(gg**2).type, 1, "order of g**2") check(ref_chi == g.chi_G_x0(), 2, "characters of g") if int(invar[0]) & 0x8000000: check((gg**2).in_Q_x0(), 3, "Invariant in involution") check((int(invar[0]) >> 24) & 7 == ref_involution_invariants[1], 4, "invar[0]") check((int(invar[1]) >> 24) & 7 == ref_involution_invariants[2], 5, "invar[1]") check( gen_leech2_type(v0) == ref_involution_invariants[3], 6, "leech2_type") check( invariant_count_type2(invar) == ref_involution_invariants[4], 7, "type-2 vector count") invar = [int(x) for x in invar if int(x)] check( len(invar) == ref_involution_invariants[0], 8, "length of invariants") for i, x in enumerate(invar[2:]): check(x & 0xff000000ff000000 == 0, 9, "bits in invaraiant[%d]" % i) data = [x for x in invar if (x >> 26) & 1 == 0] pre_data = [x for x in invar if (x >> 26) & 1 == 1] preimages = [x >> 32 for x in data] images = [x & 0x1ffffff for x in data] g_images = [x for x in gg.xsp_conjugate(list(preimages))] g_images2 = [x for x in gg.xsp_conjugate(list(images))] zipp = zip(preimages, images, g_images, g_images2) if verbose: print("Involution invariants found (length = %d)" % len(invar)) if len(pre_data) == 1: pre_l = [int(pre_data[0]) >> 24, int(pre_data[0]) & 0xffffff] print("Prefix line", [hex(x) for x in pre_l]) print(", ".join(["preimage", "image", "g_image", "g_image2", "t"])) for i, (preim, im, g_im, g_im2) in enumerate(zipp): t = preim ^ im ^ g_im if verbose: print([hex(x) for x in (preim, im, g_im, g_im2, t)]) check((preim ^ im ^ g_im) & 0xffffff == 0, 10, "(preimage ^ image ^ g_image)[%d]" % i) check(g_im2 == im & 0xffffff, 11, " g_image[%d]" % i) # test conjugation istate = invariant_status(ref_invariants) v = xsp2co1_elem_find_type4(gg._data, 0) if not errors: if ref_chi[0] in (196883, 275, 4371): # The g is of type 1A, 2B or 2A in the monster check(istate >= 2, 12, "istate (= %s)" % istate) if not errors: if istate == 0: check(v <= 0, 13, "xsp2co1_elem_find_type4(), succeeded but should not") else: check(v > 0, 14, "xsp2co1_elem_find_type4() not successful") mv = MM0("c", v)**-1 h = g**mv if errors == 0 and istate > 1: check(h.in_N_x0(), 15, "conjugating element to N_x0, h=" + str(h)) if not errors: h1 = conj_G_x0_to_Q_x0(g) ok = (g**h1).in_Q_x0() check(ok, 16, "conjugating element to Q_x0") if not errors and istate == 3: _, a = gg.conjugate_involution(MM0) check(g**a == Z, 17, "conjugating element to centre of Q_x0") if errors: print("\nError in testing involution invariants") print("\nError status =", hex(errors)) if error_text: print("Error in " + error_text) print("g =", g) print("g as an instance of Xsp2_Co1:") for i in range(26): print(" 0x%016x" % gg.data[i]) print("istate =", istate) print("Expected Invariants:", ref_invariants) print("Conjugtion status expected:", istate) print("Conjugation vector:", hex(v)) print("Involution invariants obtained") for i, x in enumerate(invar): print("%2d: 0x%014x" % (i, x)) length = ref_invariants[2][0] if 8 <= length <= 9: coset = ref_invariants[2][4] > 0 _invar = np.array(invar + [0] * 12, dtype=np.uint64) v1 = xsp2co1_involution_find_type4(_invar, coset) print("Low level conjugation vector:", hex(v1)) try: from mmgroup.clifford12 import xsp2co1_involution_error_pool error_pool = np.zeros(64, dtype=np.uint64) length = xsp2co1_involution_error_pool(error_pool, len(error_pool)) if length: s = "Error pool from function xsp2co1_involution_invariants" print(s) for i, x in enumerate(error_pool[:length]): print("%2d: 0x%014x" % (i, x)) except: pass err = "Error in involution invariants" raise ValueError(err)
def rand_type4_vector(): c = 0 while gen_leech2_type(c) != 4: c = randint(0, 0xffffff) return c
def leech_type(v2): """Return type of vector ``v2`` in the Leech lattice mod 2""" return gen_leech2_type(v2)