codex/normal-subgroup-coset-contrast.py

normal-subgroup-coset-contrast.py
"""Check S3 composition and compare normal and nonnormal coset behavior."""

from itertools import permutations
from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch


def compose(p,q):
    return tuple(p[q[i]] for i in range(3))


def inverse(p):
    return tuple(p.index(i) for i in range(3))


def parity(p):
    return (-1)**sum(p[i]>p[j] for i in range(3) for j in range(i+1,3))


def left(g,H):
    return {compose(g,h) for h in H}


def right(H,g):
    return {compose(h,g) for h in H}


def panel(ax,title,groups,notes):
    ax.axis('off');ax.set(xlim=(0,1),ylim=(0,1))
    ax.set_title(title,fontsize=16,pad=18)
    for j,(label,entries,color) in enumerate(groups):
        y=.73-j*.30
        ax.add_patch(FancyBboxPatch((.035,y-.1),.93,.22,boxstyle='round,pad=.015',
                                    facecolor=color,edgecolor='#8c9eac',lw=1))
        ax.text(.08,y+.055,label,fontsize=14,va='center')
        ax.text(.08,y-.04,entries,fontsize=15,va='center')
    ax.text(.5,.09,notes,fontsize=12,ha='center',va='center',linespacing=1.6)


def main():
    e=(0,1,2);t12=(1,0,2);g=(1,2,0);t13=(2,1,0);t23=(0,2,1)
    G=set(permutations(range(3)));N={p for p in G if parity(p)==1};H={e,t12}
    assert len(N)==3 and len(H)==2
    for a in G:
        for b in G:assert parity(compose(a,b))==parity(a)*parity(b)
        assert left(a,N)==right(N,a)
        assert {compose(compose(a,n),inverse(a)) for n in N}==N
    assert left(g,H)=={g,t13}
    assert right(H,g)=={g,t23}
    assert compose(compose(g,t12),inverse(g))==t23 and t23 not in H
    assert left(t12,N)=={t12,t13,t23}==right(N,t12)
    fig,axes=plt.subplots(1,2,figsize=(11.6,5.1),dpi=120,facecolor='white')
    panel(axes[0],r'$N=A_3$: normal',
          [(r'Even coset $N$',r'$\{e,(123),(132)\}$','#d8e9d7'),
           (r'Odd coset $(12)N=N(12)$',r'$\{(12),(13),(23)\}$','#d5e5f1')],
          'Left and right cosets match.\nParity gives a two-element quotient.')
    panel(axes[1],r'$H=\{e,(12)\}$: not normal',
          [(r'Left coset $gH$',r'$\{(123),(13)\}$','#f0ddc8'),
           (r'Right coset $Hg$',r'$\{(123),(23)\}$','#efdbde')],
          r'$g=(123)$; the two cosets differ.'+'\n'+r'$g(12)g^{-1}=(23)\notin H$')
    fig.suptitle('In S₃, normality is stronger than being a subgroup',fontsize=18,y=.97)
    fig.text(.5,.028,'Permutation products act rightmost first; e is the identity permutation.',
             fontsize=12,ha='center')
    fig.subplots_adjust(left=.04,right=.96,bottom=.14,top=.8,wspace=.18)
    fig.savefig(Path.cwd()/Path(__file__).with_suffix('.png').name,
                facecolor='white',transparent=False)
    plt.close(fig)


if __name__=='__main__':
    main()