def reduce_testcases(ncases=1000): for i in range(ncases): for complexity in range(15): yield MM0('r', complexity) g = MM0('r', 18) assert len(g.mmdata) > MIN_LEN_ALWAYS_UNREDUCED yield g
def test_elem_to_word(ntests=50, verbose=0): print("Test function test_elem_to_word()") for i, w in enumerate(make_testwords(monomial=False, ntests=ntests)): m = MM0(w) if verbose: print("\nTest %d:" % (i + 1)) print("Testing word\n%s" % m) elem = Xsp2_Co1(w) if i < 100: assert m == MM0(elem) if verbose: print("This is element\n%s" % elem) word = elem_to_word(elem, verbose > 1) if verbose: print("Reduced word\n%s" % MM0('a', word)) elem_1 = Xsp2_Co1('a', word) if verbose: print("Recomputed element\n%s" % elem_1) ok = (elem == elem_1).all() if verbose or not ok: if not ok: print("Instead of to 1, the element reduces to:") print(elem * elem_1**(-1)) err = "WTF" raise ValueError(err) word_C = elem_to_word_C(elem) assert (word_C == word).all(), (word_C, word) word1_C = reduce_word_C(m.mmdata) assert (word1_C == word).all(), (word1_C, word)
def test_cases(verbose = 0): s = "For an axis let A be the symmetric matrix corresponding to part 300x" print(s,"\n") for axis_type, g_str in AXES.items(): if verbose: print("\nTest reduction of axis type %s" % axis_type) text = display_norm_A(axis_type).split("\n") for s in text: if s: print(" " + s) # Construct an axis v of the given axi type v = V_START * MM0(g_str) target_axes = reduce_targets[axis_type] if target_axes is None: if verbose: print(" Reduction terminates here") continue nfound = 0 dict_found = defaultdict(int) for w in reduce_cases[axis_type](v, verbose): if leech_type(w) != 4: continue nfound += 1 v1 = v * MM0('c', w)**(-1) ok = False for e in [1,2]: t_axis_type = v1.axis_type(e) if t_axis_type in target_axes: ok = True dict_found[t_axis_type] += 1 assert ok assert nfound > 0 if verbose: if len(dict_found): print(" Reduced to axis types", dict(dict_found))
def test_monomial_to_word(ntests=10, verbose=0): print("Test function test_monomial_to_word()") for i, w in enumerate(make_testwords()): if verbose: print("\nTest %d:" % (i + 1)) m = MM0(w) print("Testing word\n%s" % m) elem = Xsp2_Co1(w) if verbose: print("This is element\n%s" % elem) data_i = monomial_to_word(elem, verbose > 1) elem_0 = elem.copy().mul_data(data_i) try: x = elem_0.as_xsp() ok = True except: raise ok = False if verbose or not ok: m_i = MM0("a", data_i) print("Reduced inverse word\n%s" % str(m_i)) if not ok: print("Product with inverse\n%s" % elem_0) err = "WTF" raise ValueError(err) else: print("Result is:", hex(x)) print("Test %d ok" % (i + 1)) data_C = monomial_to_word_C(elem) assert (data_C == data_i).all(), (data_C, data_i)
def test_2A_axes_classes(verbose=0): """Test computation of samples classes of 2A axes. If this function is called with parameter ``verbose == 1`` then function displays the information relevant for distinguishing between classes of 2A axes. """ do_test_baby_sample_axes(baby_sample_axes) do_test_sample_axes(sample_axes) if verbose: print(HEADER) NUM_AXES = len(sample_axes.g_strings) for i in range(NUM_AXES): # sorted_axes(sample_axes): g = MM0(sample_axes.g_strings[i]) v = MMVectorCRT(20, sample_axes.v_start) v *= g g1 = MM0(sample_axes.g_beautifiers[i]) v *= g1 Afloat = 256 * v["A"] A = np.array(Afloat, dtype=np.int32) assert (A == Afloat).all() if verbose: class_ = sample_axes.g_classes[i] print("\nClass " + class_, end=", ") print("stage = " + str(sample_axes.g_stages[i]), end="") powers = sample_axes.powers[i] s_powers = ", powers: " + powers if len(powers) else "" print(s_powers) print("Automorphism group:", sample_axes.groups[i]) print(display_norm_A(i), end="") print("Eigenvalues", block_eigenvalues(A)) display_A(A)
def one_test_reduce(g, verbose=0): g1 = MM0(g) g2 = MM(g).reduce() if verbose: print(g1) print(g2) if len(g1.mmdata) > MIN_LEN_ALWAYS_UNREDUCED: assert len(g2.mmdata) < len(g1.mmdata) assert MM0(g2) == g1
def beautify_after_signs_10B(A): for i in (5, 6): if A[1, i] < 0: src = [7, 5, 6] if i == 6 else [6, 7, 5] src = [0, 1, 2, 3, 4] + src dest = list(range(7)) #return MM0() return MM0('p', AutPL(0, zip(src, dest), 0)) return MM0()
def beautify_block_size3(A): """Try to order a matrix with a 3 times 3 block If matrix ``A`` has a 3 times 3 block in rows 0, 1, and 2, then the function checks the diagonal entries with index >= 3. It looks for a set of equal diagonal entries such that the union of the indices of these entries with the set [1,2,3] is an octad. If this is the case then the function returns an element ``g`` that that moves this octad to the first 8 rows and columns. In case of success that element is returned as an instance of class ``MM0``. Otherwise the neutral element in class ``MM0`` is returned. """ bl = blocks(A) if mat24.bw24(bl[0]) != 3: return MM0() blist = [x for x in range(24) if bl[0] & (1 << x)] if (blist != [0, 1, 2]): return MM0() d = defaultdict(list) for b in bl: if b & (b - 1) == 0: index = b.bit_length() - 1 d[A[index, index]].append(index) for lst in d.values(): if len(lst) < 8: try: gc = GCode(blist + lst).bit_list assert len(gc) == 8 except: continue isect = set(blist) & set(gc) #print("isect", isect) if len(isect) == 3: src0 = [x for x in gc if x in isect] src1 = [x for x in gc if not x in isect] dest = range(6) pi = AutPL(0, zip(src0 + src1[:3], dest), 0) return MM0(pi) if len(isect) == 1: src = gc dest = list(range(8)) src0 = [x for x in gc if not x in isect] src1 = [x for x in gc if x in isect] src2 = [x for x in blist if x not in src1] dest = list(range(10)) for i in range(1000): shuffle(src0) shuffle(src2) try: pi = AutPL(0, zip(src0 + src1 + src2, dest)) return MM0(pi) except: pass return MM0()
def conj_G_x0_to_Q_x0(g): gg = Xsp2_Co1(g) a = np.zeros(7, dtype=np.uint32) lv = chk_qstate12(xsp2co1_elem_conj_G_x0_to_Q_x0(gg._data, a)) length, q = lv >> 25, lv & 0x1ffffff h = MM0('a', a[:length]) gh = MM0(g)**h assert gh.in_Q_x0() assert gh == MM0('q', q) return h
def test_axes(): for key in AXES: v = V(*START_AXIS) * MM0(AXES[key]) assert v.axis_type() == key for i in range(20): w = v * MM0('r', 'G_x0') assert w.axis_type() == key if (i > 5): continue e = randint(1, 2) we = w.axis_type(e) assert isinstance(we, str)
def beautify_block_size2(A): """Try to order a matrix with 2 times 2 block If matrix ``A`` has 2 times 2 blocks then the function checks the diagonal entries. It looks for a set of equal diagonal entries such that the union of the indices an octad (up to a syndrome of length at most 3). If this is the case then the function returns an element ``g`` that that moves this octad to the first 8 rows and columns. In case of success that element is returned as an instance of class ``MM0``. Otherwise the neutral element in class ``MM0`` is returned. """ bl = blocks(A) if mat24.bw24(bl[0]) != 2: return MM0() blist = [x for x in range(24) if bl[0] & (1 << x)] d = defaultdict(list) for b in bl: if b & (b - 1) == 0: index = b.bit_length() - 1 d[A[index, index]].append(index) for lst in d.values(): if len(lst) <= 8: try: #print(lst) gc = GCode(blist + lst).bit_list #print("GC =", gc) except: continue if set(blist).issubset(gc) and len(gc) == 8: src0 = [x for x in gc if x in blist] src1 = [x for x in gc if x not in blist] dest = list(range(8)) for i in range(1000): shuffle(src1) try: pi = AutPL(0, zip(src0 + src1, dest), 0) return MM0(pi) except: pass if len(set(blist) & set(gc)) == 0 and len(gc) == 8: src0 = gc src1 = blist dest = list(range(10)) for i in range(10000): shuffle(src0) try: pi = AutPL(0, zip(src0 + src1, dest), 0) return MM0(pi) except: pass return MM0()
def make_axis_testcases(): #V = V_START.space yield V_START.copy(), 1 yield V("I", 11, 9), 1 yield V("I", 11, 9), 0 for i in range(10): yield V_START * MM0("r", "G_x0"), i & 1 for ax in AXES: v0 = V_START * MM0(AXES[ax]) for i in range(20): yield v0 * MM0("r", "G_x0"), i & 1 for quality in range(2, 11): for i in range(3): yield V_START * MM0("r", quality), i & 1
def beautify_diagonal_matrix(A): """Try to order a diagonal matrix If matrix ``A`` is diagonal then the function looks for a set of equal diagonal entries that is close to an octad or to a dodecad. If this is the case then the function returns an element ``g`` that that moves this Golay code word to a standard position. In case of success that element is returned as an instance of class ``MM0``. Otherwise the neutral element in class ``MM0`` is returned. """ bl = blocks(A) if mat24.bw24(bl[0]) != 1: return MM0() d = defaultdict(list) for b in bl: if b & (b - 1) == 0: index = b.bit_length() - 1 d[A[index, index]].append(index) singleton = None for lst in d.values(): if len(lst) == 1: singleton = lst for lst in d.values(): dest = list(range(8)) if len(lst) == 8: #print(lst) for i in range(10000): shuffle(lst) try: pi = AutPL(0, zip(lst, dest), 0) #print("yeah") return MM0(pi) except: continue elif len(lst) == 11 and singleton: print("dodecad") DOD = 0xeee111 dest = [i for i in range(24) if (1 << i) & DOD] src = singleton + lst #print(dest) #print(src) #return MM0() pi = mat24.perm_from_dodecads(src, dest) return MM0('p', pi) elif singleton: pi = pi = AutPL(0, zip(singleton, [0]), 0) return MM0('p', pi) return MM0()
def rand_BM(quality=8): r"""Generate certain 'random' element in the Baby Monster` Let ``v_0`` be the element of the subgroup ``Q_x0`` of ``G_x0`` corresponding to the Golay cocode element ``[2,3]``. The function generates a random element of the centralizer of ``v_0`` in the monster. """ a = MM0() for i in range(quality): a *= rand_Co2() a *= MM0('t', 'r') return a
def try_make_blocks_positive(A, block=0, first_row_only=False, tag='y'): """Make block of matrix ``A`` acting on the Leech lattice positive Here ``block`` is a block of rows of columns of the matrix given as a set of integers. Block may also be a nonzero integer encoding a block in the bits being set in that integer. In case ``block = 0`` (default) we take the largest block, where a block is as in function ``blocks()``. The function tries to compute an integer ``d`` encoding an element of of the Golay code, so that the transfromation with that Golay code element makes all entries of that block nonnegative. In case of success the function returns the element ``return MM0('y', d)`` of the Monster group that changes the signs appropriately. If this fails then the functoion raises ValueError. """ if isinstance(block, Iterable): bl_list = list(block) else: bl = block if block else blocks(A)[0] bl_list = [x for x in range(24) if (1 << x) & bl] row_list = bl_list[:1] if first_row_only else bl_list d = change_signs_A(A, [(bl_list, row_list)]) return MM0(tag, d)
def beautify(axis, verbose=0): if axis.g == MM0(): return axis bl = blocks(axis.A()) if verbose: print("Blocksizes", [bit_count(x) for x in bl]) bl_size = bit_count(bl[0]) if max(bit_count(b) for b in bl) > 3: if bl_size > 5 and verbose: print("vector type:", mat24.vect_type(bl[0])) axis.apply(make_blocks_positive) if len(bl) > 1: axis.apply(beautify_large_block) else: axis.apply(beautify_single_block) bl = axis.blocks() if bit_count(bl[0]) == 8 and bit_count(bl[1]) == 1: axis = beautify_10B(axis) elif bl_size == 3: axis.apply(beautify_large_block) axis.apply(sort_single_size3_block) axis.apply(beautify_block_size3) axis.apply(beautify_signs_size2_3) elif bl_size == 2: axis.apply(beautify_block_size2) axis.apply(beautify_signs_size2_3) elif bl_size == 1: axis.apply(beautify_diagonal_matrix) else: raise ValueError("Beautifying of matrix A failed") beautify_permutation(axis) axis.trim_axis_type() return axis
def test_display_axes(verbose=0): if verbose: print(HEADER) else: print("\nClasses of 2A axes (relative to G_x0):\n") for cl in get_axes(): axis = get_axes()[cl] print("Class:", axis.g_class, ", stage =", axis.stage, ", powers:", axis.powers) print("Automorphism group:", axis.group) print(display_norm_A(axis), end="") print("Eigenvalues of A part of axis v:", eigen(axis.A())) if verbose: n, c = (g_central * axis.reflection()).half_order() print("Half order:", n, ", central involution: ", c) if c: print("Character of central involution:", c.chi_G_x0()) (analyze_xy(c)) print("Axis type of axis v * MM('t',1):", axis.axis_type(1)) print("Dim intersection with Q_x0:", 24 - len(x_equations(axis, 0))) print("Dim intersection with Q_y0:", 24 - len(x_equations(axis, 1))) #print("Dim intersection with Q_z0:", 24 - len(x_equations(axis,2))) opp_axis_type = (v_axis_opp15 * MM0(axis.g)).axis_type() print("Image of opposite axis: ", opp_axis_type) print("A part of axis v:") display_A(axis.A()) print("\nA part of axis v * MM('t', 1):") display_A(axis.Ax()) print("A part of opposite axis v:") display_A(axis.A_opp()) print("")
def test_in_gx0(verbose = 0): print("Testing function check_mm_in_g_x0()") for n, (g, in_g_x0) in enumerate(in_gx0_testdata()): g = MM0(g) if verbose: print("Test", n+1) print("g =", g) g1 = check_mm_in_g_x0(g) if verbose: print("reduced", g1) if g1 is None: r = err_in_g_x0_c print("Reason for non-membership (.c):", r) g1_py = py_check_mm_in_g_x0(g) if verbose: print("reduced (py)", g1_py) if g1_py is None: r = err_in_g_x0_py print("Reason for non-membership (py):", r) if in_g_x0: assert g1_py is not None else: assert g1_py is None if g1_py: assert g == g1_py assert g1 == g1_py #assert g.in_G_x0() == in_g_x0 pass
def get_axes(): global AXES if len(AXES): return AXES for i, g1 in enumerate(sample_axes.g_strings): g2 = sample_axes.g_beautifiers[i] g = MM0(g1) * MM0(g2) g_class = sample_axes.g_classes[i] axis = Axis(g, g_class) axis.mark = sample_axes.g_marks[i] axis.group = sample_axes.groups[i] axis.powers = sample_axes.powers[i] axis.stage = sample_axes.g_stages[i] axis.v15 = v_axis15 * MM0(sample_axes.g_strings[i]) axis.norm15 = mm_op15_norm_A(axis.v15.data) AXES[g_class] = axis return AXES
def rand_Co2(quality=5): r"""Generate certain 'random' element in a subgroup of ``G_x0`` Let ``v_0`` be the element of the subgroup ``Q_x0`` of ``G_x0`` corresponding to the Golay cocode element ``[2,3]``. The function generates a random element of the centralizer of ``v_0`` in ``G_x0``. """ a = MM0() for i in range(quality): pi = rand_pi_mat22() x1 = randint(0, 0xfff) & ~0x200 y1 = randint(0, 0xfff) & ~0x200 e = randint(0, 2) a *= MM0([('p', pi), ('x', x1), ('y', y1), ('l', e)]) return a
def eval_a_ref(v, v2, e=0): if (e % 3): v = v * MM0('t', e) A = np.array(v["A"], dtype=np.int32) v2_sp = mm_aux_index_leech2_to_sparse(v2) v_2 = np.zeros(24, dtype=np.int32) res = mm_aux_index_sparse_to_leech(v2_sp, v_2) return (v_2 @ A @ v_2) % 15
def sort_single_size3_block(A): """Sort entries of matrix with single 3 times 3 block If matrix ``A`` contains a single 3 times 3 block and some diagonal entries the the function returns a permutation that moves the 3 times 3 block to rows and columns 0, 1, and 2. That permutation is returned as an instance of class ``MM0``. Otherwise the function returns the neutral element in class ``MM0``. """ bl = blocks(A) if mat24.bw24(bl[0]) != 3 or mat24.bw24(bl[1]) != 1: return MM0() blist = [x for x in range(24) if bl[0] & (1 << x)] dlist = sorted([(-A[x, x], x) for x in blist]) src = [x[1] for x in dlist] return MM0('p', AutPL(0, zip(src, [0, 1, 2]), 0))
def xsp2co1_fast_half_order(wx): assert isinstance(wx, Xsp2_Co1) buf = np.zeros(10, dtype=np.uint32) m = MM0(wx) res = chk_qstate12(xsp2co1_half_order_word(m._data, m.length, buf)) o, l = divmod(res, 256) assert 0 <= l <= 10 out = Xsp2_Co1() chk_qstate12(xsp2co1_mul_elem_word(out._data, buf, l)) return o, out
def beautify_signs_10B(A): sign_list = [] def sgn(i0, i1, s): t = A[i0, i1] if t * s: sign_list.append((i0, i1, t * s < 0)) for i in range(0, 4): sgn(0, i + 4, +1) for i in range(1, 4): sgn(4, i, -1) #sgn(0, 4, 1) try: y = solve_gcode_diag(sign_list) print("Beautification found in case 10B") return MM0('y', y) except: print("Beautification failed in case 10B") return MM0()
def trim_axis_type(self): t = self.axis_type(0) if self.axis_type(2) != t: self *= MM0('d', 0x800) if self.axis_type(1) != t: Ax = self.Ax() if t in trim_cooctad_required: self *= trim_cooctad(Ax) Ax = self.Ax() if t in positive_blocks: d = change_signs_A(Ax, positive_blocks[t], ignore=True) #if (d): print("d =", d) self *= MM0('x', d) elif t in negative_blocks: d = change_signs_A(Ax, [], negative_blocks[t], ignore=True) if (d): print("d =", d) self *= MM0('x', d) else: self *= make_blocks_positive(Ax, tag='x') return self
def make_involution_samples(): # sample obtained from former error cases NEW_SAMPLES = [ # The following sample led to a bug in MacOS (MM0("y_80fh*d_1h"), [(4, 4), (275, 43, 8, 0), (9, 4, 1, 4, 16)]), ] for h, invar in NEW_SAMPLES: yield h, invar for invar, g in INVOLUTION_SAMPLES: g = MM0(g) g.in_G_x0() yield g, invar n_samples = 20 if invariant_status(invar) == 3 else 10 last = g for i in range(n_samples): t = MM0('r', 'G_x0') h = g**t h.in_G_x0() if h != last: yield h, invar last = h
def gA_from_type4(v_type4): r"""Comupute a group element reducing a type-4 Leech lattice vector Let ``v_type_4`` be a vector of type 4 in the Leech lattice mod 2 in **Leech lattice encoding**. The function returns an element ``g`` of the subgroup :math:`G_{x0}` of the monster that maps `v_type_4`` to the standard frame :math:`\Omega`. The group element ``g`` is returned as a string. """ g_data = np.zeros(10, dtype=np.uint32) len_g = gen_leech2_reduce_type4(v_type4, g_data) gA = MM0('a', g_data[:len_g]) return str(gA)
def reduce_v_axis_C(v, std_axis): va = mm_vector(15, 2) vc, work = va[0].data, va[1].data mm_op15_copy(v.data, vc) r = np.zeros(200, dtype=np.uint32) res = mm_reduce_vector_vp(vc, std_axis, r, work) if not 0 < res <= 200: raise ValueError(ERR_REDUCE_V_AXIS, res) g = MM0('a', r[:res]) axis_found = r[res - 1] assert axis_found & 0xfe000000 == 0x84000000 axis_found &= 0x1ffffff return g, axis_found
def character(g, verbose=0): assert isinstance(g, Xsp2_Co1_Element) a = xsp2co1_traces(g) if verbose: print("Subcharacters", a) chi24, chisq24, chi4096, chi98260 = map(int, a[:4]) chi299 = (chi24**2 + chisq24) // 2 - 1 assert chi24 >= 0 if chi24 == 0: assert chi4096 >= 0 chi_M = chi299 + chi98260 + chi24 * chi4096 #print("MMMM", MM0(g)) chi_g = MM0(g).chi_G_x0() assert chi_g == (chi_M, chi299, chi24, chi4096) return chi_M
def do_test_2A_involution(n_tests=30, verbose=1): for i, g in enumerate(make_2A_samples(n_tests)): if verbose: print("Test", i + 1) print("g=", g) itype, h = g.conjugate_involution(ntrials=40, verbose=verbose) assert itype == 1 res = (g**h) res.in_G_x0() if verbose: print("h=", h) print("g**h=", res) assert res in (Z_2A, MM0('x', 0x200) * Z_2A)