-title: AgdaによるGalois理論のプログラミング
--motivation
5次方程式が代数的に解けないことの復習
数学書では省略されてても Agda は許してくれない
計算で示しても、それが証明になっているかどうかは別
証明付きデータ構造を使う
計算と証明が「全部つながってる」
この計算、いったい、何を計算してるの?
それを型で示す
--Galois theory : 多項式方程式
(x - α)(x - β)(x - γ) = 0
と因数分解されればαβγが解になる。
--Galois theory : 解と置換群(対称群)
αβγを入れ替えても良い(Symmetric Group))。これが
(x - α)(x - β) = 0
に帰着されるなら、αβ を入れ替えても良い。ならば、αβγ の置換で
αβγ = βαγ
にならないとおかしい。
--Galois theory : 可解群
αβγ = βαγ
α⁻¹β⁻¹αβγγ⁻¹ = α⁻¹β⁻¹βαγγ⁻¹
α⁻¹β⁻¹αβ = e (交換子 Commutator)
なので、対称群のすべての要素を α⁻¹β⁻¹αβ の形にするのを繰り返して e になれば良い(可解群)。
(もちろん、これは証明になってない。気分的な説明。本当は正規拡大体とか代数的拡大とか)
ここは今回は Agda で証明しません。
あれ? 割と Agda の得意な分野なのでできるはず。やさしくはないだろうけど
Agdaは抽象的な証明が得意
--5次方程式が代数的に解けないことの証明
5次の対称群は可解でないことを示せばよい。2,3,4次は可解。教科書だと
これは良い方で、岩波だと練習問題。
--数学の本の記述の特徴
理解した後で読むとちゃんと書いてある
理解する前には何が書いてあるのかわからない
--Agda でちゃんとやろうぜ
Curry Howard 対応に基づく定理証明支援系
依存型を持つ純関数型言語
依存型とは、型を値に持つ変数
命題そのものは Set という型を持つ
構文的には Haskell とほぼ同じ。Coq と違い、何もしてくれない。全部、自分で証明を書く。(いさぎよい)
--Agda : lambda
A → B の証明
→intro : {A B : Set } → A → B → ( A → B )
→intro _ b = λ x → b
→elim : {A B : Set } → A → ( A → B ) → B
→elim a f = f a
引数の値は、型の証明
入力は∀が付いていると考える(∃はあとで)
--Agda : record
A ∧ B の証明
record _∧_ (A B : Set) : Set where
field
proj1 : A
proj2 : B
∧elim : {A B : Set} → ( A ∧ B ) → A
∧elim a∧b = proj1 a∧b
∧intro : {A B : Set} → A → B → ( A ∧ B )
∧intro a b = record { proj1 = a ; proj2 = b }
--Agda : data
A ∨ B の証明
data _∨_ (A B : Set) : Set where
case1 : A → A ∨ B
case2 : B → A ∨ B
∨intro : {A B : Set} → A → ( A ∨ B )
∨intro a = case1
∨elim : {A B : Set} → ( A ∨ A ) → A
∨elim (case1 a) = a
∨elim (case2 a) = a
--Agda : negation
data ⊥ : Set where
constructor のないデータ構造(偽
⊥-elim : {A : Set } -> ⊥ -> A
⊥-elim ()
起きない入力は () 。λ () とも書ける
data ⊤ : Set where
tt : ⊤
要素が一つしかない型(真
--Agda : unification
data _≡_ {A : Set } : A → A → Set where
refl : {x : A} → x ≡ x
≡intro : {A : Set} {x : A } → x ≡ x
≡intro = refl
≡elim : {A : Set} {x y : A } → x ≡ y → y ≡ x
≡elim refl = refl
項(正規化された)として等しい。変数はどうするの? 十分に instanciation されない場合は黄色くなる。
その他、細かい問題が... internal parametricity... inspect...
でも、これで全部。さぁ、Agda を書こう。
--Galois theory i nAgda : Commutator
[_,_] : Carrier → Carrier → Carrier
[ g , h ] = g ⁻¹ ∙ h ⁻¹ ∙ g ∙ h
こんな風に数学の教科書通りに Unicode を使って書けるところが Agda の良いところ
data Commutator (P : Carrier → Set ) : (f : Carrier) → Set where
comm : {g h : Carrier} → P g → P h → Commutator P [ g , h ]
ccong : {f g : Carrier} → f ≈ g → Commutator P f → Commutator P g
deriving : ( i : ℕ ) → Carrier → Set
deriving 0 x = ⊤
deriving (suc i) x = Commutator (deriving i) x
Set を返してるのはなに? Set は何かの命題、 つまり真偽として扱って良い。したがって
P : Carrier → Set
これは Carrier の部分集合を指定する命題となる。 (Carrier は群の要素の型)
交換子 Commutator p は述語 f p で限定された p : Carrier が [ g , h ] という形で生成されることを示している。
deriving i は、Carrier の部分集合で、Commutator を再帰的に繰り返して得られたもの
--Galois theory in Agda : Solvable
record solvable : Set (Level.suc n ⊔ m) where
field
dervied-length : ℕ
end : (x : Carrier ) → deriving dervied-length x → x ≈ ε
存在∃は record で書く。ある dervied-length : ℕ があって、その回数のderive の繰り返しで x ≈ ε になる
この record を構成できれば、その群は可解ということになる。これで問題は定義できた
--Galois theory in Agda : Symmetric group
対称群の要素は置換だが、Agdaの標準ライブラリだと有限な数のBijectionとして定義される
Permutation p p
定義は複雑だが二つの写像 _⟨$⟩ˡ_ _⟨$⟩ʳ_ と y ⟨$⟩ˡ (y ⟨$⟩ʳ x) ≡ x と y ⟨$⟩ʳ (y ⟨$⟩ˡ x) ≡ x からなる record
残念ながら扱いにくい。同等性とか。単純に x ≡ y を証明できない(Agdaの制約 1)
しかし群であることを示すのは簡単
--Permutation : Data.Fin
有限な数
data Fin : ℕ → Set where
zero : {n : ℕ} → Fin (suc n)
suc : {n : ℕ} (i : Fin n) → Fin (suc n)
x : Fin 3 のように使う
Fin 0 の値は存在しない
_⟨$⟩ˡ_ : Fin p → Fin p
--Permutation : List
置換は List ℕ で表されるので、それで良いのだが、List ℕ が全部置換になるわけではない
そこで減少列 FL とその大小関係を定義する
data FL : (n : ℕ )→ Set where
f0 : FL 0
_::_ : { n : ℕ } → Fin (suc n ) → FL n → FL (suc n)
data _f<_ : {n : ℕ } (x : FL n ) (y : FL n) → Set where
f
FList : (n : ℕ ) → Set
FList n = List# (FL n) ⌊ _f ¬a ¬b lt = cons a ( x ∷# [] ) ( Level.lift (fromWitness lt) , Level.lift tt )
FLinsert {suc n} x (cons a y yr) | tri> ¬a ¬b a ¬a ¬b c = no ( ¬a )
--sym5
abc が反例。これが常に残ることを示す
counter-example : ¬ (abc 0<3 0<4 =p= pid )
counter-example eq with ←pleq _ _ eq
... | ()
二つ余地を確保する
ins2 : {i j : ℕ } → Permutation 3 3 → (i ≤ 3 ) → ( j ≤ 4 ) → Permutation 5 5
ins2 abc i<3 j<4 = (save2 i<3 j<4 ∘ₚ (pprep (pprep abc))) ∘ₚ flip (save2 i<3 j<4 )
abc と dba を作る
abc : {i j : ℕ } → (i ≤ 3 ) → ( j ≤ 4 ) → Permutation 5 5
abc i<3 j<4 = ins2 3rot i<3 j<4
dba : {i j : ℕ } → (i ≤ 3 ) → ( j ≤ 4 ) → Permutation 5 5
dba i<3 j<4 = ins2 (3rot ∘ₚ 3rot) i<3 j<4
abc が derive されることを示す
dervie-any-3rot0 : (n : ℕ ) → {i j : ℕ } → (i<3 : i ≤ 3 ) → (j<4 : j ≤ 4 )
→ deriving n (abc i<3 j<4 )
dervie-any-3rot0 0 i<3 j<4 = lift tt
dervie-any-3rot0 (suc i) i<3 j<4 = ccong {deriving i} (psym ceq) (commd dba0 aec0 df dg )where
commd : {n : ℕ } → (f g : Permutation 5 5)
→ deriving n f
→ deriving n g
→ Commutator (deriving n) [ f , g ]
commd {n} f g df dg = comm {deriving n} {f} {g} df dg
df と dg が前に derive されたもの
df = dervie-any-3rot1 i (fin≤n {3} (dba0<3 tc)) (fin≤n {4} (dba1<4 tc))
dg = dervie-any-3rot1 i (fin≤n {3} (aec0<3 tc)) (fin≤n {4} (aec1<4 tc))
それは、再帰的に作れるのだが種(dbaとaec)を二つ計算する必要がある
それは右回転と左回転があって、 dervie-any-3rot0 と dervie-any-3rot1 で交互に作られる
そのつくり方だが...
tc = triple i<3 j<4
dba0 = dba (fin≤n {3} (dba0<3 tc)) (fin≤n {4} (dba1<4 tc))
aec0 = dba (fin≤n {3} (aec0<3 tc)) (fin≤n {4} (aec1<4 tc))
ceq : abc i<3 j<4 =p= [ dba0 , aec0 ]
ceq = record { peq = peq (abc= tc) }
dba と aec を作るのだが
record Triple {i j : ℕ } (i<3 : i ≤ 3) (j<4 : j ≤ 4) (rot : Permutation 3 3) : Set where
field
dba0<3 : Fin 4
dba1<4 : Fin 5
aec0<3 : Fin 4
aec1<4 : Fin 5
abc= : ins2 rot i<3 j<4 =p= [ ins2 (rot ∘ₚ rot) (fin≤n {3} dba0<3) (fin≤n {4} dba1<4) , ins2 (rot ∘ₚ rot) (fin≤n {3} aec0<3) (fin≤n {4} aec1<4) ]
open Triple
triple : {i j : ℕ } → (i<3 : i ≤ 3) (j<4 : j ≤ 4) → Triple i<3 j<4 3rot
triple z≤n z≤n = record { dba0<3 = # 0 ; dba1<4 = # 4 ; aec0<3 = # 2 ; aec1<4 = # 0 ; abc= = pleq _ _ refl }
triple z≤n (s≤s z≤n) = record { dba0<3 = # 0 ; dba1<4 = # 4 ; aec0<3 = # 2 ; aec1<4 = # 0 ; abc= = pleq _ _ refl }
....
と自分でうまく2つの余地を選択する必要がある
もちろん、計算することは可能だが...