quotient type in cubical type theory
はじめてのCubical
http://d.hatena.ne.jp/m-a-o/20131227#p1
の続き。何分できたばっかの処理系なので、上で書いたコードは微妙に動かなくなってしまっているっぽいけど、まぁ少し修正するだけ
実用的には、quotient typeが作れるのは重要な気もするので、その話。一応、examples/quotient.cubを見れば実装は載っているが、少し変更した実装を
https://gist.github.com/vertexoperator/3ca7af8c9a0784af9656fd37dfc3eac0
に作った。
quot : (A:U) -> (R:rel A) -> U quot A R = Sigma (A->U) (\f->exists A (\c->Id (A->U) (R c) f)) -- canonical projection canProj : (A:U) (R:rel A) -> A -> quot A R canProj A R a = (R a , pr) where pr : exists A (\c -> Id (A->U) (R c) (R a)) pr = inc (Sigma A (\c-> Id (A->U) (R c) (R a))) (a, refl (A->U) (R a))
というのが定義で、こちらの方が分かりやすい(と思う)。canProj A R cは、x:Aがcと同値かどうか判定する関数となる。
前提として、どういう性質を持てば、quotient typeなのかというと、一つは
(x y:A) -> R x y -> Id (quot A R) (canProj A R x) (canProj A R y)
というのが、言えてほしい。これは、同値な元は、quotient type上では等しい元に射影されるという、当然の要請
もう一つは、quotientの普遍性で
(f : A -> B) -> ((x y : A) -> R x y -> Id B (f x) (f y)) -> (quot A R -> B)
という性質。f:A->Bという関数が、同値な元を等しい元に移すなら、quot A R -> Bが作れる。大体、quotient typeがから写像を作るには、いつでも、この関数に頼ることになる。ほんとは、普遍性というからには、存在だけでなく、一意性も言わないといけないけど、そのへんは省略
上の2つの性質を、前提条件も含めて、正確に書くと、
relQuot : (A:U) (R:rel A) -> equivalence A R -> propRel A R -> (x y:A) -> R x y -> Id (quot A R) (canProj A R x) (canProj A R y) univQuot : (A B : U) (R : rel A) (f : A -> B) -> set B -> resp A B R f -> (eqR : equivalence A R) (pR : propRel A R) (x : quot A R) -> B
という形になる。ただし
resp : (A B : U) (R : rel A) (f : A -> B) -> U resp A B R f = (x y : A) -> R x y -> Id B (f x) (f y)
もう一つ
setQuot : (A : U) (R:rel A) -> equivalence A R -> propRel A R -> set (quot A R))
というのも言えてほしいけど、証明してない(できるはずだけど)
証明自体は、面倒だけど直感的と思う。relQuoteの方は、propositional extensionality + functional extensionalityと、あと
eqPropFam : (A : U) (B : A -> U) (h : propFam A B) (au bv : Sigma A B) -> Id A au.1 bv.1 -> Id (Sigma A B) au bv
が重要。univQuotの方は、もっと面倒だが、頑張るとできる(説明がめんどい)。univQuotの二変数・N変数版は別途作る必要がある
例として、モノイドの項を割って、自由モノイドを作るみたいのを
に書いてみた。自由モノイドなので、リストでいいんだけど、例としては丁度いい
項の間の同値関係の定義として、一つはnormalizerを定義して、正規化したら、等しい項になるという形で定義できる。ただ、normalizerを正しく作ることは、一般には全然自明でないし、数学的な定義とも乖離してるし、存在するという保証もない。別の定義として
monoideq : (A:U) -> (x y:MonoidTerm A) -> U monoideq A x y = (r:rel (MonoidTerm A)) -> (p1:equivalence (MonoidTerm A) r) -> (p2:assocProp r) -> (p3:leftidProp r) -> (p4:rightidProp r) -> (p5:substProp r) -> (r x y) where assocProp : (r:rel (MonoidTerm A)) -> U assocProp r = (x y z:MonoidTerm A) -> (r (join x (join y z)) (join (join x y) z)) leftidProp : (r:rel (MonoidTerm A)) -> U leftidProp r = (x:MonoidTerm A) -> (r (join empty x) x) rightidProp : (r:rel (MonoidTerm A)) -> U rightidProp r = (x:MonoidTerm A) -> (r (join x empty) x) substProp : (r:rel (MonoidTerm A)) -> U substProp r = (x1 x2 y1 y2:MonoidTerm A) -> (r x1 x2) -> (r y1 y2) -> (r (join x1 y1) (join x2 y2))
とかでもいける。この2つの定義が同値であることは証明できる(上のgistでは面倒になって途中で諦めているけど)
多分本当は
monoideq : (A:U) -> (x y:MonoidTerm A) -> U monoideq A x y = (r:rel (MonoidTerm A)) -> (p0:propRel (MonoidTerm A) r) -> (p1:equivalence (MonoidTerm A) r) -> (p2:assocProp r) -> (p3:leftidProp r) -> (p4:rightidProp r) -> (p5:substProp r) -> (r x y) where assocProp : (r:rel (MonoidTerm A)) -> U assocProp r = (x y z:MonoidTerm A) -> (r (join x (join y z)) (join (join x y) z)) leftidProp : (r:rel (MonoidTerm A)) -> U leftidProp r = (x:MonoidTerm A) -> (r (join empty x) x) rightidProp : (r:rel (MonoidTerm A)) -> U rightidProp r = (x:MonoidTerm A) -> (r (join x empty) x) substProp : (r:rel (MonoidTerm A)) -> U substProp r = (x1 x2 y1 y2:MonoidTerm A) -> (r x1 x2) -> (r y1 y2) -> (r (join x1 y1) (join x2 y2))
としておかないと、monoideqがpropRelにならなくて困りそうな気がする
あまり説明になってないけど、実装見ればわかる気がする
quotient3.cub
https://gist.github.com/vertexoperator/c741f54b2d8a4dfa816f7a375205eae2
monoid.cub
https://gist.github.com/vertexoperator/a0ff3d1aefa6fddc63c0a06cf6b6efba
(追記)Sets in homotopy type theory
http://arxiv.org/abs/1305.3835
の2.4節Voevodsky's impredicative quotientsの構成と、本質的には同じと思う