Skip to content
The Lumenary

Math laboratory

Maschke's theorem fails in characteristic p

Lists all lines of F_p^2 for p = 2, 3, 5, 7 and finds those invariant under the shear (order p) and under the swap (order 2): the shear has a single invariant line, so Maschke fails exactly when p divides the group order. It also runs the averaging argument of Maschke's proof, which works for p odd and breaks for p = 2. Exhaustive and exact.

Back to the labExact computationExhaustive finite checkCounterexample
Maschke's theorem fails in characteristic pPythonExact computationExhaustive finite checkCounterexampleComputationally tested
"""Maschke's theorem and its failure when the characteristic divides |G|.

Over F_p, the shear J = [[1, 1], [0, 1]] has order p, so g -> J^g is a
representation of the cyclic group of order p on F_p^2. We list all p + 1
lines of F_p^2 and find the invariant ones: there is exactly one, so it has
no invariant complement and the representation is not completely reducible.
For contrast, the swap S = [[0, 1], [1, 0]] (a representation of the group of
order 2) has two complementary invariant lines when p is odd but only one
when p = 2. Finally we run Maschke's averaging on a projection: for p odd,
(pi + S pi S) / 2 is an equivariant projection; for p = 2 the division by
|G| = 2 is impossible, and the sum pi + S pi S is not a projection.
"""

def lines(p):
    """One spanning vector for each of the p + 1 lines of F_p^2."""
    return [(1, a) for a in range(p)] + [(0, 1)]

def apply(m, v, p):
    """Matrix times vector mod p."""
    return ((m[0][0] * v[0] + m[0][1] * v[1]) % p,
            (m[1][0] * v[0] + m[1][1] * v[1]) % p)

def on_line(w, v, p):
    """Is w a multiple of v mod p?"""
    return (w[0] * v[1] - w[1] * v[0]) % p == 0

def invariant_lines(m, p):
    """Lines of F_p^2 mapped into themselves by m."""
    return [v for v in lines(p) if on_line(apply(m, v, p), v, p)]

def matmul(a, b, p):
    """2 x 2 matrix product mod p."""
    return [[sum(a[i][k] * b[k][j] for k in range(2)) % p for j in range(2)]
            for i in range(2)]

def order(m, p):
    """Multiplicative order of an invertible 2 x 2 matrix mod p."""
    k, x = 1, m
    while x != [[1, 0], [0, 1]]:
        x, k = matmul(x, m, p), k + 1
    return k

SHEAR = [[1, 1], [0, 1]]
SWAP = [[0, 1], [1, 0]]
# projection onto the line spanned by (1, 1) along the line spanned by (1, 0)
PI = [[0, 1], [0, 1]]

def averaged(p):
    """sum over G = {1, S} of g pi g^-1, divided by |G| = 2 if possible."""
    total = [[(PI[i][j] + matmul(matmul(SWAP, PI, p), SWAP, p)[i][j]) % p
              for j in range(2)] for i in range(2)]
    if p == 2:
        return total
    half = pow(2, p - 2, p)
    return [[x * half % p for x in row] for row in total]

def main():
    print(" p  order of shear  invariant lines (shear)  invariant lines (swap)")
    for p in (2, 3, 5, 7):
        print(f"{p:2}  {order(SHEAR, p):14}  {str(invariant_lines(SHEAR, p)):23}"
              f"  {invariant_lines(SWAP, p)}")
    for p in (3, 5, 2):
        e = averaged(p)
        proj = matmul(e, e, p) == e
        equiv = matmul(e, SWAP, p) == matmul(SWAP, e, p)
        label = "(pi + S pi S)/2" if p != 2 else "pi + S pi S (no 1/2)"
        print(f"p = {p}: {label} = {e}")
        print(f"  idempotent: {proj}; commutes with S: {equiv}")
    print()
    print("Epistemic status: exhaustive over all lines of F_p^2 for the four "
          "primes shown,\nwith exact modular arithmetic: genuine "
          "counterexamples to complete reducibility\nwhen p divides |G|. "
          "Maschke's theorem itself is proved in the lesson.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Used in