codexs3-two-coset-action-kernel.py
s3-two-coset-action-kernel.py
"""Draw the transitive, nonfaithful S3 action on two left cosets; PNG to cwd."""
from itertools import permutations
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
def compose(p, q):
return tuple(p[j - 1] for j in q)
def main():
group = list(permutations((1, 2, 3)))
e, t, r = (1, 2, 3), (2, 1, 3), (2, 3, 1)
n = {e, r, compose(r, r)}
cosets = [frozenset(n), frozenset(compose(t, a) for a in n)]
assert cosets[0].isdisjoint(cosets[1])
assert set.union(*(set(c) for c in cosets)) == set(group)
actions = {g: tuple(cosets.index(frozenset(compose(g, a) for a in c))
for c in cosets) for g in group}
assert {g for g in group if actions[g] == (0, 1)} == n
assert set(actions.values()) == {(0, 1), (1, 0)}
assert actions[r] == (0, 1) and actions[t] == (1, 0)
assert [{g for g in group if actions[g][i] == i} for i in range(2)] == [n, n]
for a in group:
for b in group:
assert actions[compose(a, b)] == tuple(actions[a][j] for j in actions[b])
ink, blue, orange, gray = "#243344", "#166b99", "#a55719", "#d7dfe6"
fig = plt.figure(figsize=(10, 6.4), dpi=110, facecolor="white")
ax = fig.add_axes((0, 0, 1, 1))
ax.set(xlim=(0, 1), ylim=(0, 1))
ax.axis("off")
ax.text(.5, .953, r"$S_3$ on two left cosets: transitive, with a hidden kernel",
ha="center", fontsize=18, color=ink)
ax.text(.5, .9, r"$N=A_3=\{e,(123),(132)\}$ is normal",
ha="center", fontsize=13, color=ink)
for x, color, label, members, explanation in (
(.265, blue, r"$E=N$", r"$\{e,(123),(132)\}$", "Even permutations"),
(.735, orange, r"$O=(12)N$", r"$\{(12),(13),(23)\}$", "Odd permutations")):
ax.add_patch(FancyBboxPatch((x - .21, .696), .42, .15,
boxstyle="round,pad=.006", facecolor="white", edgecolor=color, lw=1.8))
ax.text(x, .802, label, ha="center", fontsize=17, color=color)
ax.text(x, .755, members, ha="center", fontsize=15, color=ink)
ax.text(x, .711, explanation, ha="center", fontsize=11, color=color)
for left, g, label in ((.065, r, r"$(123)$ fixes both labels"),
(.565, t, r"$(12)$ exchanges the labels")):
ax.text(left + .18, .641, label, ha="center", fontsize=13, color=ink)
xs = (left + .045, left + .305)
for i, x in enumerate(xs):
color = (blue, orange)[i]
ax.annotate("", xy=(xs[actions[g][i]], .413), xytext=(x, .552),
arrowprops={"arrowstyle": "-|>", "lw": 2.5,
"color": color, "mutation_scale": 17})
for y in (.584, .381):
ax.text(x, y, (r"$E$", r"$O$")[i], ha="center", va="center",
fontsize=16, color=color, bbox={"facecolor": "white",
"edgecolor": color, "boxstyle": "round,pad=.3"})
ax.plot([.035, .965], [.315, .315], color=gray, lw=1.5)
ax.text(.095, .262, r"$e,\ (123),\ (132)$", color=blue, fontsize=15)
ax.text(.535, .262, "all induce the identity", color=ink, fontsize=13)
ax.text(.095, .207, r"$(12),\ (13),\ (23)$", color=orange, fontsize=15)
ax.text(.535, .207, "all induce the exchange", color=ink, fontsize=13)
ax.text(.5, .124, r"$\ker\rho=N,\qquad S_3/N\cong C_2$",
ha="center", fontsize=18, color=ink)
ax.text(.5, .05, "2 cosets • 2 distinct induced permutations • 3 invisible elements",
ha="center", fontsize=13, color=ink)
out = Path.cwd() / (Path(__file__).stem + ".png")
fig.savefig(out, facecolor="white", transparent=False)
plt.close(fig)
print("Checked 12 coset images, 36 composition identities, transitivity and kernel A3.")
print(out)
if __name__ == "__main__":
main()