/- Copyright (c) 2016 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Zipperer, Jeremy Avigad We provide two versions of the quoptient construction. They use the same names and notation: one lives in the namespace 'quotient_group' and the other lives in the namespace 'quotient_group_general'. The first takes a group, A, and a normal subgroup, H. We have quotient H := the quotient of A by H qproj H a := the projection, with notation a' * G qproj H ' s := the image of s, with notation s / G extend H respf := given f : A → B respecting the equivalence relation, we get a function f : quotient G → B bar f := the above, G = ker f) The definition is constructive, using quotient types. We prove all the characteristic properties. As in the SSReflect library, we also provide a construction to quotient by an *arbitrary subgroup*. Now we have quotient H := the quotient of normalizer H by H qproj H a := still denoted a '* H, the projection when a is in normalizer H, arbitrary otherwise qproj H G := still denoted G / H, the image of the above extend H G respf := given a homomorphism on G with ker_in G f ⊆ H, extends to a homomorphism G / H bar G f := the above, with H = ker_in f G This quotient H is defined by composing the first one with the construction which turns normalizer H into a group. -/ import .subgroup_to_group theories.move open set function subtype classical quot namespace group_theory open coset_notation variables {A B C : Type} /- the quotient group -/ namespace quotient_group variables [group A] (H : set A) [is_normal H] definition lcoset_setoid [instance] : setoid A := setoid.mk (lcoset_equiv H) (equivalence_lcoset_equiv H) definition quotient := quot (lcoset_setoid H) private definition qone : quotient H := ⟦ 1 ⟧ private definition qmul : quotient H → quotient H → quotient H := quot.lift₂ (λ a b, ⟦a * b⟧) (λ a₁ a₂ b₁ b₂ e₁ e₂, quot.sound (lcoset_equiv_mul H e₁ e₂)) private definition qinv : quotient H → quotient H := quot.lift (λ a, ⟦a⁻¹⟧) (λ a₁ a₂ e, quot.sound (lcoset_equiv_inv H e)) private proposition qmul_assoc (a b c : quotient H) : qmul H (qmul H a b) c = qmul H a (qmul H b c) := quot.induction_on₂ a b (λ a b, quot.induction_on c (λ c, have H : ⟦a * b * c⟧ = ⟦a * (b * c)⟧, by rewrite mul.assoc, H)) private proposition qmul_qone (a : quotient H) : qmul H a (qone H) = a := quot.induction_on a (λ a', show ⟦a' * 1⟧ = ⟦a'⟧, by rewrite mul_one) private proposition qone_qmul (a : quotient H) : qmul H (qone H) a = a := quot.induction_on a (λ a', show ⟦1 * a'⟧ = ⟦a'⟧, by rewrite one_mul) private proposition qmul_left_inv (a : quotient H) : qmul H (qinv H a) a = qone H := quot.induction_on a (λ a', show ⟦a'⁻¹ * a'⟧ = ⟦1⟧, by rewrite mul.left_inv) protected definition group [instance] : group (quotient H) := ⦃ group, mul := qmul H, inv := qinv H, one := qone H, mul_assoc := qmul_assoc H, mul_one := qmul_qone H, one_mul := qone_qmul H, mul_left_inv := qmul_left_inv H ⦄ -- these theorems characterize the quotient group definition qproj (a : A) : quotient H := ⟦a⟧ infix ` '* `:65 := λ {A' : Type} [group A'] a H' [is_normal H'], qproj H' a infix ` / ` := λ {A' : Type} [group A'] G H' [is_normal H'], qproj H' ' G proposition is_hom_qproj [instance] : is_hom (qproj H) := is_mul_hom.mk (λ a b, rfl) variable {H} proposition qproj_eq_qproj {a b : A} (h : a * H = b * H) : a '* H = b '* H := quot.sound h proposition lcoset_eq_lcoset_of_qproj_eq_qproj {a b : A} (h : a '* H = b '* H) : a * H = b * H := quot.exact h variable (H) proposition qproj_eq_qproj_iff (a b : A) : a '* H = b '* H ↔ a * H = b * H := iff.intro lcoset_eq_lcoset_of_qproj_eq_qproj qproj_eq_qproj proposition ker_qproj [is_subgroup H] : ker (qproj H) = H := ext (take a, begin rewrite [↑ker, mem_set_of_iff, -hom_one (qproj H), qproj_eq_qproj_iff, one_lcoset], show a * H = H ↔ a ∈ H, from iff.intro mem_of_lcoset_eq_self lcoset_eq_self_of_mem end) proposition qproj_eq_one_iff [is_subgroup H] (a : A) : a '* H = 1 ↔ a ∈ H := have H : qproj H a = 1 ↔ a ∈ ker (qproj H), from iff.rfl, by rewrite [H, ker_qproj] variable {H} proposition qproj_eq_one_of_mem [is_subgroup H] {a : A} (aH : a ∈ H) : a '* H = 1 := iff.mpr (qproj_eq_one_iff H a) aH proposition mem_of_qproj_eq_one [is_subgroup H] {a : A} (h : a '* H = 1) : a ∈ H := iff.mp (qproj_eq_one_iff H a) h variable (H) proposition surjective_qproj : surjective (qproj H) := take y, quot.induction_on y (λ a, exists.intro a rfl) variable {H} proposition quotient_induction {P : quotient H → Prop} (h : ∀ a, P (a '* H)) : ∀ a, P a := surjective_induction (surjective_qproj H) h proposition quotient_induction₂ {P : quotient H → quotient H → Prop} (h : ∀ a₁ a₂, P (a₁ '* H) (a₂ '* H)) : ∀ a₁ a₂, P a₁ a₂ := surjective_induction₂ (surjective_qproj H) h variable (H) proposition image_qproj_self [is_subgroup H] : H / H = '{1} := eq_of_subset_of_subset (image_subset_of_maps_to (take x, suppose x ∈ H, show x '* H ∈ '{1}, from mem_singleton_of_eq (qproj_eq_one_of_mem `x ∈ H`))) (take x, suppose x ∈ '{1}, have x = 1, from eq_of_mem_singleton this, show x ∈ H / H, by rewrite this; apply mem_image_of_mem _ one_mem) -- extending a function A → B to a function A / H → B section respf variable {H} variables {f : A → B} (respf : ∀ a₁ a₂, a₁ * H = a₂ * H → f a₁ = f a₂) definition extend : quotient H → B := quot.lift f respf proposition extend_qproj (a : A) : extend respf (a '* H) = f a := rfl proposition extend_comp_qproj : extend respf ∘ (qproj H) = f := rfl proposition image_extend (G : set A) : (extend respf) ' (G / H) = f ' G := by rewrite [-image_comp] variable [group B] proposition is_hom_extend [instance] [is_hom f] : is_hom (extend respf) := is_mul_hom.mk (take a b, show (extend respf (a * b)) = (extend respf a) * (extend respf b), from quot.induction_on₂ a b (take a b, hom_mul f a b)) proposition ker_extend : ker (extend respf) = ker f / H := eq_of_subset_of_subset (quotient_induction (take a, assume Ha : qproj H a ∈ ker (extend respf), have f a = 1, from Ha, show a '* H ∈ ker f / H, from mem_image_of_mem _ this)) (image_subset_of_maps_to (take a, assume h : a ∈ ker f, show extend respf (a '* H) = 1, from h)) end respf end quotient_group /- the first homomorphism theorem for the quotient group -/ namespace quotient_group variables [group A] [group B] (f : A → B) [is_hom f] lemma eq_of_lcoset_equiv_ker ⦃a b : A⦄ (h : lcoset_equiv (ker f) a b) : f a = f b := have b⁻¹ * a ∈ ker f, from inv_mul_mem_of_lcoset_eq_lcoset h, eq.symm (eq_of_inv_mul_mem_ker this) definition bar : quotient (ker f) → B := extend (eq_of_lcoset_equiv_ker f) proposition bar_qproj (a : A) : bar f (a '* ker f) = f a := rfl proposition is_hom_bar [instance] : is_hom (bar f) := is_hom_extend _ proposition image_bar (G : set A) : bar f ' (G / ker f) = f ' G := by rewrite [↑bar, image_extend] proposition image_bar_univ : bar f ' univ = f ' univ := by rewrite [↑bar, -image_eq_univ_of_surjective (surjective_qproj (ker f)), image_extend] proposition surj_on_bar : surj_on (bar f) univ (f ' univ) := by rewrite [↑surj_on, image_bar_univ]; apply subset.refl proposition ker_bar_eq : ker (bar f) = '{1} := by rewrite [↑bar, ker_extend, image_qproj_self] proposition injective_bar : injective (bar f) := injective_of_ker_eq_singleton_one (ker_bar_eq f) end quotient_group /- a generic morphism extension property -/ section variables [group A] [group B] [group C] variables (G : set A) [is_subgroup G] variables (g : A → C) (f : A → B) noncomputable definition gen_extend : C → B := λ c, f (inv_fun g G 1 c) variables {G g f} proposition eq_of_ker_in_subset {a₁ a₂ : A} (a₁G : a₁ ∈ G) (a₂G : a₂ ∈ G) [is_hom_on g G] [is_hom_on f G] (Hker : ker_in g G ⊆ ker f) (H' : g a₁ = g a₂) : f a₁ = f a₂ := have memG : a₁⁻¹ * a₂ ∈ G, from mul_mem (inv_mem a₁G) a₂G, have a₁⁻¹ * a₂ ∈ ker_in g G, from inv_mul_mem_ker_in_of_eq a₁G a₂G H', have a₁⁻¹ * a₂ ∈ ker_in f G, from and.intro (Hker this) memG, show f a₁ = f a₂, from eq_of_inv_mul_mem_ker_in a₁G a₂G this proposition gen_extend_spec [is_hom_on g G] [is_hom_on f G] (Hker : ker_in g G ⊆ ker f) {a : A} (aG : a ∈ G) : gen_extend G g f (g a) = f a := eq_of_ker_in_subset (inv_fun_spec' aG) aG Hker (inv_fun_spec aG) proposition is_hom_on_gen_extend [is_hom_on g G] [is_hom_on f G] (Hker : ker_in g G ⊆ ker f) : is_hom_on (gen_extend G g f) (g ' G) := have is_subgroup (g ' G), from is_subgroup_image g G, take c₁, assume c₁gG : c₁ ∈ g ' G, take c₂, assume c₂gG : c₂ ∈ g ' G, let ginv := inv_fun g G 1 in have Hginv : maps_to ginv (g ' G) G, from maps_to_inv_fun one_mem, have ginvc₁ : ginv c₁ ∈ G, from Hginv c₁gG, have ginvc₂ : ginv c₂ ∈ G, from Hginv c₂gG, have ginvc₁c₂ : ginv (c₁ * c₂) ∈ G, from Hginv (mul_mem c₁gG c₂gG), have HH : ∀₀ c ∈ g ' G, g (ginv c) = c, from λ a aG, right_inv_on_inv_fun_of_surj_on _ (surj_on_image g G) aG, have eq₁ : g (ginv c₁) = c₁, from HH c₁gG, have eq₂ : g (ginv c₂) = c₂, from HH c₂gG, have eq₃ : g (ginv (c₁ * c₂)) = c₁ * c₂, from HH (mul_mem c₁gG c₂gG), have g (ginv (c₁ * c₂)) = g ((ginv c₁) * (ginv c₂)), by rewrite [eq₃, hom_on_mul g ginvc₁ ginvc₂, eq₁, eq₂], have f (ginv (c₁ * c₂)) = f (ginv c₁ * ginv c₂), from eq_of_ker_in_subset (ginvc₁c₂) (mul_mem ginvc₁ ginvc₂) Hker this, show f (ginv (c₁ * c₂)) = f (ginv c₁) * f (ginv c₂), by rewrite [this, hom_on_mul f ginvc₁ ginvc₂] end /- quotient by an arbitrary group, not necessarily normal -/ namespace quotient_group_general variables [group A] (H : set A) [is_subgroup H] lemma is_normal_to_group_of_normalizer [instance] : is_normal (to_group_of (normalizer H) ' H) := have H1 : is_normal_in (to_group_of (normalizer H) ' H) (to_group_of (normalizer H) ' (normalizer H)), from is_normal_in_image_image (subset_normalizer_self H) (to_group_of (normalizer H)), have H2 : to_group_of (normalizer H) ' (normalizer H) = univ, from image_to_group_of_eq_univ (normalizer H), is_normal_of_is_normal_in_univ (by rewrite -H2; exact H1) section quotient_group open quotient_group noncomputable definition quotient : Type := quotient (to_group_of (normalizer H) ' H) noncomputable definition group_quotient [instance] : group (quotient H) := quotient_group.group (to_group_of (normalizer H) ' H) noncomputable definition qproj : A → quotient H := qproj (to_group_of (normalizer H) ' H) ∘ (to_group_of (normalizer H)) infix ` '* `:65 := λ {A' : Type} [group A'] a H' [is_subgroup H'], qproj H' a infix ` / ` := λ {A' : Type} [group A'] G H' [is_subgroup H'], qproj H' ' G proposition is_hom_on_qproj [instance] : is_hom_on (qproj H) (normalizer H) := have H₀ : is_hom_on (to_group_of (normalizer H)) (normalizer H), from is_hom_on_to_group_of (normalizer H), have H₁ : is_hom_on (quotient_group.qproj (to_group_of (normalizer H) ' H)) univ, from iff.mpr (is_hom_on_univ_iff (quotient_group.qproj (to_group_of (normalizer H) ' H))) (is_hom_qproj (to_group_of (normalizer H) ' H)), is_hom_on_comp H₀ H₁ (maps_to_univ (to_group_of (normalizer H)) (normalizer H)) proposition is_hom_on_qproj' [instance] (G : set A) [is_normal_in H G] : is_hom_on (qproj H) G := is_hom_on_of_subset (qproj H) (subset_normalizer G H) proposition ker_in_qproj : ker_in (qproj H) (normalizer H) = H := let tg := to_group_of (normalizer H) in begin rewrite [↑ker_in, ker_eq_preimage_one, ↑qproj, preimage_comp, -ker_eq_preimage_one], have is_hom_on tg H, from is_hom_on_of_subset _ (subset_normalizer_self H), have is_subgroup (tg ' H), from is_subgroup_image tg H, krewrite [ker_qproj, to_group_of_preimage_to_group_of_image (subset_normalizer_self H)] end end quotient_group variable {H} proposition qproj_eq_qproj_iff {a b : A} (Ha : a ∈ normalizer H) (Hb : b ∈ normalizer H) : a '* H = b '* H ↔ a * H = b * H := by rewrite [lcoset_eq_lcoset_iff, eq_iff_inv_mul_mem_ker_in Ha Hb, ker_in_qproj, -inv_mem_iff, mul_inv, inv_inv] proposition qproj_eq_qproj {a b : A} (Ha : a ∈ normalizer H) (Hb : b ∈ normalizer H) (h : a * H = b * H) : a '* H = b '* H := iff.mpr (qproj_eq_qproj_iff Ha Hb) h proposition lcoset_eq_lcoset_of_qproj_eq_qproj {a b : A} (Ha : a ∈ normalizer H) (Hb : b ∈ normalizer H) (h : a '* H = b '* H) : a * H = b * H := iff.mp (qproj_eq_qproj_iff Ha Hb) h variable (H) proposition qproj_mem {a : A} {G : set A} (aG : a ∈ G) : a '* H ∈ G / H := mem_image_of_mem _ aG proposition qproj_one : 1 '* H = 1 := hom_on_one (qproj H) (normalizer H) variable {H} proposition mem_of_qproj_mem {a : A} (anH : a ∈ normalizer H) {G : set A} (HsubG : H ⊆ G) [is_subgroup G] [is_normal_in H G] (aHGH : a '* H ∈ G / H): a ∈ G := have GH : G ⊆ normalizer H, from subset_normalizer G H, obtain b [bG (bHeq : b '* H = a '* H)], from aHGH, have b * H = a * H, from lcoset_eq_lcoset_of_qproj_eq_qproj (GH bG) anH bHeq, have a ∈ b * H, by rewrite this; apply mem_lcoset_self, have a ∈ b * G, from lcoset_subset_lcoset b HsubG this, show a ∈ G, by rewrite [lcoset_eq_self_of_mem bG at this]; apply this proposition qproj_eq_one_iff {a : A} (Ha : a ∈ normalizer H) : a '* H = 1 ↔ a ∈ H := by rewrite [-hom_on_one (qproj H) (normalizer H), qproj_eq_qproj_iff Ha one_mem, one_lcoset, lcoset_eq_self_iff] proposition qproj_eq_one_of_mem {a : A} (aH : a ∈ H) : a '* H = 1 := iff.mpr (qproj_eq_one_iff (subset_normalizer_self H aH)) aH proposition mem_of_qproj_eq_one {a : A} (Ha : a ∈ normalizer H) (h : a '* H = 1) : a ∈ H := iff.mp (qproj_eq_one_iff Ha) h variable (H) section open quotient_group proposition surj_on_qproj_normalizer : surj_on (qproj H) (normalizer H) univ := have H₀ : surj_on (to_group_of (normalizer H)) (normalizer H) univ, from surj_on_to_group_of_univ (normalizer H), have H₁ : surj_on (quotient_group.qproj (to_group_of (normalizer H) ' H)) univ univ, from surj_on_univ_of_surjective univ (surjective_qproj _), surj_on_comp H₁ H₀ end variable {H} proposition quotient_induction {P : quotient H → Prop} (hyp : ∀₀ a ∈ normalizer H, P (a '* H)) : ∀ a, P a := surj_on_univ_induction (surj_on_qproj_normalizer H) hyp proposition quotient_induction₂ {P : quotient H → quotient H → Prop} (hyp : ∀₀ a₁ ∈ normalizer H, ∀₀ a₂ ∈ normalizer H, P (a₁ '* H) (a₂ '* H)) : ∀ a₁ a₂, P a₁ a₂ := surj_on_univ_induction₂ (surj_on_qproj_normalizer H) hyp variable (H) proposition image_qproj_self : H / H = '{1} := eq_of_subset_of_subset (image_subset_of_maps_to (take x, suppose x ∈ H, show x '* H ∈ '{1}, from mem_singleton_of_eq (qproj_eq_one_of_mem `x ∈ H`))) (take x, suppose x ∈ '{1}, have x = 1, from eq_of_mem_singleton this, show x ∈ H / H, by rewrite [this, -qproj_one H]; apply mem_image_of_mem _ one_mem) section respf variable (H) variables [group B] (G : set A) [is_subgroup G] (f : A → B) noncomputable definition extend : quotient H → B := gen_extend G (qproj H) f variables [is_hom_on f G] [is_normal_in H G] private proposition aux : is_hom_on (qproj H) G := is_hom_on_of_subset (qproj H) (subset_normalizer G H) local attribute [instance] aux variables {H f} private proposition aux' (respf : H ⊆ ker f) : ker_in (qproj H) G ⊆ ker f := subset.trans (show ker_in (qproj H) G ⊆ ker_in (qproj H) (normalizer H), from inter_subset_inter_left _ (subset_normalizer G H)) (by rewrite [ker_in_qproj]; apply respf) variable {G} proposition extend_qproj (respf : H ⊆ ker f) {a : A} (aG : a ∈ G) : extend H G f (a '* H) = f a := gen_extend_spec (aux' G respf) aG proposition image_extend (respf : H ⊆ ker f) {s : set A} (ssubG : s ⊆ G) : extend H G f ' (s / H) = f ' s := begin rewrite [-image_comp], apply image_eq_image_of_eq_on, intro a amems, apply extend_qproj respf (ssubG amems) end variable (G) proposition is_hom_on_extend [instance] (respf : H ⊆ ker f) : is_hom_on (extend H G f) (G / H) := by unfold extend; apply is_hom_on_gen_extend (aux' G respf) variable {G} proposition ker_in_extend [is_subgroup G] (respf : H ⊆ ker f) (HsubG : H ⊆ G) : ker_in (extend H G f) (G / H) = (ker_in f G) / H := begin apply ext, intro aH, cases surj_on_qproj_normalizer H (show aH ∈ univ, from trivial) with a atemp, cases atemp with anH aHeq, rewrite -aHeq, apply iff.intro, { intro akerin, cases akerin with aker ain, have a '* H ∈ G / H, from ain, have a ∈ G, from mem_of_qproj_mem anH HsubG this, have a '* H ∈ ker (extend H G f), from aker, have extend H G f (a '* H) = 1, from this, have f a = extend H G f (a '* H), from eq.symm (extend_qproj respf `a ∈ G`), have f a = 1, by rewrite this; assumption, have a ∈ ker_in f G, from and.intro this `a ∈ G`, show a '* H ∈ (ker_in f G) / H, from qproj_mem H this}, intro aHker, have aker : a ∈ ker_in f G, begin have Hsub : H ⊆ ker_in f G, from subset_inter respf HsubG, have is_normal_in H (ker_in f G), from subset.trans (inter_subset_right (ker f) G) (subset_normalizer G H), apply (mem_of_qproj_mem anH Hsub aHker) end, have a ∈ G, from and.right aker, have f a = 1, from and.left aker, have extend H G f (a '* H) = 1, from eq.trans (extend_qproj respf `a ∈ G`) this, show a '* H ∈ ker_in (extend H G f) (G / H), from and.intro this (qproj_mem H `a ∈ G`) end /- (comment from Jeremy) This version kills the elaborator. I don't know why. Tracing class instances doesn't show a problem. My best guess is that it is the backgracking from the "obtain". proposition ker_in_extend [is_subgroup G] (respf : H ⊆ ker f) (HsubG : H ⊆ G) : ker_in (extend H G f) (qproj H ' G) = qproj H ' (ker_in f G) := ext (take aH, obtain a [(anH : a ∈ normalizer H) (aHeq : a '* H = aH)], from surj_on_qproj_normalizer H (show aH ∈ univ, from trivial), begin rewrite -aHeq, apply iff.intro, unfold ker_in, exact (assume aker : a '* H ∈ ker (extend H G f) ∩ (qproj H ' G), have a '* H ∈ qproj H ' G, from and.right aker, have a ∈ G, from mem_of_qproj_mem anH HsubG this, -- Uncommenting the next line of code slows things down dramatically. -- Uncommenting the one after kills the system. -- have a '* H ∈ ker (extend H G f), from and.left aker, -- have extend H G f (a '* H) = 1, from this, -- have f a = extend H G f (a '* H), from eq.symm (extend_qproj respf `a ∈ G`), -- have f a = 1, by rewrite [-this, extend_qproj respf aG], -- have a ∈ ker_in f G, from and.intro this `a ∈ G`, show a '* H ∈ qproj H ' (ker_in f G), from sorry), exact (assume hyp : a '* H ∈ qproj H ' (ker_in f G), show a '* H ∈ ker_in (extend H G f) (qproj H ' G), from sorry) end) -/ end respf attribute quotient [irreducible] end quotient_group_general /- the first homomorphism theorem for general quotient groups -/ namespace quotient_group_general variables [group A] [group B] (G : set A) [is_subgroup G] variables (f : A → B) [is_hom_on f G] noncomputable definition bar : quotient (ker_in f G) → B := extend (ker_in f G) G f proposition bar_qproj {a : A} (aG : a ∈ G) : bar G f (a '* ker_in f G) = f a := extend_qproj (inter_subset_left _ _) aG proposition is_hom_on_bar [instance] : is_hom_on (bar G f) (G / ker_in f G) := have is_subgroup (ker f ∩ G), from is_subgroup_ker_in f G, have is_normal_in (ker f ∩ G) G, from is_normal_in_ker_in f G, is_hom_on_extend G (inter_subset_left _ _) proposition image_bar {s : set A} (ssubG : s ⊆ G) : bar G f ' (s / ker_in f G) = f ' s := have is_subgroup (ker f ∩ G), from is_subgroup_ker_in f G, have is_normal_in (ker f ∩ G) G, from is_normal_in_ker_in f G, image_extend (inter_subset_left _ _) ssubG proposition surj_on_bar : surj_on (bar G f) (G / ker_in f G) (f ' G) := by rewrite [↑surj_on, image_bar G f (@subset.refl _ G)]; apply subset.refl proposition ker_in_bar : ker_in (bar G f) (G / ker_in f G) = '{1} := have H₀ : ker_in f G ⊆ ker f, from inter_subset_left _ _, have H₁ : ker_in f G ⊆ G, from inter_subset_right _ _, by rewrite [↑bar, ker_in_extend H₀ H₁, image_qproj_self] proposition inj_on_bar : inj_on (bar G f) (G / ker_in f G) := inj_on_of_ker_in_eq_singleton_one (ker_in_bar G f) end quotient_group_general end group_theory