(* (c) Copyright 2006-2016 Microsoft Corporation and Inria.                  *)
(* Distributed under the terms of CeCILL-B.                                  *)
From mathcomp
From mathcomp
(******************************************************************************)
(* This file contains the definitions of:                                     *)
(*                                                                            *)
(*   {morphism D >-> rT} ==                                                   *)
(*     the structure type of functions that are group morphisms mapping a     *)
(*     domain set D : {set aT} to a type rT; rT must have a finGroupType      *)
(*     structure, and D is usually a group (most of the theory expects this). *)
(*            mfun == the coercion projecting {morphism D >-> rT} to aT -> rT *)
(*                                                                            *)
(* Basic examples:                                                            *)
(*            idm D == the identity morphism with domain D, or more precisely *)
(*                     the identity function, but with a canonical            *)
(*                     {morphism G -> gT} structure.                          *)
(*          trivm D == the trivial morphism with domain D.                    *)
(* If f has a {morphism D >-> rT} structure                                   *)
(*           'dom f == D, the domain of f.                                    *)
(*           f @* A == the image of A by f, where f is defined.               *)
(*                  := f @: (D :&: A)                                         *)
(*        f @*^-1 R == the pre-image of R by f, where f is defined.           *)
(*                  :=  D :&: f @^-1: R                                       *)
(*           'ker f == the kernel of f.                                       *)
(*                  :=  f @*^-1 1                                             *)
(*         'ker_G f == the kernel of f restricted to G.                       *)
(*                  :=  G :&: 'ker f (this is a pure notation)                *)
(*          'injm f <=> f injective on D.                                     *)
(*                  <-> ker f \subset 1 (this is a pure notation)             *)
(*        invm injf == the inverse morphism of f, with domain f @* D, when f  *)
(*                     is injective (injf : 'injm f).                         *)
(*    restrm f sDom == the restriction of f to a subset A of D, given         *)
(*                     (sDom : A \subset D); restrm f sDom is transparently   *)
(*                     identical to f; the restrmP and domP lemmas provide    *)
(*                     opaque restrictions.                                   *)
(*     invm f infj  == the inverse morphism for an injective f, with domain   *)
(*                     f @* D, given (injf : 'injm f).                        *)
(*                                                                            *)
(*      G \isog H  <=> G and H are isomorphic as groups.                      *)
(*       H \homg G <=> H is a homomorphic image of G.                         *)
(*      isom G H f <=> f maps G isomorphically to H, provided D contains G.   *)
(*                  := f @: G^# == H^#                                        *)
(*                                                                            *)
(* If, moreover, g : {morphism G >-> gT} with G : {group aT},                 *)
(*  factm sKer sDom == the (natural) factor morphism mapping f @* G to g @* G *)
(*                     with sDom : G \subset D, sKer : 'ker f \subset 'ker g. *)
(*    ifactm injf g == the (natural) factor morphism mapping f @* G to g @* G *)
(*                     when f is injective (injf : 'injm f); here g must      *)
(*                     denote an actual morphism structure, not its function  *)
(*                     projection.                                            *)
(*                                                                            *)
(* If g has a {morphism G >-> aT} structure for any G : {group gT}, then      *)
(*           f \o g has a canonical {morphism g @*^-1 D >-> rT} structure.    *)
(*                                                                            *)
(* Finally, for an arbitrary function f : aT -> rT                            *)
(*     morphic D f <=> f preserves group multiplication in D, i.e.,           *)
(*                     f (x * y) = (f x) * (f y) for all x, y in D.           *)
(*        morphm fM == a function identical to f, but with a canonical        *)
(*                     {morphism D >-> rT} structure, given fM : morphic D f. *)
(*      misom D C f <=> f is a morphism that maps D isomorphically to C.      *)
(*                  := morphic D f && isom D C f                              *)
(******************************************************************************)
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Reserved Notation "x \isog y" (at level 70).
Section MorphismStructure.
Variables aT rT : finGroupType.
Structure morphism (D : {set aT}) : Type := Morphism {
mfun :> aT -> FinGroup.sort rT;
_ : {in D &, {morph mfun : x y / x * y}}
}.
(* We give the 'lightest' possible specification to define morphisms: local   *)
(* congruence, in D, with the group law of aT. We then provide the properties *)
(* for the 'textbook' notion of morphism, when the required structures are    *)
(* available (e.g. its domain is a group).                                    *)
Definition morphism_for D of phant rT := morphism D.
Definition clone_morphism D f :=
let: Morphism _ fM := f
return {type of @Morphism D for f} -> morphism_for D (Phant rT)
in fun k => k fM.
Variables (D A : {set aT}) (R : {set rT}) (x : aT) (y : rT) (f : aT -> rT).
Variant morphim_spec : Prop := MorphimSpec z & z \in D & z \in A & y = f z.

(* Specifications: *)
Lemma morphimP : reflect morphim_spec (y \in f @: (D :&: A)).
Lemma morphpreP : reflect (x \in D /\ f x \in R) (x \in D :&: f @^-1: R).
Lemma morphV : {in D, {morph f : x / x^-1}}.
Lemma morphJ : {in D &, {morph f : x y / x ^ y}}.
Lemma morphR : {in D &, {morph f : x y / [~ x, y]}}.
Lemma morphimIim A : f @* D :&: f @* A = f @* A.
Lemma morphpreS R S : R \subset S -> f @*^-1 R \subset f @*^-1 S.
Lemma morphim0 : f @* set0 = set0.
Lemma morphpreV R : f @*^-1 R^-1 = (f @*^-1 R)^-1.
Lemma morphimMl A B : A \subset D -> f @* (A * B) = f @* A * f @* B.
Lemma morphimMr A B : B \subset D -> f @* (A * B) = f @* A * f @* B.
Lemma morphpreMl R S :
R \subset f @* D -> f @*^-1 (R * S) = f @*^-1 R * f @*^-1 S.
Lemma morphimJ A x : x \in D -> f @* (A :^ x) = f @* A :^ f x.
Lemma morphpreJ R x : x \in D -> f @*^-1 (R :^ f x) = f @*^-1 R :^ x.
Lemma morphim_class x A :
x \in D -> A \subset D -> f @* (x ^: A) = f x ^: f @* A.
Lemma classes_morphim A :
A \subset D -> classes (f @* A) = [set f @* xA | xA in classes A].
Lemma morphimT : f @* setT = f @* D.
Lemma ker_rcoset x y :
x \in D -> y \in D -> f x = f y -> exists2 z, z \in 'ker f & x = z * y.
Lemma ker_normal : 'ker f <| D.
Lemma morphimIG A G : 'ker f \subset G -> f @* (A :&: G) = f @* A :&: f @* G.
Lemma morphimDG A G : 'ker f \subset G -> f @* (A :\: G) = f @* A :\: f @* G.
Lemma morphimD1 A : (f @* A)^# \subset f @* A^#.
Lemma morphim_groupset G : group_set (f @* G).
Canonical morphpre_group fPh M :=
@group _ (morphpre fPh M) (morphpre_groupset M).