def rule_xx(group, word): global n_rules n_rules += 1 x1, x2 = word[0], word[1] delta = AutPLoopAtom('p', mat24.ploop_cap(x1.pl, x2.pl), 0) x = xy_Atom(x1.tag, mat24.mul_ploop(x1.pl, x2.pl)) return [delta, x]
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 index_suboctad(tag, i, index_type_T=3, a_indices_T=None): """Convert an index specifying an suboctad number 0 <= 'i' < 64 is an index specifying the number of a suboctad in the Golay cocode. Here a suboctad is a Golay cocode word which can be represented a subset of of an octad. For each octad there is a lexicographic numbering of its suboctad, and index 'i' refers to that lexicographic numbering. This index type occurs as the second index of tag T only, so the first index of that tag gives us a reference octad. If 'i' is of type Cocode or GcVector, corresponding to a Golay cocode word, that cocode word is taken if it fits into the reference octad; otherwise we raise ValueError. The function returns triple (index_type, a_indices, sign). Here index_type indicates whether the index has been selected ar random, or whether it refers to a slice, as in function index_I(). The index or the indices making up the slice are returned in the numpy array 'a_indices', as in function index_I(). In any case the numbers in that array are suboctad numbers. Parameters ('index_type_T', 'a_indices_T') must be the values (index_type, a_indices) returned by function index_T(), when called with the first index for tag T. The second index of tag T is of this type. Parameter 'tag' is for compatibility with similar functions; it must be 'T'. """ if isinstance(i, Integral): if 0 <= i < 64: return 0, i, 0 raise IndexError(INDEX_ERROR_RANGE % ("Second ", tag)) elif isinstance(i, str): if i in ["r", "n"]: return INDEX_IS_RANDOM, randint(0, 63), 0 raise IndexError(INDEX_ERROR_RAND % tag) elif isinstance(i, slice): return INDEX_IS_SLICE, a_slice(i, 64), 0 elif isinstance(i, (GCode, Cocode, GcVector)): if index_type_T == 0: gcode = mat24.octad_to_gcode(a_indices_T) & 0xfff if isinstance(i, GCode): cocode = mat24.ploop_cap(gcode, i) else: cocode = Cocode(i).cocode sub = mat24.cocode_to_suboctad(cocode, gcode) return 0, sub, 0 err = "Second vector index for tag T must be integer here" raise TypeError(err) elif isinstance(i, Iterable): return index_iterable(index, 64, tag, 2) raise TypeError(INDEX_ERROR_TYPE % ("Second ", type(i), tag))
def rule_xy(group, word): global n_rules n_rules += 1 x, y = word[0], word[1] delta = AutPLoopAtom('p', mat24.ploop_cap(x.pl, y.pl), 0) comm = mat24.ploop_comm(x.pl, y.pl) << 12 x1 = xy_Atom(x.tag, x.pl ^ comm) y1 = xy_Atom(y.tag, y.pl ^ comm) return [delta, y1, x1]
def test_Parker_loop(): print("\nTesting operation on Parker loop") for i in range(200): # Test power map, inveriosn, sign, theta, and conversion to GCode n1 = randint(0, 0x1fff) p1 = PLoop(n1) assert p1.ord == n1 == p1.gcode + 0x1000 * (1 - p1.sign) / 2 if (i < 2): print("Testing Parker loop element", p1, ", GCode = ", GCode(p1)) assert len(p1) == mat24.gcode_weight(n1) << 2 assert p1.theta() == Cocode(mat24.ploop_theta(n1)) assert p1 / 4 == p1.theta(p1) == Parity(mat24.ploop_cocycle(n1, n1)) assert p1**2 == PLoopZ(p1 / 4) == (-PLoopZ())**(p1 / 4) assert p1**(-5) == PLoopZ(p1 / 4) * p1 == (-1)**(p1 / 4) * p1 == 1 / p1 assert (1 / p1).ord ^ n1 == (mat24.gcode_weight(n1) & 1) << 12 assert -1 / p1 == -p1**3 == -(1 / p1) assert p1 * (-1 / p1) == PLoopZ(1) == -PLoopZ() assert abs(p1).ord == GCode(p1).ord == p1.ord & 0xfff assert p1 != GCode(p1) assert +p1 == 1 * p1 == p1 * 1 == p1 assert p1 != -p1 and p1 != ~p1 assert (-p1).ord == p1.ord ^ 0x1000 assert (~p1).ord == p1.ord ^ 0x800 s, o, p1_pos = p1.split() assert s == (p1.ord >> 12) & 1 assert o == (p1.ord >> 11) & 1 assert p1.sign == (-1)**s assert p1_pos.ord == p1.ord & 0x7ff assert PLoopZ(s, o) * p1_pos == p1 assert PLoopZ(0, o) * p1_pos == abs(p1) assert PLoopZ(s + 1, o) * p1_pos == -p1 assert -p1 == -1 * p1 == p1 * -1 == p1 / -1 == -1 / p1**-5 assert PLoopZ(s, 1 + o) * p1_pos == ~p1 assert PLoopZ(1 + s, 1 + o) * p1_pos == ~-p1 == -~p1 == ~p1 / -1 assert 2 * p1 == GCode(0) == -2 * GCode(p1) assert -13 * p1 == GCode(p1) == 7 * GCode(p1) if len(p1) & 7 == 0: assert p1**Parity(1) == p1 assert p1**Parity(0) == PLoop(0) else: with pytest.raises(ValueError): p1**Parity(randint(0, 1)) assert p1.bit_list == mat24.gcode_to_bit_list(p1.value & 0xfff) assert p1.bit_list == GcVector(p1).bit_list assert p1.bit_list == GCode(p1).bit_list assert PLoop(GcVector(p1) + 0) == PLoop(GCode(p1) + 0) == abs(p1) assert p1 + 0 == 0 + p1 == GCode(p1) + 0 == 0 + GCode(p1) assert Cocode(GcVector(p1)) == Cocode(0) assert p1 / 2 == Parity(0) # Test Parker loop multiplication and commutator n2 = randint(0, 0x1fff) p2 = PLoop(n2) coc = Cocode(mat24.ploop_cap(n1, n2)) if (i < 1): print("Intersection with", p2, "is", coc) p2inv = p2**-1 assert p1 * p2 == PLoop(mat24.mul_ploop(p1.ord, p2.ord)) assert p1 / p2 == p1 * p2**(-1) assert p1 + p2 == p1 - p2 == GCode(p1 * p2) == GCode(n1 ^ n2) assert (p1 * p2) / (p2 * p1) == PLoopZ((p1 & p2) / 2) assert p1 & p2 == coc assert p1.theta() == Cocode(mat24.ploop_theta(p1.ord)) assert p1.theta(p2) == Parity(mat24.ploop_cocycle(p1.ord, p2.ord)) assert (p1 & p2) / 2 == p1.theta(p2) + p2.theta(p1) assert p1 & p2 == p1.theta() + p2.theta() + (p1 + p2).theta() assert int((p1 & p2) / 2) == mat24.ploop_comm(p1.ord, p2.ord) assert GcVector(p1 & p2) == GcVector(p1) & GcVector(p2) assert ~GcVector(p1 & p2) == ~GcVector(p1) | ~GcVector(p2) assert Cocode(GcVector(p1 & p2)) == p1 & p2 # Test associator n3 = randint(0, 0x1fff) p3 = PLoop(n3) assert p1 * p2 * p3 / (p1 * (p2 * p3)) == PLoopZ(p1 & p2 & p3) assert int(p1 & p2 & p3) == mat24.ploop_assoc(p1.ord, p2.ord, p3.ord) i = randint(-1000, 1000) par = Parity(i) s3 = ((p3 & p1) & p2) + par assert s3 == ((p3 & p1) & p2) + par assert s3 == i + (p1 & (p2 & p3)) assert s3 == par + (p1 & (p2 & p3)) # Test some operations leading to a TypeError with pytest.raises(TypeError): p1 & p2 & p3 & p1 with pytest.raises(TypeError): coc & coc with pytest.raises(TypeError): GCode(p1) * GCode(p2) with pytest.raises(TypeError): 1 / GCode(p2) with pytest.raises(ValueError): coc / 4 with pytest.raises(TypeError): p1 * coc with pytest.raises(TypeError): coc * p1 types = [GcVector, GCode, Cocode, PLoop] for type_ in types: with pytest.raises(TypeError): int(type_(0)) print("Parker Loop test passed")
def _as_suboctad(v1, o): d = m24.octad_to_gcode(o) c = m24.ploop_cap(v1, d) return m24.cocode_to_suboctad(c, d)
def __init__(self, v1, v2): assert isinstance(v1, GCode) and isinstance(v2, GCode) self.v1, self.v2 = v1.value, v2.value self.value = mat24.ploop_cap(self.v1, self.v2)
def SubOctad(octad, suboctad=0): """Creates a suboctad as instance of class |XLeech2| :param octad: The first component of the pair *(octad, suboctad)* to be created. :type octad: same as in function :py:class:`~mmgroup.Octad` :param suboctad: The second component of the pair *(octad, suboctad)* to be created. :type suboctad: see table below for legal types :return: The suboctad given by the pair *(octad, suboctad)* :rtype: an instance of class |XLeech2| :raise: * TypeError if one of the arguments *octad* or *suboctad* is not of correct type. * ValueError if argument *octad* or *suboctad* does not evaluate to an octad or to a correct suboctad, respectively. A *suboctad* is an even cocode element that can be represented as a subset of the octad given by the argument *octad*. The raison d'etre of function ``SubOctad`` is that pairs *(octad, suboctad)* are used for indexing vectors in the representation of the monster group. Here we want to number the octads from ``0`` to ``758`` and the suboctads form ``0`` to ``63``, depending on the octad. Note that every octad has ``64`` suboctads. Depending on its type parameter **suboctad** is interpreted as follows: .. table:: Legal types for parameter ``suboctad`` :widths: 20 80 ===================== ================================================ type Evaluates to ===================== ================================================ ``int`` Here the suboctad with the number given in the argument is taken. That numbering depends on the octad given in the argument ``octad``. ``0 <= suboctad < 64`` must hold. ``list`` of ``int`` Such a list is converted to a bit vector as in class |GcVector|, and the cocode element corresponding to that bit vector is taken. class |GCode| The intersection of the octad given as the first argument and the Golay code word given as the second argument is taken. class |GcVector| This is converted to a cocode element, see class |Cocode|, and that cocode element is taken. class |Cocode| That cocode element is taken as the suboctad. ``str`` Create random element depending on the string | ``'r'``: Create arbitrary suboctad ===================== ================================================ The numbering of the suboctads Suboctads are numbered for 0 to 63. Let ``[b0, b1,..., b7]`` be the bits set in the octad of the pair ``(octad, suboctad)`` in natural order. The following table shows the suboctad numbers for some suboctads given as cocode elements. More suboctad numbers can be obtained by combining suboctads and their corresponding numbers with ``XOR``. .. table:: Suboctad numbers of some cocode elements :widths: 16 16 16 16 18 18 =========== =========== =========== =========== =========== =========== ``[b0,b1]`` ``[b0,b2]`` ``[b0,b3]`` ``[b0,b4]`` ``[b0,b5]`` ``[b0,b6]`` ``s = 1`` ``s = 2`` ``s = 4`` ``s = 8`` ``s = 16`` ``s = 32`` =========== =========== =========== =========== =========== =========== E.g. ``[b0, b5, b6, b7]`` is equivalent to ``[b1, b2, b3, b4]`` modulo the Golay code and has number ``s = 1 ^ 2 ^ 4 ^ 8 = 15``. """ ploop = Octad(octad) gcode = ploop.value & 0xfff if isinstance(suboctad, str): suboctad_ = randint(0, 63) elif isinstance(suboctad, Integral): suboctad_ = suboctad & 0x3f elif isinstance(suboctad, GCode): value = mat24.ploop_cap(gcode, suboctad.value) suboctad_ = mat24.cocode_to_suboctad(value, gcode) else: value = Cocode(suboctad).cocode suboctad_ = mat24.cocode_to_suboctad(value, gcode) cocode = mat24.suboctad_to_cocode(suboctad_, gcode) if import_pending: complete_import() result = XLeech2(ploop, cocode) subtype = result.xsubtype assert subtype in [0x22, 0x42], (hex(subtype), hex(ploop), hex(cocode), hex(result.value)) # complent a complement of an octad if subtype == 0x42: result.value ^= 0x800000 return result
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)
def as_suboctad(v1, d): c = m24.ploop_cap(v1, d) return m24.cocode_to_suboctad(c, d)