正規部分群でガロア拡大
V4の正規部分群

1.中間体のガロア拡大の確認
このワークシートはMath by Codeの一部です。
前回は
K上の多項式f(x)の分解体Lのガロア群Gで、
Lの中間体MとGの部分群Hの1対1対応、ガロア対応をさぐりました。
中間体Mに対応する部分群H=M*,
部分群Hに対応する中間体M=H¥
もちろん、代数拡大L/K自体はガロア拡大なら、中間体MでもL/Mもガロア拡大だった。
しかし、中間体M/Kがガロア拡大であるとは限らない。
今回は、ガロア対応の
根っこの部分M/Kがガロア拡大になっているか
を探ってみよう。
そのために、ガロア拡大の定義の確認をしておこう。
(ガロア拡大と正規拡大の差異は、今のところ不問にします。
体としては有限次元Fpなどは除外しています。)
<ガロア拡大>
次は、同値
・代数拡大L/Kで自己同型群G=Aut(L/K)で不変な体LG=Kなら、L/Kはガロア拡大だ。
・任意のx∈Lについて、xのK上の共役は、どれもLに属している。(正規拡大)
・体LはK上の多項式f(x)∈K[x]の最小分解体だ。
<中間体がガロア拡大>
L/Kがガロア拡大のとき、
・中間体からの拡大L/Mはガロア拡大だ。M*=Gal(L/M)はFixG(M)
・中間体への拡大M/Kがガロア拡大なのは、FixG(M)がGの正規部分群のときに限る。
このとき、M*=Gal(M/K)=G/FixG(M)
KがQの拡大体で、L/Kを2次拡大とすると、L/Kはガロア拡大だ。
(理由)
[L:K]=2からKにない元a∈Lで、aのK上の最小多項式をf(x)とすると、f(x)の次元は2となる。
aのK上共役をa,bとすると、解と係数の関係から、b∈Lが言えるので、Lがf(x)の最小分解体。
<ガロア拡大だけのガロア対応>
ということは、
K上の多項式f(x)の分解体Lのガロア群Gで、
Lの中間体MとGの部分群Hの1対1対応、ガロア対応をさぐりました。
拡大の後半L/Mはガロア拡大になるので、拡大の前半M/Kがガロア拡大かどうかがわかればよい。
Gの正規部分群がNだとわかれば、それに対応する中間体M=N¥がKに対して
M/Kがガロア拡大になるから、ガロア拡大だけでできたガロア対応を作ることができる。
(例)f(x)=x3-2の分解体Lのガロア群からガロア拡大だけでできたガロア対応を作る。
最小多項式の根の共役をu1,u2,u3= , ω , ω2 とおこう。
分解体L=Q( ,ω)=Q({a+bω+c +dω +e 2+fω 2 | a,b,c,d,e,f∈Q}= Q(u1,u2,u3)だ。
ガロア群G=Gal(L/K)={e, s:(1 2 3), ss:(1 3 2), a:(1 2) , b:(1 3) ,c :(2 3)} =S3
自明でない部分群H={A,B,C,N}={{e,a},{e,b},{e,c},{e,s,ss}}
対応する中間M={C¥,B¥,A¥,N¥}={Q(u1),Q(u2),Q(u3),Q(ω)}
中間体M={A,B,C,N}のどれでも、代数拡大M/Hはガロア拡大になるので、これは調べない。
・Aut(Q(u1))=Aut(Q(u2))=Aut(Q(u3))={id}だから、自己同型写像の不変体が基底のQではなく、
中間体自身になってしまうので、ガロア拡大ではない。
・しかし、Q(ω)/Qは、ωのQ上の最小多項式がf(x)=x3-1で、f(x)の解ωの共役1,ω,ω2がQ(ω)に属するので
Q(ω)はf(x)の最小分解体だから、ガロア拡大だ。N={e,s,ss}がGの正規部分群という理由からも言えるね。
<正規部分群の判定>
正規部分群にはgN=Ng、言い換えるとN=g−1Ng
共役写像(自己同型写像)igで不変な部分群という調べ方があった。
質問:クラインの4元群V4の3つの部分群が正規部分群かどうかをコードでしらべるにはどうしましょう。
V4の4元e,a,b,cを平面の4象限の置換をイメージして辞書{もと:行き先}で定義します。
e={1:1,2:2,3:3,4:4}
a={1:2,2:1,3:4,4:3}
b={1:4,2:3,3:2,4:1}
c={1:3,2:4,3:1,4:2}
V4はS=[e,a,b,c]で、部分群は3つA=[e,a]、B=[e,b]、C=[e,c]です。
部分群A,B,Cそれぞれに対して、
igx関数で、g,xから置換辞書xから共役な置換辞書yを返します。
igxs関数は、群の置換ぜんぶをxsで渡して、ぜんぶ共役にしたリストを返します。
make_auto関数は、群Gの部分群Hを渡すと、その全部の要素の、Gの要素gによる共役を計算したリスト
nameListを計算しながら表示します。そして、もとのHの要素の集合とnameListを蓄積したリストをユニークな集合にします。最後にそれを比較して、Hが正規部分群かどうかのメッセージを出します。
[IN]Python
#=============
def ami2dic(ami):
return dict(zip(ami , ami[1:] + [ami[0]]))
def amis2dics(amis):
return [dict(zip(ami , ami[1:] + [ami[0]])) for ami in amis]
# kの辞書dic_aによる行先を返す。辞書にないなら行先はk。
def ami_go(k,dic_a):
return dic_a[k] if k in dic_a.keys() else k
#あみだの辞書a,bの連結をする。
def conL(a,b):#a,bの順に演算する。
keys = list(set(list(a.keys()) + list(b.keys())))
dic ={key:ami_go(ami_go(key,a),b) for key in keys if key !=ami_go(ami_go(key,a),b)}
if len(dic)==0:
dic={1:1}
return dic
def conR(a,b):#b,aの順に演算する。
return conL(b,a)
#アミダを、(辞書,名)のタプルのリストにする。
def rotdic(S,SN):
dic=[ami2dic(x) for x in S]
return list(zip(dic,SN))
# あみだ辞書dic_aを名で返す。
def name(dic_a):
global Nlist
return [item[1] for item in Nlist if item[0]==dic_a][0]
# あみだ辞書集dicsを名のリストで返す。
def names(dics):
global Nlist
return [item[1] for item in Nlist for b in dics if item[0]==b]
# あみだ辞書の集合Hと辞書aを演算した結果リストを返す。
def Ha(H,a):
global Nlist
res=[]
for b in H:
res +=[item[1] for item in Nlist if item[0]==conR(b,a)]
return res
def aH(a,H):
global Nlist
res=[]
for b in H:
res +=[item[1] for item in Nlist if item[0]==conR(a,b)]
return res
#==================================以上が基本関数====================
#辞書リストS,名リストSNから(辞書、名)のタプルのリストにする。
def Ndic(S,SN):
return list(zip(S,SN))
def igx(g,x):
global Ssize
n = Ssize
keys=[ami_go(k,g) for k in range(1,n+1)]
vals=[ami_go(ami_go(k,x),g) for k in range(1,n+1)]
return dict(zip(keys,vals))
def igxs(g,xs):
return [igx(g,x) for x in xs]
#=========ここからがデータ入力
Ssize=4
e={1:1,2:2,3:3,4:4}
a={1:2,2:1,3:4,4:3}
b={1:4,2:3,3:2,4:1}
c={1:3,2:4,3:1,4:2}
S=[e,a,b,c]
A=[e,a]
B=[e,b]
C=[e,c]
SN=["e","a","b","c"]
Nlist=Ndic(S,SN)
#内部自己同型の演算表を作る
def make_auto(H):
global Nlist
targetset = set(names(H))
goalList= []
G = [x[0] for x in Nlist]
print("igの対象=",names(H))
for item in G:
nameList= names(igxs(item,H))
print(name(item),"→",nameList)
goalList.extend(nameList)
goalset=set(goalList)
print(targetset,"→",goalset)
msg = f"だから、{targetset}は正規部分群"
msg += "です。" if targetset == goalset else "ではありません。"
print(msg)
return True
print("G∍gによる内部自己同型")
make_auto(A)
make_auto(B)
make_auto(C)
#===============
[OUT]
G∍gによる内部自己同型
igの対象= ['e', 'a']
e → ['e', 'a']
a → ['e', 'a']
b → ['e', 'a']
c → ['e', 'a']
{'e', 'a'} → {'e', 'a'}
だから、{'e', 'a'}は正規部分群です。
igの対象= ['e', 'b']
e → ['e', 'b']
a → ['e', 'b']
b → ['e', 'b']
c → ['e', 'b']
{'b', 'e'} → {'b', 'e'}
だから、{'b', 'e'}は正規部分群です。
igの対象= ['e', 'c']
e → ['e', 'c']
a → ['e', 'c']
b → ['e', 'c']
c → ['e', 'c']
{'e', 'c'} → {'e', 'c'}
だから、{'e', 'c'}は正規部分群です。
たとえば、
f(x)=(x2-2)(x2-3)の分解体Lのガロア群Gはクラインの4元群V4のガロア拡大のガロア対応を作りたい。
さっそく、V4の3つの部分群が正規部分群であることが使える。
分解体L=Q(√2,√3)={a+b√2+c√3+d√6 | a,b,c,d∈Q}だ。
ガロア群G=Gal(L/Q)=V4=Z/2Z×Z/2Z={(0,0),(0,1),(1,0),(0,0)}={e,a,b,c}
自明でない部分群H={A,B,C}={{e,a},{e,b},{e,c}}
対応する中間体M={A¥,B¥,C¥}={Q(√3),Q(√2),Q(√6)}のどれでも、代数拡大L/Mはガロア拡大になる
対応する中間体M/Qはすべて2次拡大でもあり、Hが正規分群だから、ここもガロア拡大だ。
ガロア対応がオールガロア拡大になったね。
2.ガロア拡大の視覚化
質問:ガロア拡大だけのガロア対応を視覚化するにはどうしたらよいでしょう。
部分グラフを左右に並べて、上下関係を考えならが線を引きましょう。
ノードを別にかかず、エッヂをひくときにノード名をかけばよいですね。
部分群どうしの指数や拡大次数は計算ではなく、リストで与えると
見やすくなります。
#最小多項式がx^3-2の分解体Lのガロア群S3の部分群に対する、ガロア対応のガロア拡大
from graphviz import Digraph
def hasses(dot,itemG,itemK,sizeG,sizeK):
with dot.subgraph(name="cluster0") as G:
for pos in range(len(sizeG)-1):
a = itemG[pos]
b = itemG[pos+1]
G.edge(a,b,str(sizeG[pos+1]//sizeG[pos]),dir='back') #上が小、下が大(上に部分群)
G.attr(label='部分群')
with dot.subgraph(name="cluster1") as G:
for pos in range(len(sizeK)-1):
a = itemK[pos]
b = itemK[pos+1]
G.edge(a,b,str(sizeK[pos]//sizeK[pos+1]),dir='back') #上が大、下が小(上に拡大)
G.attr(label='拡大体')
return True
#=====================================================
dot = Digraph(format='png')
dot.attr('node', fontname="MS Gothic")
itemG=["{e}","N={e,s,ss}", "G={e,s,ss,a,b,c}"]
itemK=["L=Q(2^(1/3),ω)","N¥=Q(ω)","K"]
sizeG=[1,3,6]
sizeK=[6,2,1]
hasses(dot,itemG,itemK,sizeG,sizeK)
dot.attr(label=r'ガロア対応図 \n <======>\n')
dot.attr(fontsize='20')
dot

#最小多項式が(x^2-2)(x^2-3)の分解体Lのガロア群V4の部分群に対する、ガロア対応のガロア拡大
残念ながら汎用性がないので、ガロア拡大に応じて、コードも修正が必要になるね。
from graphviz import Digraph
def hasses(dot,itemG,itemK,sizeG,sizeK):
size=len(sizeG)-1
with dot.subgraph(name="cluster0") as G:
for pos in range(1,size):
a = itemG[0]
b = itemG[pos]
G.edge(a,b,str(sizeG[pos]//sizeG[0]),dir='back')
for pos in range(1,size):
a = itemG[pos]
b = itemG[size]
G.edge(a,b,str(sizeG[size]//sizeG[pos]),dir='back')
G.attr(label='部分群')
with dot.subgraph(name="cluster1") as G:
for pos in range(1,size):
a = itemK[0]
b = itemK[pos]
G.edge(a,b,str(sizeK[pos]//sizeK[0]),dir='back')
for pos in range(1,size):
a = itemK[pos]
b = itemK[size]
G.edge(a,b,str(sizeK[size]//sizeK[pos]),dir='back')
G.attr(label='拡大体')
return True
#=====================================================
dot = Digraph(format='png')
dot.attr('node', fontname="MS Gothic")
itemG={0:"{e}",1:"A{e,p}",2:"B{e,q}",3:"C{e,pq}",4:"G={e,p,q,pq}"}
itemK={0:"L=Q(√2,√3)",1:"Q(√3)",2:"Q(√2)",3:"Q(√6)",4:"Q"}
sizeG=[1,2,2,2,4]
sizeK=sizeG
hasses(dot,itemG,itemK,sizeG,sizeK)
dot.attr(label=r'ガロア対応図 \n <======>\n')
dot.attr(fontsize='20')
dot
