\import Algebra.Group
\import Algebra.Group.Sub
\import Algebra.Monoid
\import Algebra.Monoid.MonoidHom
\import Algebra.Pointed
\import Function
\import Function.Meta
\import Logic
\import Logic.Meta
\import Paths
\import Paths.Meta
\record GroupHom \extends MonoidHom {
\override Dom : Group
\override Cod : Group
| func-ide => cancel_*-left (func ide) $ inv func-* *> pmap func ide-left *> inv ide-right
\lemma func-inverse {a : Dom} : func (inverse a) = inverse (func a)
=> MonoidHom.presInvElem \this (Group.makeInv a) (Group.makeInv (func a))
\func Kernel : NormalSubGroup Dom \cowith
| contains x => func x = ide
| contains_ide => func-ide
| contains_inverse {x : Dom} (p : func x = ide) =>
func (inverse x) ==< func-inverse >==
inverse (func x) ==< pmap inverse p >==
inverse ide ==< Group.inverse_ide >==
ide `qed
| isNormal g {h} p =>
func (g * h * inverse g) ==< func-* >==
func (g * h) * func (inverse g) ==< pmap (`* (func (inverse g))) func-* >==
func g * func h * func (inverse g) ==< pmap (\lam z => func g * z * func (inverse g)) p >==
func g * ide * func (inverse g) ==< pmap (`* (func (inverse g))) ide-right >==
func g * func (inverse g) ==< inv func-* >==
func (g * inverse g) ==< pmap func inverse-right >==
func ide ==< func-ide >==
ide `qed
| contains_* {x} {y} p q =>
func (x * y) ==< func-* >==
func x * func y ==< pmap (`* func y) p >==
ide * func y ==< ide-left >==
func y ==< q >==
ide `qed
\func TrivialKernel : \Prop => \Pi {g : Dom} -> Kernel g -> g = ide
\func same-images-test {a b : Dom} (p : func a = func b) : Kernel (inverse a * b) =>
func (inverse a * b) ==< func-* >==
func (inverse a) * func b ==< pmap (`* func b) func-inverse >==
inverse (func a) * func b ==< Group.equality-corrolary (func a) (func b) p >==
ide `qed
\lemma Kernel-injectivity-test (p : TrivialKernel) : IsInj func =>
\lam q => Group.equality-check (p (same-images-test q))
\lemma Kernel-injectivity-corrolary (p : IsInj func) : TrivialKernel =>
\lam q => p (q *> inv func-ide)
\func IsIsomorphism : \Prop => \Sigma (IsInj func) (IsSurj func)
} \where {
\func id {G : Group} : GroupHom G G \cowith
| func x => x
| func-* => idp
\func \fixl 8 compose \alias \infixl 8 ∘ {G H K : Group} (g : GroupHom H K) (f : GroupHom G H) : GroupHom G K \cowith
| func x => g (f x)
| func-* => pmap g f.func-* *> g.func-*
}
\record AddGroupHom \extends AddMonoidHom {
\override Dom : AddGroup
\override Cod : AddGroup
| func-zro => AddGroup.cancel-left (func 0) (inv func-+ *> pmap func zro-right *> inv zro-right)
\lemma func-negative {x : Dom} : func (negative x) = negative (func x)
=> AddGroup.cancel-left (func x) (inv (negative-right *> inv (pmap func negative-right *> func-zro) *> func-+))
\lemma func-minus {x y : Dom} : func (x - y) = func x - func y
=> func-+ *> pmap (_ +) func-negative
\lemma injective (p : \Pi {a : Dom} -> func a = 0 -> a = 0) : IsInj func
=> \lam q => AddGroup.fromZero $ p $ func-+ *> pmap (_ +) func-negative *> AddGroup.toZero q
\lemma func-*i {n : Int} {x : Dom} : func (n AddGroup.*i x) = n AddGroup.*i func x \elim n
| pos n => func-*n
| neg n => func-*n *> pmap (n AddMonoid.*n) func-negative
\protected \func Kernel : SubAddGroup Dom \cowith
| contains x => func x = zro
| contains_zro => func-zro
| contains_+ p q => rewrite (func-+, p, q, zro-left) idp
| contains_negative p => rewrite (func-negative, p, AddGroup.negative_zro) idp
\protected \func Image : SubAddGroup Cod \cowith
| contains x => ∃ (y : Dom) (func y = x)
| contains_zro => inP (zro, func-zro)
| contains_+ (inP (a, p)) (inP (b, q)) => inP (a + b, rewrite (func-+,p, q) idp)
| contains_negative (inP (a, p)) => inP (negative a, rewrite (AddGroupHom.func-negative, p) idp)
} \where {
\func toGroupHom {G H : AddGroup} (f : AddGroupHom G H) : GroupHom (AddGroup.toGroup G) (AddGroup.toGroup H) \cowith
| func x => f x
| func-* => f.func-+
\func fromGroupHom {G H : Group} (f : GroupHom G H) : AddGroupHom (AddGroup.fromGroup G) (AddGroup.fromGroup H) \cowith
| func x => f x
| func-+ => f.func-*
\func id {G : AddGroup} : AddGroupHom G G \cowith
| func x => x
| func-+ => idp
}