(* (c) Copyright 2006-2016 Microsoft Corporation and Inria.                  *)
(* Distributed under the terms of CeCILL-B.                                  *)
From mathcomp
From mathcomp
From mathcomp
(******************************************************************************)
(*  * Finite dimensional field extentions                                     *)
(*      fieldExtType F == the interface type for finite field extensions of F *)
(*                        it simply combines the fieldType and FalgType F     *)
(*                        interfaces.                                         *)
(* [fieldExtType F of L] == a fieldExt F structure for a type L that has both *)
(*                        FalgType F and fieldType canonical instances. The   *)
(*                        field class instance must be manifest with explicit *)
(*                        comRing, idomain, and field mixins. If L has an     *)
(*                        abstract field class should use the 'for' variant.  *)
(* [fieldExtType F of L for K] == a fieldExtType F structure for a type L     *)
(*                        that has an FalgType F canonical structure, given   *)
(*                        a K : fieldType whose unitRingType projection       *)
(*                        coincides with the canonical unitRingType for F.    *)
(*        {subfield L} == the type of subfields of L that are also extensions *)
(*                        of F; since we are in a finite dimensional setting  *)
(*                        these are exactly the F-subalgebras of L, and       *)
(*                        indeed {subfield L} is just display notation for    *)
(*                        {aspace L} when L is an extFieldType.               *)
(*  --> All aspace operations apply to {subfield L}, but there are several    *)
(*      additional lemmas and canonical instances specific to {subfield L}    *)
(*      spaces, e.g., subvs_of E is an extFieldType F when E : {subfield L}.  *)
(*  --> Also note that not all constructive subfields have type {subfield E}  *)
(*      in the same way that not all constructive subspaces have type         *)
(*      {vspace E}. These types only include the so called "detachable"       *)
(*      subspaces (and subalgebras).                                          *)
(*                                                                            *)
(* (E :&: F)%AS, (E * F)%AS == the intersection and product (meet and join)   *)
(*                           of E and F as subfields.                         *)
(*    subFExtend iota z p == Given a field morphism iota : F -> L, this is a  *)
(*                           type for the field F^iota(z) obtained by         *)
(*                           adjoining z to the image of F in L under iota.   *)
(*                           The construction requires a non-zero polynomial  *)
(*                           p in F such that z is a root of p^iota; it       *)
(*                           returns the field F^iota if this is not so.      *)
(*                           However, p need not be irredicible.              *)
(*            subfx_inj x == The injection of F^iota(z) into L.               *)
(*   inj_subfx iota z p x == The injection of F into F^iota(z).               *)
(*  subfx_eval iota z p q == Given q : {poly F} returns q.[z] as a value of   *)
(*                           type F^iota(z).                                  *)
(*    subfx_root iota z p == The generator of F^iota(z) over F.               *)
(* SubFieldExtType pz0 irr_p == A fieldExtType F structure for F^iota(z)      *)
(*                           (more precisely, subFExtend iota z p), given     *)
(*                           proofs pz0: root (map_poly iota p) z and         *)
(*                           irr_p : irreducible_poly p. The corresponding    *)
(*                           vectType substructure (SubfxVectType pz0 irr_p)  *)
(*                           has dimension (size p).-1 over F.                *)
(*            minPoly K x == the monic minimal polynomial of x over the       *)
(*                           subfield K.                                      *)
(*      adjoin_degree K x == the degree of the minimial polynomial or the     *)
(*                           dimension of K(x)/K.                             *)
(*     Fadjoin_poly K x y == a polynomial p over K such that y = p.[x].       *)
(*                                                                            *)
(*            fieldOver F == L, but with an extFieldType (subvs_of F)         *)
(*                           structure, for F : {subfield L}                  *)
(*         vspaceOver F V == the smallest subspace of fieldOver F containing  *)
(*                           V; this coincides with V if V is an F-module.    *)
(*        baseFieldType L == L, but with an extFieldType F0 structure, when L *)
(*                           has a canonical extFieldType F structure and F   *)
(*                           in turn has an extFieldType F0 structure.        *)
(*           baseVspace V == the subspace of baseFieldType L that coincides   *)
(*                           with V : {vspace L}.                             *)
(* --> Some caution must be exercised when using fieldOver and baseFieldType, *)
(*     because these are convertible to L while carrying different Lmodule    *)
(*     structures. This means that the safeguards engineered in the ssralg    *)
(*     library that normally curb the Coq kernel's inclination to diverge are *)
(*     no longer effectcive, so additional precautions should be taken when   *)
(*     matching or rewriting terms of the form a *: u, because Coq may take   *)
(*     forever to realize it's dealing with a *: in the wrong structure. The  *)
(*     baseField_scaleE and fieldOver_scaleE lemmas should be used to expand  *)
(*     or fold such "trans-structure" operations explicitly beforehand.       *)
(******************************************************************************)
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Local Open Scope ring_scope.
Module FieldExt.
Section FieldExt.
Variable R : ringType.
Record class_of T := Class {
base : Falgebra.class_of R T;
comm_ext : commutative (Ring.mul base);
idomain_ext : IntegralDomain.axiom (Ring.Pack base);
field_ext : Field.mixin_of (UnitRing.Pack base)
}.
Local Coercion base : class_of >-> Falgebra.class_of.
Section Bases.
Variables (T : Type) (c : class_of T).
Definition base1 := ComRing.Class (@comm_ext T c).
Definition base2 := @ComUnitRing.Class T base1 c.
Definition base3 := @IntegralDomain.Class T base2 (@idomain_ext T c).
Definition base4 := @Field.Class T base3 (@field_ext T c).
End Bases.
Local Coercion base1 : class_of >-> ComRing.class_of.
Local Coercion base2 : class_of >-> ComUnitRing.class_of.
Local Coercion base3 : class_of >-> IntegralDomain.class_of.
Local Coercion base4 : class_of >-> Field.class_of.
Structure type (phR : phant R) := Pack {sort; _ : class_of sort}.
Local Coercion sort : type >-> Sortclass.
Variables (phR : phant R) (T : Type) (cT : type phR).
Definition class := let: Pack _ c :=  cT return class_of cT in c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of xT).
Definition pack :=
fun (bT : Falgebra.type phR) b
& phant_id (Falgebra.class bT : Falgebra.class_of R bT)
(b : Falgebra.class_of R T) =>
fun mT Cm IDm Fm & phant_id (Field.class mT) (@Field.Class T
(@IntegralDomain.Class T (@ComUnitRing.Class T (@ComRing.Class T b
Cm) b) IDm) Fm) => Pack phR (@Class T b Cm IDm Fm).
Definition pack_eta K :=
let cK := Field.class K in let Cm := ComRing.mixin cK in
let IDm := IntegralDomain.mixin cK in let Fm := Field.mixin cK in
fun (bT : Falgebra.type phR) b & phant_id (Falgebra.class bT) b =>
fun cT_ & phant_id (@Class T b) cT_ => @Pack phR T (cT_ Cm IDm Fm).
Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition zmodType := @Zmodule.Pack cT xclass.
Definition ringType := @Ring.Pack cT xclass.
Definition unitRingType := @UnitRing.Pack cT xclass.
Definition comRingType := @ComRing.Pack cT xclass.
Definition comUnitRingType := @ComUnitRing.Pack cT xclass.
Definition idomainType := @IntegralDomain.Pack cT xclass.
Definition fieldType := @Field.Pack cT xclass.
Definition lmodType := @Lmodule.Pack R phR cT xclass.
Definition lalgType := @Lalgebra.Pack R phR cT xclass.
Definition algType := @Algebra.Pack R phR cT xclass.
Definition unitAlgType := @UnitAlgebra.Pack R phR cT xclass.
Definition vectType := @Vector.Pack R phR cT xclass.
Definition FalgType := @Falgebra.Pack R phR cT xclass.
Definition Falg_comRingType := @ComRing.Pack FalgType xclass.
Definition Falg_comUnitRingType := @ComUnitRing.Pack FalgType xclass.
Definition Falg_idomainType := @IntegralDomain.Pack FalgType xclass.
Definition Falg_fieldType := @Field.Pack FalgType xclass.
Definition vect_comRingType := @ComRing.Pack vectType xclass.
Definition vect_comUnitRingType := @ComUnitRing.Pack vectType xclass.
Definition vect_idomainType := @IntegralDomain.Pack vectType xclass.
Definition vect_fieldType := @Field.Pack vectType xclass.
Definition unitAlg_comRingType := @ComRing.Pack unitAlgType xclass.
Definition unitAlg_comUnitRingType := @ComUnitRing.Pack unitAlgType xclass.
Definition unitAlg_idomainType := @IntegralDomain.Pack unitAlgType xclass.
Definition unitAlg_fieldType := @Field.Pack unitAlgType xclass.
Definition alg_comRingType := @ComRing.Pack algType xclass.
Definition alg_comUnitRingType := @ComUnitRing.Pack algType xclass.
Definition alg_idomainType := @IntegralDomain.Pack algType xclass.
Definition alg_fieldType := @Field.Pack algType xclass.
Definition lalg_comRingType := @ComRing.Pack lalgType xclass.
Definition lalg_comUnitRingType := @ComUnitRing.Pack lalgType xclass.
Definition lalg_idomainType := @IntegralDomain.Pack lalgType xclass.
Definition lalg_fieldType := @Field.Pack lalgType xclass.
Definition lmod_comRingType := @ComRing.Pack lmodType xclass.
Definition lmod_comUnitRingType := @ComUnitRing.Pack lmodType xclass.
Definition lmod_idomainType := @IntegralDomain.Pack lmodType xclass.
Definition lmod_fieldType := @Field.Pack lmodType xclass.
End FieldExt.
Module Exports.
Coercion sort : type >-> Sortclass.
Bind Scope ring_scope with sort.
Coercion base : class_of >-> Falgebra.class_of.
Coercion base4 : class_of >-> Field.class_of.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion zmodType : type >-> Zmodule.type.
Canonical zmodType.
Coercion ringType : type >-> Ring.type.
Canonical ringType.
Coercion unitRingType : type >-> UnitRing.type.
Canonical unitRingType.
Coercion comRingType : type >-> ComRing.type.
Canonical comRingType.
Coercion comUnitRingType : type >-> ComUnitRing.type.
Canonical comUnitRingType.
Coercion idomainType : type >-> IntegralDomain.type.
Canonical idomainType.
Coercion fieldType : type >-> Field.type.
Canonical fieldType.
Coercion lmodType : type >-> Lmodule.type.
Canonical lmodType.
Coercion lalgType : type >-> Lalgebra.type.
Canonical lalgType.
Coercion algType : type >-> Algebra.type.
Canonical algType.
Coercion unitAlgType : type >-> UnitAlgebra.type.
Canonical unitAlgType.
Coercion vectType : type >-> Vector.type.
Canonical vectType.
Coercion FalgType : type >-> Falgebra.type.
Canonical FalgType.
Canonical Falg_comRingType.
Canonical Falg_comUnitRingType.
Canonical Falg_idomainType.
Canonical Falg_fieldType.
Canonical vect_comRingType.
Canonical vect_comUnitRingType.
Canonical vect_idomainType.
Canonical vect_fieldType.
Canonical unitAlg_comRingType.
Canonical unitAlg_comUnitRingType.
Canonical unitAlg_idomainType.
Canonical unitAlg_fieldType.
Canonical alg_comRingType.
Canonical alg_comUnitRingType.
Canonical alg_idomainType.
Canonical alg_fieldType.
Canonical lalg_comRingType.
Canonical lalg_comUnitRingType.
Canonical lalg_idomainType.
Canonical lalg_fieldType.
Canonical lmod_comRingType.
Canonical lmod_comUnitRingType.
Canonical lmod_idomainType.
Canonical lmod_fieldType.
Notation fieldExtType R := (type (Phant R)).
Notation "[ 'fieldExtType' F 'of' L ]" :=
(@pack _ (Phant F) L _ _ id _ _ _ _ id)
(at level 0, format "[ 'fieldExtType'  F  'of'  L ]") : form_scope.
Notation "[ 'fieldExtType' F 'of' L 'for' K ]" :=
(@pack_eta _ (Phant F) L K _ _ id _ id)
(at level 0, format "[ 'fieldExtType'  F  'of'  L  'for'  K ]") : form_scope.
Notation "{ 'subfield' L }" := (@aspace_of _ (FalgType _) (Phant L))
(at level 0, format "{ 'subfield'  L }") : type_scope.
End Exports.
End FieldExt.
Export FieldExt.Exports.
Canonical regular_fieldExtType (F : fieldType) := [fieldExtType F of F^o for F].
Section FieldExtTheory.
Variables (F0 : fieldType) (L : fieldExtType F0).
Implicit Types (U V M : {vspace L}) (E F K : {subfield L}).

Lemma prodvCA : left_commutative (@prodv F0 L).