-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つの余地を選択する必要がある もちろん、計算することは可能だが...