aboutsummaryrefslogtreecommitdiff
path: root/mathcomp/field/fieldext.v
diff options
context:
space:
mode:
authorEnrico Tassi2015-03-09 11:07:53 +0100
committerEnrico Tassi2015-03-09 11:24:38 +0100
commitfc84c27eac260dffd8f2fb1cb56d599f1e3486d9 (patch)
treec16205f1637c80833a4c4598993c29fa0fd8c373 /mathcomp/field/fieldext.v
Initial commit
Diffstat (limited to 'mathcomp/field/fieldext.v')
-rw-r--r--mathcomp/field/fieldext.v1626
1 files changed, 1626 insertions, 0 deletions
diff --git a/mathcomp/field/fieldext.v b/mathcomp/field/fieldext.v
new file mode 100644
index 0000000..d9b181a
--- /dev/null
+++ b/mathcomp/field/fieldext.v
@@ -0,0 +1,1626 @@
+(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *)
+Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div choice fintype.
+Require Import tuple finfun bigop ssralg finalg zmodp matrix vector falgebra.
+Require Import poly polydiv mxpoly generic_quotient.
+
+(******************************************************************************)
+(* * 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 *)
+(* fieldType and FalgType F canonical structures. *)
+(* [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 muse be exercised when using fieldOver and basFieldType, *)
+(* 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.
+Import GRing.Theory.
+
+Module FieldExt.
+
+Import GRing.
+
+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 T);
+ field_ext : Field.mixin_of (UnitRing.Pack base T)
+}.
+
+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; _ : Type}.
+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) T.
+
+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) T.
+
+Definition eqType := @Equality.Pack cT xclass xT.
+Definition choiceType := @Choice.Pack cT xclass xT.
+Definition zmodType := @Zmodule.Pack cT xclass xT.
+Definition ringType := @Ring.Pack cT xclass xT.
+Definition unitRingType := @UnitRing.Pack cT xclass xT.
+Definition comRingType := @ComRing.Pack cT xclass xT.
+Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT.
+Definition idomainType := @IntegralDomain.Pack cT xclass xT.
+Definition fieldType := @Field.Pack cT xclass xT.
+Definition lmodType := @Lmodule.Pack R phR cT xclass xT.
+Definition lalgType := @Lalgebra.Pack R phR cT xclass xT.
+Definition algType := @Algebra.Pack R phR cT xclass xT.
+Definition unitAlgType := @UnitAlgebra.Pack R phR cT xclass xT.
+Definition vectType := @Vector.Pack R phR cT xclass xT.
+Definition FalgType := @Falgebra.Pack R phR cT xclass xT.
+
+Definition Falg_comRingType := @ComRing.Pack FalgType xclass xT.
+Definition Falg_comUnitRingType := @ComUnitRing.Pack FalgType xclass xT.
+Definition Falg_idomainType := @IntegralDomain.Pack FalgType xclass xT.
+Definition Falg_fieldType := @Field.Pack FalgType xclass xT.
+
+Definition vect_comRingType := @ComRing.Pack vectType xclass xT.
+Definition vect_comUnitRingType := @ComUnitRing.Pack vectType xclass xT.
+Definition vect_idomainType := @IntegralDomain.Pack vectType xclass xT.
+Definition vect_fieldType := @Field.Pack vectType xclass xT.
+
+Definition unitAlg_comRingType := @ComRing.Pack unitAlgType xclass xT.
+Definition unitAlg_comUnitRingType := @ComUnitRing.Pack unitAlgType xclass xT.
+Definition unitAlg_idomainType := @IntegralDomain.Pack unitAlgType xclass xT.
+Definition unitAlg_fieldType := @Field.Pack unitAlgType xclass xT.
+
+Definition alg_comRingType := @ComRing.Pack algType xclass xT.
+Definition alg_comUnitRingType := @ComUnitRing.Pack algType xclass xT.
+Definition alg_idomainType := @IntegralDomain.Pack algType xclass xT.
+Definition alg_fieldType := @Field.Pack algType xclass xT.
+
+Definition lalg_comRingType := @ComRing.Pack lalgType xclass xT.
+Definition lalg_comUnitRingType := @ComUnitRing.Pack lalgType xclass xT.
+Definition lalg_idomainType := @IntegralDomain.Pack lalgType xclass xT.
+Definition lalg_fieldType := @Field.Pack lalgType xclass xT.
+
+Definition lmod_comRingType := @ComRing.Pack lmodType xclass xT.
+Definition lmod_comUnitRingType := @ComUnitRing.Pack lmodType xclass xT.
+Definition lmod_idomainType := @IntegralDomain.Pack lmodType xclass xT.
+Definition lmod_fieldType := @Field.Pack lmodType xclass xT.
+
+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 ]" :=
+ (@FieldExt.pack _ (Phant F) L _ _ id K _ _ _ idfun)
+ (at level 0, format "[ 'fieldExtType' F 'of' L 'for' K ]") : 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.
+
+Section FieldExtTheory.
+
+Variables (F0 : fieldType) (L : fieldExtType F0).
+Implicit Types (U V M : {vspace L}) (E F K : {subfield L}).
+
+Lemma dim_cosetv U x : x != 0 -> \dim (U * <[x]>) = \dim U.
+Proof.
+move=> nz_x; rewrite -limg_amulr limg_dim_eq //.
+apply/eqP; rewrite -subv0; apply/subvP=> y.
+by rewrite memv_cap memv0 memv_ker lfunE mulf_eq0 (negPf nz_x) orbF => /andP[].
+Qed.
+
+Lemma prodvC : commutative (@prodv F0 L).
+Proof.
+move=> U V; without loss suffices subC: U V / (U * V <= V * U)%VS.
+ by apply/eqP; rewrite eqEsubv !{1}subC.
+by apply/prodvP=> x y Ux Vy; rewrite mulrC memv_mul.
+Qed.
+Canonical prodv_comoid := Monoid.ComLaw prodvC.
+
+Lemma prodvCA : left_commutative (@prodv F0 L).
+Proof. exact: Monoid.mulmCA. Qed.
+
+Lemma prodvAC : right_commutative (@prodv F0 L).
+Proof. exact: Monoid.mulmAC. Qed.
+
+Lemma algid1 K : algid K = 1. Proof. exact/skew_field_algid1/fieldP. Qed.
+
+Lemma mem1v K : 1 \in K. Proof. by rewrite -algid_eq1 algid1. Qed.
+Lemma sub1v K : (1 <= K)%VS. Proof. exact: mem1v. Qed.
+
+Lemma subfield_closed K : agenv K = K.
+Proof.
+by apply/eqP; rewrite eqEsubv sub_agenv agenv_sub_modr ?sub1v ?asubv.
+Qed.
+
+Lemma AHom_lker0 (rT : FalgType F0) (f : 'AHom(L, rT)) : lker f == 0%VS.
+Proof. by apply/lker0P; apply: fmorph_inj. Qed.
+
+Lemma AEnd_lker0 (f : 'AEnd(L)) : lker f == 0%VS. Proof. exact: AHom_lker0. Qed.
+
+Fact aimg_is_aspace (rT : FalgType F0) (f : 'AHom(L, rT)) (E : {subfield L}) :
+ is_aspace (f @: E).
+Proof.
+rewrite /is_aspace -aimgM limgS ?prodv_id // has_algid1 //.
+by apply/memv_imgP; exists 1; rewrite ?mem1v ?rmorph1.
+Qed.
+Canonical aimg_aspace rT f E := ASpace (@aimg_is_aspace rT f E).
+
+Lemma Fadjoin_idP {K x} : reflect (<<K; x>>%VS = K) (x \in K).
+Proof.
+apply: (iffP idP) => [/addv_idPl-> | <-]; first exact: subfield_closed.
+exact: memv_adjoin.
+Qed.
+
+Lemma Fadjoin0 K : <<K; 0>>%VS = K.
+Proof. by rewrite addv0 subfield_closed. Qed.
+
+Lemma Fadjoin_nil K : <<K & [::]>>%VS = K.
+Proof. by rewrite adjoin_nil subfield_closed. Qed.
+
+Lemma FadjoinP {K x E} :
+ reflect (K <= E /\ x \in E)%VS (<<K; x>>%AS <= E)%VS.
+Proof.
+apply: (iffP idP) => [sKxE | /andP].
+ by rewrite (subvP sKxE) ?memv_adjoin // (subv_trans _ sKxE) ?subv_adjoin.
+by rewrite -subv_add => /agenvS; rewrite subfield_closed.
+Qed.
+
+Lemma Fadjoin_seqP {K} {rs : seq L} {E} :
+ reflect (K <= E /\ {subset rs <= E})%VS (<<K & rs>> <= E)%VS.
+Proof.
+apply: (iffP idP) => [sKrsE | [sKE /span_subvP/(conj sKE)/andP]].
+ split=> [|x rs_x]; first exact: subv_trans (subv_adjoin_seq _ _) sKrsE.
+ by rewrite (subvP sKrsE) ?seqv_sub_adjoin.
+by rewrite -subv_add => /agenvS; rewrite subfield_closed.
+Qed.
+
+Lemma alg_polyOver E p : map_poly (in_alg L) p \is a polyOver E.
+Proof. by apply/(polyOverS (subvP (sub1v _)))/polyOver1P; exists p. Qed.
+
+Lemma sub_adjoin1v x E : (<<1; x>> <= E)%VS = (x \in E)%VS.
+Proof. by rewrite (sameP FadjoinP andP) sub1v. Qed.
+
+Fact vsval_multiplicative K : multiplicative (vsval : subvs_of K -> L).
+Proof. by split => //=; apply: algid1. Qed.
+Canonical vsval_rmorphism K := AddRMorphism (vsval_multiplicative K).
+Canonical vsval_lrmorphism K := [lrmorphism of (vsval : subvs_of K -> L)].
+
+Lemma vsval_invf K (w : subvs_of K) : val w^-1 = (vsval w)^-1.
+Proof.
+have [-> | Uv] := eqVneq w 0; first by rewrite !invr0.
+by apply: vsval_invr; rewrite unitfE.
+Qed.
+
+Fact aspace_divr_closed K : divr_closed K.
+Proof. by split=> [|u v Ku Kv]; rewrite ?mem1v ?memvM ?memvV. Qed.
+Canonical aspace_mulrPred K := MulrPred (aspace_divr_closed K).
+Canonical aspace_divrPred K := DivrPred (aspace_divr_closed K).
+Canonical aspace_smulrPred K := SmulrPred (aspace_divr_closed K).
+Canonical aspace_sdivrPred K := SdivrPred (aspace_divr_closed K).
+Canonical aspace_semiringPred K := SemiringPred (aspace_divr_closed K).
+Canonical aspace_subringPred K := SubringPred (aspace_divr_closed K).
+Canonical aspace_subalgPred K := SubalgPred (memv_submod_closed K).
+Canonical aspace_divringPred K := DivringPred (aspace_divr_closed K).
+Canonical aspace_divalgPred K := DivalgPred (memv_submod_closed K).
+
+Definition subvs_mulC K := [comRingMixin of subvs_of K by <:].
+Canonical subvs_comRingType K :=
+ Eval hnf in ComRingType (subvs_of K) (@subvs_mulC K).
+Canonical subvs_comUnitRingType K :=
+ Eval hnf in [comUnitRingType of subvs_of K].
+Definition subvs_mul_eq0 K := [idomainMixin of subvs_of K by <:].
+Canonical subvs_idomainType K :=
+ Eval hnf in IdomainType (subvs_of K) (@subvs_mul_eq0 K).
+Lemma subvs_fieldMixin K : GRing.Field.mixin_of (@subvs_idomainType K).
+Proof.
+by move=> w nz_w; rewrite unitrE -val_eqE /= vsval_invf algid1 divff.
+Qed.
+Canonical subvs_fieldType K :=
+ Eval hnf in FieldType (subvs_of K) (@subvs_fieldMixin K).
+Canonical subvs_fieldExtType K := Eval hnf in [fieldExtType F0 of subvs_of K].
+
+Lemma polyOver_subvs {K} {p : {poly L}} :
+ reflect (exists q : {poly subvs_of K}, p = map_poly vsval q)
+ (p \is a polyOver K).
+Proof.
+apply: (iffP polyOverP) => [Hp | [q ->] i]; last by rewrite coef_map // subvsP.
+exists (\poly_(i < size p) (Subvs (Hp i))); rewrite -{1}[p]coefK.
+by apply/polyP=> i; rewrite coef_map !coef_poly; case: ifP.
+Qed.
+
+Lemma divp_polyOver K : {in polyOver K &, forall p q, p %/ q \is a polyOver K}.
+Proof.
+move=> _ _ /polyOver_subvs[p ->] /polyOver_subvs[q ->].
+by apply/polyOver_subvs; exists (p %/ q); rewrite map_divp.
+Qed.
+
+Lemma modp_polyOver K : {in polyOver K &, forall p q, p %% q \is a polyOver K}.
+Proof.
+move=> _ _ /polyOver_subvs[p ->] /polyOver_subvs[q ->].
+by apply/polyOver_subvs; exists (p %% q); rewrite map_modp.
+Qed.
+
+Lemma gcdp_polyOver K :
+ {in polyOver K &, forall p q, gcdp p q \is a polyOver K}.
+Proof.
+move=> _ _ /polyOver_subvs[p ->] /polyOver_subvs[q ->].
+by apply/polyOver_subvs; exists (gcdp p q); rewrite gcdp_map.
+Qed.
+
+Fact prodv_is_aspace E F : is_aspace (E * F).
+Proof.
+rewrite /is_aspace prodvCA -!prodvA prodvA !prodv_id has_algid1 //=.
+by rewrite -[1]mulr1 memv_mul ?mem1v.
+Qed.
+Canonical prodv_aspace E F : {subfield L} := ASpace (prodv_is_aspace E F).
+
+Fact field_mem_algid E F : algid E \in F. Proof. by rewrite algid1 mem1v. Qed.
+Canonical capv_aspace E F : {subfield L} := aspace_cap (field_mem_algid E F).
+
+Lemma polyOverSv U V : (U <= V)%VS -> {subset polyOver U <= polyOver V}.
+Proof. by move/subvP=> sUV; apply: polyOverS. Qed.
+
+Lemma field_subvMl F U : (U <= F * U)%VS.
+Proof. by rewrite -{1}[U]prod1v prodvSl ?sub1v. Qed.
+
+Lemma field_subvMr U F : (U <= U * F)%VS.
+Proof. by rewrite prodvC field_subvMl. Qed.
+
+Lemma field_module_eq F M : (F * M <= M)%VS -> (F * M)%VS = M.
+Proof. by move=> modM; apply/eqP; rewrite eqEsubv modM field_subvMl. Qed.
+
+Lemma sup_field_module F E : (F * E <= E)%VS = (F <= E)%VS.
+Proof.
+apply/idP/idP; first exact: subv_trans (field_subvMr F E).
+by move/(prodvSl E)/subv_trans->; rewrite ?asubv.
+Qed.
+
+Lemma field_module_dimS F M : (F * M <= M)%VS -> (\dim F %| \dim M)%N.
+Proof. exact/skew_field_module_dimS/fieldP. Qed.
+
+Lemma field_dimS F E : (F <= E)%VS -> (\dim F %| \dim E)%N.
+Proof. exact/skew_field_dimS/fieldP. Qed.
+
+Lemma dim_field_module F M : (F * M <= M)%VS -> \dim M = (\dim_F M * \dim F)%N.
+Proof. by move/field_module_dimS/divnK. Qed.
+
+Lemma dim_sup_field F E : (F <= E)%VS -> \dim E = (\dim_F E * \dim F)%N.
+Proof. by move/field_dimS/divnK. Qed.
+
+Lemma field_module_semisimple F M (m := \dim_F M) :
+ (F * M <= M)%VS ->
+ {X : m.-tuple L | {subset X <= M} /\ 0 \notin X
+ & let FX := (\sum_(i < m) F * <[X`_i]>)%VS in FX = M /\ directv FX}.
+Proof.
+move=> modM; have dimM: (m * \dim F)%N = \dim M by rewrite -dim_field_module.
+have [X [defM dxFX nzX]] := skew_field_module_semisimple (@fieldP L) modM.
+have szX: size X == m.
+ rewrite -(eqn_pmul2r (adim_gt0 F)) dimM -defM (directvP dxFX) /=.
+ rewrite -sum1_size big_distrl; apply/eqP/eq_big_seq => x Xx /=.
+ by rewrite mul1n dim_cosetv ?(memPn nzX).
+rewrite directvE /= !(big_nth 0) (eqP szX) !big_mkord -directvE /= in defM dxFX.
+exists (Tuple szX) => //; split=> // _ /tnthP[i ->]; rewrite (tnth_nth 0) /=.
+by rewrite -defM memvE (sumv_sup i) ?field_subvMl.
+Qed.
+
+Section FadjoinPolyDefinitions.
+
+Variables (U : {vspace L}) (x : L).
+
+Definition adjoin_degree := (\dim_U <<U; x>>).-1.+1.
+Local Notation n := adjoin_degree.
+
+Definition Fadjoin_sum := (\sum_(i < n) U * <[x ^+ i]>)%VS.
+
+Definition Fadjoin_poly v : {poly L} :=
+ \poly_(i < n) (sumv_pi Fadjoin_sum (inord i) v / x ^+ i).
+
+Definition minPoly : {poly L} := 'X^n - Fadjoin_poly (x ^+ n).
+
+Lemma size_Fadjoin_poly v : size (Fadjoin_poly v) <= n.
+Proof. exact: size_poly. Qed.
+
+Lemma Fadjoin_polyOver v : Fadjoin_poly v \is a polyOver U.
+Proof.
+apply/(all_nthP 0) => i _; rewrite coef_poly /=.
+case: ifP => lti; last exact: mem0v.
+have /memv_cosetP[y Uy ->] := memv_sum_pi (erefl Fadjoin_sum) (inord i) v.
+rewrite inordK //; have [-> | /mulfK-> //] := eqVneq (x ^+ i) 0.
+by rewrite mulr0 mul0r mem0v.
+Qed.
+
+Fact Fadjoin_poly_is_linear : linear_for (in_alg L \; *:%R) Fadjoin_poly.
+Proof.
+move=> a u v; apply/polyP=> i; rewrite coefD coefZ !coef_poly.
+case: ifP => lti; last by rewrite mulr0 addr0.
+by rewrite linearP mulrA -mulrDl mulr_algl.
+Qed.
+Canonical Fadjoin_poly_additive := Additive Fadjoin_poly_is_linear.
+Canonical Fadjoin_poly_linear := AddLinear Fadjoin_poly_is_linear.
+
+Lemma size_minPoly : size minPoly = n.+1.
+Proof. by rewrite size_addl ?size_polyXn // size_opp ltnS size_poly. Qed.
+
+Lemma monic_minPoly : minPoly \is monic.
+Proof.
+rewrite monicE /lead_coef size_minPoly coefB coefXn eqxx.
+by rewrite nth_default ?subr0 ?size_poly.
+Qed.
+
+End FadjoinPolyDefinitions.
+
+Section FadjoinPoly.
+
+Variables (K : {subfield L}) (x : L).
+Local Notation n := (adjoin_degree (asval K) x).
+Local Notation sumKx := (Fadjoin_sum (asval K) x).
+
+Lemma adjoin_degreeE : n = \dim_K <<K; x>>.
+Proof. by rewrite [n]prednK // divn_gt0 ?adim_gt0 // dimvS ?subv_adjoin. Qed.
+
+Lemma dim_Fadjoin : \dim <<K; x>> = (n * \dim K)%N.
+Proof. by rewrite adjoin_degreeE -dim_sup_field ?subv_adjoin. Qed.
+
+Lemma adjoin0_deg : adjoin_degree K 0 = 1%N.
+Proof. by rewrite /adjoin_degree addv0 subfield_closed divnn adim_gt0. Qed.
+
+Lemma adjoin_deg_eq1 : (n == 1%N) = (x \in K).
+Proof.
+rewrite (sameP Fadjoin_idP eqP) adjoin_degreeE; have sK_Kx := subv_adjoin K x.
+apply/eqP/idP=> [dimKx1 | /eqP->]; last by rewrite divnn adim_gt0.
+by rewrite eq_sym eqEdim sK_Kx /= (dim_sup_field sK_Kx) dimKx1 mul1n.
+Qed.
+
+Lemma Fadjoin_sum_direct : directv sumKx.
+Proof.
+rewrite directvE /=; case Dn: {-2}n (leqnn n) => // [m] {Dn}.
+elim: m => [|m IHm] ltm1n; rewrite ?big_ord1 // !(big_ord_recr m.+1) /=.
+do [move/(_ (ltnW ltm1n))/eqP; set S := (\sum_i _)%VS] in IHm *.
+rewrite -IHm dimv_add_leqif; apply/subvP=> z; rewrite memv_cap => /andP[Sz].
+case/memv_cosetP=> y Ky Dz; rewrite memv0 Dz mulf_eq0 expf_eq0 /=.
+apply: contraLR ltm1n => /norP[nz_y nz_x].
+rewrite -leqNgt -(leq_pmul2r (adim_gt0 K)) -dim_Fadjoin.
+have{IHm} ->: (m.+1 * \dim K)%N = \dim S.
+ rewrite -[m.+1]card_ord -sum_nat_const IHm.
+ by apply: eq_bigr => i; rewrite dim_cosetv ?expf_neq0.
+apply/dimvS/agenv_sub_modl; first by rewrite (sumv_sup 0) //= prodv1 sub1v.
+rewrite prodvDl subv_add -[S]big_distrr prodvA prodv_id subvv !big_distrr /=.
+apply/subv_sumP=> i _; rewrite -expv_line prodvCA -expvSl expv_line.
+have [ltim | lemi] := ltnP i m; first by rewrite (sumv_sup (Sub i.+1 _)).
+have{lemi} /eqP->: i == m :> nat by rewrite eqn_leq leq_ord.
+rewrite -big_distrr -2!{2}(prodv_id K) /= -!prodvA big_distrr -/S prodvSr //=.
+by rewrite -(canLR (mulKf nz_y) Dz) -memvE memv_mul ?rpredV.
+Qed.
+
+Let nz_x_i (i : 'I_n) : x ^+ i != 0.
+Proof.
+by rewrite expf_eq0; case: eqP i => [->|_] [[]] //; rewrite adjoin0_deg.
+Qed.
+
+Lemma Fadjoin_eq_sum : <<K; x>>%VS = sumKx.
+Proof.
+apply/esym/eqP; rewrite eqEdim eq_leq ?andbT.
+ apply/subv_sumP=> i _; rewrite -agenvM prodvS ?subv_adjoin //.
+ by rewrite -expv_line (subv_trans (subX_agenv _ _)) ?agenvS ?addvSr.
+rewrite dim_Fadjoin -[n]card_ord -sum_nat_const (directvP Fadjoin_sum_direct).
+by apply: eq_bigr => i _; rewrite /= dim_cosetv.
+Qed.
+
+Lemma Fadjoin_poly_eq v : v \in <<K; x>>%VS -> (Fadjoin_poly K x v).[x] = v.
+Proof.
+move/(sumv_pi_sum Fadjoin_eq_sum)=> {2}<-; rewrite horner_poly.
+by apply: eq_bigr => i _; rewrite inord_val mulfVK.
+Qed.
+
+Lemma mempx_Fadjoin p : p \is a polyOver K -> p.[x] \in <<K; x>>%VS.
+Proof.
+move=> Kp; rewrite rpred_horner ?memv_adjoin ?(polyOverS _ Kp) //.
+exact: subvP_adjoin.
+Qed.
+
+Lemma Fadjoin_polyP {v} :
+ reflect (exists2 p, p \in polyOver K & v = p.[x]) (v \in <<K; x>>%VS).
+Proof.
+apply: (iffP idP) => [Kx_v | [p Kp ->]]; last exact: mempx_Fadjoin.
+by exists (Fadjoin_poly K x v); rewrite ?Fadjoin_polyOver ?Fadjoin_poly_eq.
+Qed.
+
+Lemma Fadjoin_poly_unique p v :
+ p \is a polyOver K -> size p <= n -> p.[x] = v -> Fadjoin_poly K x v = p.
+Proof.
+have polyKx q i: q \is a polyOver K -> q`_i * x ^+ i \in (K * <[x ^+ i]>)%VS.
+ by move/polyOverP=> Kq; rewrite memv_mul ?Kq ?memv_line.
+move=> Kp szp Dv; have /Fadjoin_poly_eq/eqP := mempx_Fadjoin Kp.
+rewrite {1}Dv {Dv} !(@horner_coef_wide _ n) ?size_poly //.
+move/polyKx in Kp; have /polyKx K_pv := Fadjoin_polyOver K x v.
+rewrite (directv_sum_unique Fadjoin_sum_direct) // => /eqfunP eq_pq.
+apply/polyP=> i; have [leni|?] := leqP n i; last exact: mulIf (eq_pq (Sub i _)).
+by rewrite !nth_default ?(leq_trans _ leni) ?size_poly.
+Qed.
+
+Lemma Fadjoin_polyC v : v \in K -> Fadjoin_poly K x v = v%:P.
+Proof.
+move=> Kv; apply: Fadjoin_poly_unique; rewrite ?polyOverC ?hornerC //.
+by rewrite size_polyC (leq_trans (leq_b1 _)).
+Qed.
+
+Lemma Fadjoin_polyX : x \notin K -> Fadjoin_poly K x x = 'X.
+Proof.
+move=> K'x; apply: Fadjoin_poly_unique; rewrite ?polyOverX ?hornerX //.
+by rewrite size_polyX ltn_neqAle andbT eq_sym adjoin_deg_eq1.
+Qed.
+
+Lemma minPolyOver : minPoly K x \is a polyOver K.
+Proof. by rewrite /minPoly rpredB ?rpredX ?polyOverX ?Fadjoin_polyOver. Qed.
+
+Lemma minPolyxx : (minPoly K x).[x] = 0.
+Proof.
+by rewrite !hornerE hornerXn Fadjoin_poly_eq ?subrr ?rpredX ?memv_adjoin.
+Qed.
+
+Lemma root_minPoly : root (minPoly K x) x. Proof. exact/rootP/minPolyxx. Qed.
+
+Lemma Fadjoin_poly_mod p :
+ p \is a polyOver K -> Fadjoin_poly K x p.[x] = p %% minPoly K x.
+Proof.
+move=> Kp; rewrite {1}(divp_eq p (minPoly K x)) 2!hornerE minPolyxx mulr0 add0r.
+apply: Fadjoin_poly_unique => //; first by rewrite modp_polyOver // minPolyOver.
+by rewrite -ltnS -size_minPoly ltn_modp // monic_neq0 ?monic_minPoly.
+Qed.
+
+Lemma minPoly_XsubC : reflect (minPoly K x = 'X - x%:P) (x \in K).
+Proof.
+set p := minPoly K x; apply: (iffP idP) => [Kx | Dp]; last first.
+ suffices ->: x = - p`_0 by rewrite rpredN (polyOverP minPolyOver).
+ by rewrite Dp coefB coefX coefC add0r opprK.
+rewrite (@all_roots_prod_XsubC _ p [:: x]) /= ?root_minPoly //.
+ by rewrite big_seq1 (monicP (monic_minPoly K x)) scale1r.
+by apply/eqP; rewrite size_minPoly eqSS adjoin_deg_eq1.
+Qed.
+
+Lemma root_small_adjoin_poly p :
+ p \is a polyOver K -> size p <= n -> root p x = (p == 0).
+Proof.
+move=> Kp szp; apply/rootP/eqP=> [px0 | ->]; last by rewrite horner0.
+rewrite -(Fadjoin_poly_unique Kp szp px0).
+by apply: Fadjoin_poly_unique; rewrite ?polyOver0 ?size_poly0 ?horner0.
+Qed.
+
+Lemma minPoly_irr p :
+ p \is a polyOver K -> p %| minPoly K x -> (p %= minPoly K x) || (p %= 1).
+Proof.
+rewrite dvdp_eq; set q := _ %/ _ => Kp def_pq.
+have Kq: q \is a polyOver K by rewrite divp_polyOver // minPolyOver.
+move: q Kq def_pq root_minPoly (size_minPoly K x) => q Kq /eqP->.
+rewrite rootM => pqx0 szpq.
+have [nzq nzp]: q != 0 /\ p != 0.
+ by apply/norP; rewrite -mulf_eq0 -size_poly_eq0 szpq.
+without loss{pqx0} qx0: q p Kp Kq nzp nzq szpq / root q x.
+ move=> IH; case/orP: pqx0 => /IH{IH}IH; first exact: IH.
+ have{IH} /orP[]: (q %= p * q) || (q %= 1) by apply: IH => //; rewrite mulrC.
+ by rewrite orbC -{1}[q]mul1r eqp_mul2r // eqp_sym => ->.
+ by rewrite -{1}[p]mul1r eqp_sym eqp_mul2r // => ->.
+apply/orP; right; rewrite -size_poly_eq1 eqn_leq lt0n size_poly_eq0 nzp andbT.
+rewrite -(leq_add2r (size q)) -leq_subLR subn1 -size_mul // mulrC szpq.
+by rewrite ltnNge; apply: contra nzq => /(root_small_adjoin_poly Kq) <-.
+Qed.
+
+Lemma minPoly_dvdp p : p \is a polyOver K -> root p x -> (minPoly K x) %| p.
+Proof.
+move=> Kp rootp.
+have gcdK : gcdp (minPoly K x) p \is a polyOver K.
+ by rewrite gcdp_polyOver ?minPolyOver.
+have /orP[gcd_eqK|gcd_eq1] := minPoly_irr gcdK (dvdp_gcdl (minPoly K x) p).
+ by rewrite -(eqp_dvdl _ gcd_eqK) dvdp_gcdr.
+case/negP: (root1 x).
+by rewrite -(eqp_root gcd_eq1) root_gcd rootp root_minPoly.
+Qed.
+
+End FadjoinPoly.
+
+Lemma minPolyS K E a : (K <= E)%VS -> minPoly E a %| minPoly K a.
+Proof.
+move=> sKE; apply: minPoly_dvdp; last exact: root_minPoly.
+by apply: (polyOverSv sKE); rewrite minPolyOver.
+Qed.
+
+Implicit Arguments Fadjoin_polyP [K x v].
+Lemma Fadjoin1_polyP x v :
+ reflect (exists p, v = (map_poly (in_alg L) p).[x]) (v \in <<1; x>>%VS).
+Proof.
+apply: (iffP Fadjoin_polyP) => [[_ /polyOver1P]|] [p ->]; first by exists p.
+by exists (map_poly (in_alg L) p) => //; apply: alg_polyOver.
+Qed.
+
+Section Horner.
+
+Variables z : L.
+
+Definition fieldExt_horner := horner_morph (fun x => mulrC z (in_alg L x)).
+Canonical fieldExtHorner_additive := [additive of fieldExt_horner].
+Canonical fieldExtHorner_rmorphism := [rmorphism of fieldExt_horner].
+Lemma fieldExt_hornerC b : fieldExt_horner b%:P = b%:A.
+Proof. exact: horner_morphC. Qed.
+Lemma fieldExt_hornerX : fieldExt_horner 'X = z.
+Proof. exact: horner_morphX. Qed.
+Fact fieldExt_hornerZ : scalable fieldExt_horner.
+Proof.
+move=> a p; rewrite -mul_polyC rmorphM /= fieldExt_hornerC.
+by rewrite -scalerAl mul1r.
+Qed.
+Canonical fieldExt_horner_linear := AddLinear fieldExt_hornerZ.
+Canonical fieldExt_horner_lrmorhism := [lrmorphism of fieldExt_horner].
+
+End Horner.
+
+End FieldExtTheory.
+
+Notation "E :&: F" := (capv_aspace E F) : aspace_scope.
+Notation "'C_ E [ x ]" := (capv_aspace E 'C[x]) : aspace_scope.
+Notation "'C_ ( E ) [ x ]" := (capv_aspace E 'C[x])
+ (only parsing) : aspace_scope.
+Notation "'C_ E ( V )" := (capv_aspace E 'C(V)) : aspace_scope.
+Notation "'C_ ( E ) ( V )" := (capv_aspace E 'C(V))
+ (only parsing) : aspace_scope.
+Notation "E * F" := (prodv_aspace E F) : aspace_scope.
+Notation "f @: E" := (aimg_aspace f E) : aspace_scope.
+
+Implicit Arguments Fadjoin_idP [F0 L K x].
+Implicit Arguments FadjoinP [F0 L K x E].
+Implicit Arguments Fadjoin_seqP [F0 L K rs E].
+Implicit Arguments polyOver_subvs [F0 L K p].
+Implicit Arguments Fadjoin_polyP [F0 L K x v].
+Implicit Arguments Fadjoin1_polyP [F0 L x v].
+Implicit Arguments minPoly_XsubC [F0 L K x].
+
+Section MapMinPoly.
+
+Variables (F0 : fieldType) (L rL : fieldExtType F0) (f : 'AHom(L, rL)).
+Variables (K : {subfield L}) (x : L).
+
+Lemma adjoin_degree_aimg : adjoin_degree (f @: K) (f x) = adjoin_degree K x.
+Proof.
+rewrite !adjoin_degreeE -aimg_adjoin.
+by rewrite !limg_dim_eq ?(eqP (AHom_lker0 f)) ?capv0.
+Qed.
+
+Lemma map_minPoly : map_poly f (minPoly K x) = minPoly (f @: K) (f x).
+Proof.
+set fp := minPoly (f @: K) (f x); pose fM := [rmorphism of f].
+have [p Kp Dp]: exists2 p, p \is a polyOver K & map_poly f p = fp.
+ have Kfp: fp \is a polyOver (f @: K)%VS by apply: minPolyOver.
+ exists (map_poly f^-1%VF fp).
+ apply/polyOver_poly=> j _; have /memv_imgP[y Ky ->] := polyOverP Kfp j.
+ by rewrite lker0_lfunK ?AHom_lker0.
+ rewrite -map_poly_comp map_poly_id // => _ /(allP Kfp)/memv_imgP[y _ ->].
+ by rewrite /= limg_lfunVK ?memv_img ?memvf.
+apply/eqP; rewrite -eqp_monic ?monic_map ?monic_minPoly // -Dp eqp_map.
+have: ~~ (p %= 1) by rewrite -size_poly_eq1 -(size_map_poly fM) Dp size_minPoly.
+apply: implyP; rewrite implyNb orbC eqp_sym minPoly_irr //.
+rewrite -(dvdp_map fM) Dp minPoly_dvdp ?fmorph_root ?root_minPoly //.
+by apply/polyOver_poly=> j _; apply/memv_img/polyOverP/minPolyOver.
+Qed.
+
+End MapMinPoly.
+
+(* Changing up the reference field of a fieldExtType. *)
+Section FieldOver.
+
+Variables (F0 : fieldType) (L : fieldExtType F0) (F : {subfield L}).
+
+Definition fieldOver of {vspace L} : Type := L.
+Local Notation K_F := (subvs_of F).
+Local Notation L_F := (fieldOver F).
+
+Canonical fieldOver_eqType := [eqType of L_F].
+Canonical fieldOver_choiceType := [choiceType of L_F].
+Canonical fieldOver_zmodType := [zmodType of L_F].
+Canonical fieldOver_ringType := [ringType of L_F].
+Canonical fieldOver_unitRingType := [unitRingType of L_F].
+Canonical fieldOver_comRingType := [comRingType of L_F].
+Canonical fieldOver_comUnitRingType := [comUnitRingType of L_F].
+Canonical fieldOver_idomainType := [idomainType of L_F].
+Canonical fieldOver_fieldType := [fieldType of L_F].
+
+Definition fieldOver_scale (a : K_F) (u : L_F) : L_F := vsval a * u.
+Local Infix "*F:" := fieldOver_scale (at level 40).
+
+Fact fieldOver_scaleA a b u : a *F: (b *F: u) = (a * b) *F: u.
+Proof. exact: mulrA. Qed.
+
+Fact fieldOver_scale1 u : 1 *F: u = u.
+Proof. by rewrite /(1 *F: u) /= algid1 mul1r. Qed.
+
+Fact fieldOver_scaleDr a u v : a *F: (u + v) = a *F: u + a *F: v.
+Proof. exact: mulrDr. Qed.
+
+Fact fieldOver_scaleDl v a b : (a + b) *F: v = a *F: v + b *F: v.
+Proof. exact: mulrDl. Qed.
+
+Definition fieldOver_lmodMixin :=
+ LmodMixin fieldOver_scaleA fieldOver_scale1
+ fieldOver_scaleDr fieldOver_scaleDl.
+
+Canonical fieldOver_lmodType := LmodType K_F L_F fieldOver_lmodMixin.
+
+Lemma fieldOver_scaleE a (u : L) : a *: (u : L_F) = vsval a * u.
+Proof. by []. Qed.
+
+Fact fieldOver_scaleAl a u v : a *F: (u * v) = (a *F: u) * v.
+Proof. exact: mulrA. Qed.
+
+Canonical fieldOver_lalgType := LalgType K_F L_F fieldOver_scaleAl.
+
+Fact fieldOver_scaleAr a u v : a *F: (u * v) = u * (a *F: v).
+Proof. exact: mulrCA. Qed.
+
+Canonical fieldOver_algType := AlgType K_F L_F fieldOver_scaleAr.
+Canonical fieldOver_unitAlgType := [unitAlgType K_F of L_F].
+
+Fact fieldOver_vectMixin : Vector.mixin_of fieldOver_lmodType.
+Proof.
+have [bL [_ nz_bL] [defL dxSbL]] := field_module_semisimple (subvf (F * _)).
+do [set n := \dim_F {:L} in bL nz_bL *; set SbL := (\sum_i _)%VS] in defL dxSbL.
+have in_bL i (a : K_F) : val a * (bL`_i : L_F) \in (F * <[bL`_i]>)%VS.
+ by rewrite memv_mul ?(valP a) ?memv_line.
+have nz_bLi (i : 'I_n): bL`_i != 0 by rewrite (memPn nz_bL) ?memt_nth.
+pose r2v (v : 'rV[K_F]_n) : L_F := \sum_i v 0 i *: (bL`_i : L_F).
+have r2v_lin: linear r2v.
+ move=> a u v; rewrite /r2v scaler_sumr -big_split /=; apply: eq_bigr => i _.
+ by rewrite scalerA -scalerDl !mxE.
+have v2rP x: {r : 'rV[K_F]_n | x = r2v r}.
+ apply: sig_eqW; have /memv_sumP[y Fy ->]: x \in SbL by rewrite defL memvf.
+ have /fin_all_exists[r Dr] i: exists r, y i = r *: (bL`_i : L_F).
+ by have /memv_cosetP[a Fa ->] := Fy i isT; exists (Subvs Fa).
+ by exists (\row_i r i); apply: eq_bigr => i _; rewrite mxE.
+pose v2r x := sval (v2rP x).
+have v2rK: cancel v2r (Linear r2v_lin) by rewrite /v2r => x; case: (v2rP x).
+suffices r2vK: cancel r2v v2r.
+ by exists n, v2r; [exact: can2_linear v2rK | exists r2v].
+move=> r; apply/rowP=> i; apply/val_inj/(mulIf (nz_bLi i))/eqP; move: i isT.
+by apply/forall_inP; move/directv_sum_unique: dxSbL => <- //; exact/eqP/v2rK.
+Qed.
+
+Canonical fieldOver_vectType := VectType K_F L_F fieldOver_vectMixin.
+Canonical fieldOver_FalgType := [FalgType K_F of L_F].
+Canonical fieldOver_fieldExtType := [fieldExtType K_F of L_F].
+
+Implicit Types (V : {vspace L}) (E : {subfield L}).
+
+Lemma trivial_fieldOver : (1%VS : {vspace L_F}) =i F.
+Proof.
+move=> x; apply/vlineP/idP=> [[{x}x ->] | Fx].
+ by rewrite fieldOver_scaleE mulr1 (valP x).
+by exists (vsproj F x); rewrite fieldOver_scaleE mulr1 vsprojK.
+Qed.
+
+Definition vspaceOver V := <<vbasis V : seq L_F>>%VS.
+
+Lemma mem_vspaceOver V : vspaceOver V =i (F * V)%VS.
+Proof.
+move=> y; apply/idP/idP; last rewrite unlock; move=> /coord_span->.
+ rewrite (@memv_suml F0 L) // => i _.
+ by rewrite memv_mul ?subvsP // vbasis_mem ?memt_nth.
+rewrite memv_suml // => ij _; rewrite -tnth_nth; set x := tnth _ ij.
+have/allpairsP[[u z] /= [Fu Vz {x}->]]: x \in _ := mem_tnth ij _.
+by rewrite scalerAl (memvZ (Subvs _)) ?memvZ ?memv_span //= vbasis_mem.
+Qed.
+
+Lemma mem_aspaceOver E : (F <= E)%VS -> vspaceOver E =i E.
+Proof.
+by move=> sFE y; rewrite mem_vspaceOver field_module_eq ?sup_field_module.
+Qed.
+
+Fact aspaceOver_suproof E : is_aspace (vspaceOver E).
+Proof.
+rewrite /is_aspace has_algid1; last by rewrite mem_vspaceOver (@mem1v _ L).
+by apply/prodvP=> u v; rewrite !mem_vspaceOver; exact: memvM.
+Qed.
+Canonical aspaceOver E := ASpace (aspaceOver_suproof E).
+
+Lemma dim_vspaceOver M : (F * M <= M)%VS -> \dim (vspaceOver M) = \dim_F M.
+Proof.
+move=> modM; have [] := field_module_semisimple modM.
+set n := \dim_F M => b [Mb nz_b] [defM dx_b].
+suff: basis_of (vspaceOver M) b by apply: size_basis.
+apply/andP; split.
+ rewrite eqEsubv; apply/andP; split; apply/span_subvP=> u.
+ by rewrite mem_vspaceOver field_module_eq // => /Mb.
+ move/(@vbasis_mem _ _ _ M); rewrite -defM => /memv_sumP[{u}u Fu ->].
+ apply: memv_suml => i _; have /memv_cosetP[a Fa ->] := Fu i isT.
+ by apply: (memvZ (Subvs Fa)); rewrite memv_span ?memt_nth.
+apply/freeP=> a /(directv_sum_independent dx_b) a_0 i.
+have{a_0}: a i *: (b`_i : L_F) == 0.
+ by rewrite a_0 {i}// => i _; rewrite memv_mul ?memv_line ?subvsP.
+by rewrite scaler_eq0=> /predU1P[] // /idPn[]; rewrite (memPn nz_b) ?memt_nth.
+Qed.
+
+Lemma dim_aspaceOver E : (F <= E)%VS -> \dim (vspaceOver E) = \dim_F E.
+Proof. by rewrite -sup_field_module; exact: dim_vspaceOver. Qed.
+
+Lemma vspaceOverP V_F :
+ {V | [/\ V_F = vspaceOver V, (F * V <= V)%VS & V_F =i V]}.
+Proof.
+pose V := (F * <<vbasis V_F : seq L>>)%VS.
+have idV: (F * V)%VS = V by rewrite prodvA prodv_id.
+suffices defVF: V_F = vspaceOver V.
+ by exists V; split=> [||u]; rewrite ?defVF ?mem_vspaceOver ?idV.
+apply/vspaceP=> v; rewrite mem_vspaceOver idV.
+do [apply/idP/idP; last rewrite /V unlock] => [/coord_vbasis|/coord_span] ->.
+ by apply: memv_suml => i _; rewrite memv_mul ?subvsP ?memv_span ?memt_nth.
+apply: memv_suml => i _; rewrite -tnth_nth; set xu := tnth _ i.
+have /allpairsP[[x u] /=]: xu \in _ := mem_tnth i _.
+case=> /vbasis_mem Fx /vbasis_mem Vu ->.
+rewrite scalerAl (coord_span Vu) mulr_sumr memv_suml // => j_.
+by rewrite -scalerCA (memvZ (Subvs _)) ?memvZ // vbasis_mem ?memt_nth.
+Qed.
+
+Lemma aspaceOverP (E_F : {subfield L_F}) :
+ {E | [/\ E_F = aspaceOver E, (F <= E)%VS & E_F =i E]}.
+Proof.
+have [V [defEF modV memV]] := vspaceOverP E_F.
+have algE: has_algid V && (V * V <= V)%VS.
+ rewrite has_algid1; last by rewrite -memV mem1v.
+ by apply/prodvP=> u v; rewrite -!memV; exact: memvM.
+by exists (ASpace algE); rewrite -sup_field_module; split; first exact: val_inj.
+Qed.
+
+End FieldOver.
+
+(* Changing the reference field to a smaller field. *)
+Section BaseField.
+
+Variables (F0 : fieldType) (F : fieldExtType F0) (L : fieldExtType F).
+
+Definition baseField_type of phant L : Type := L.
+Notation L0 := (baseField_type (Phant (FieldExt.sort L))).
+
+Canonical baseField_eqType := [eqType of L0].
+Canonical baseField_choiceType := [choiceType of L0].
+Canonical baseField_zmodType := [zmodType of L0].
+Canonical baseField_ringType := [ringType of L0].
+Canonical baseField_unitRingType := [unitRingType of L0].
+Canonical baseField_comRingType := [comRingType of L0].
+Canonical baseField_comUnitRingType := [comUnitRingType of L0].
+Canonical baseField_idomainType := [idomainType of L0].
+Canonical baseField_fieldType := [fieldType of L0].
+
+Definition baseField_scale (a : F0) (u : L0) : L0 := in_alg F a *: u.
+Local Infix "*F0:" := baseField_scale (at level 40).
+
+Fact baseField_scaleA a b u : a *F0: (b *F0: u) = (a * b) *F0: u.
+Proof. by rewrite [_ *F0: _]scalerA -rmorphM. Qed.
+
+Fact baseField_scale1 u : 1 *F0: u = u.
+Proof. by rewrite /(1 *F0: u) rmorph1 scale1r. Qed.
+
+Fact baseField_scaleDr a u v : a *F0: (u + v) = a *F0: u + a *F0: v.
+Proof. exact: scalerDr. Qed.
+
+Fact baseField_scaleDl v a b : (a + b) *F0: v = a *F0: v + b *F0: v.
+Proof. by rewrite -scalerDl -rmorphD. Qed.
+
+Definition baseField_lmodMixin :=
+ LmodMixin baseField_scaleA baseField_scale1
+ baseField_scaleDr baseField_scaleDl.
+
+Canonical baseField_lmodType := LmodType F0 L0 baseField_lmodMixin.
+
+Lemma baseField_scaleE a (u : L) : a *: (u : L0) = a%:A *: u.
+Proof. by []. Qed.
+
+Fact baseField_scaleAl a (u v : L0) : a *F0: (u * v) = (a *F0: u) * v.
+Proof. exact: scalerAl. Qed.
+
+Canonical baseField_lalgType := LalgType F0 L0 baseField_scaleAl.
+
+Fact baseField_scaleAr a u v : a *F0: (u * v) = u * (a *F0: v).
+Proof. exact: scalerAr. Qed.
+
+Canonical baseField_algType := AlgType F0 L0 baseField_scaleAr.
+Canonical baseField_unitAlgType := [unitAlgType F0 of L0].
+
+Let n := \dim {:F}.
+Let bF : n.-tuple F := vbasis {:F}.
+Let coordF (x : F) := (coord_vbasis (memvf x)).
+
+Fact baseField_vectMixin : Vector.mixin_of baseField_lmodType.
+Proof.
+pose bL := vbasis {:L}; set m := \dim {:L} in bL.
+pose v2r (x : L0) := mxvec (\matrix_(i, j) coord bF j (coord bL i x)).
+have v2r_lin: linear v2r.
+ move=> a x y; rewrite -linearP; congr (mxvec _); apply/matrixP=> i j.
+ by rewrite !mxE linearP mulr_algl linearP.
+pose r2v r := \sum_(i < m) (\sum_(j < n) vec_mx r i j *: bF`_j) *: bL`_i.
+have v2rK: cancel v2r r2v.
+ move=> x; transitivity (\sum_(i < m) coord bL i x *: bL`_i); last first.
+ by rewrite -coord_vbasis ?memvf.
+ (* GG: rewrite {2}(coord_vbasis (memvf x)) -/m would take 8s; *)
+ (* The -/m takes 8s, and without it then apply: eq_bigr takes 12s. *)
+ (* The time drops to 2s with a -[GRing.Field.ringType F]/(F : fieldType) *)
+ apply: eq_bigr => i _; rewrite mxvecK; congr (_ *: _ : L).
+ by rewrite (coordF (coord bL i x)); apply: eq_bigr => j _; rewrite mxE.
+exists (m * n)%N, v2r => //; exists r2v => // r.
+apply: (canLR vec_mxK); apply/matrixP=> i j; rewrite mxE.
+by rewrite !coord_sum_free ?(basis_free (vbasisP _)).
+Qed.
+
+Canonical baseField_vectType := VectType F0 L0 baseField_vectMixin.
+Canonical baseField_FalgType := [FalgType F0 of L0].
+Canonical baseField_extFieldType := [fieldExtType F0 of L0].
+
+Let F0ZEZ a x v : a *: ((x *: v : L) : L0) = (a *: x) *: v.
+Proof. by rewrite [a *: _]scalerA -scalerAl mul1r. Qed.
+
+Let baseVspace_basis V : seq L0 :=
+ [seq tnth bF ij.2 *: tnth (vbasis V) ij.1 | ij : 'I_(\dim V) * 'I_n].
+Definition baseVspace V := <<baseVspace_basis V>>%VS.
+
+Lemma mem_baseVspace V : baseVspace V =i V.
+Proof.
+move=> y; apply/idP/idP=> [/coord_span->|/coord_vbasis->]; last first.
+ apply: memv_suml => i _; rewrite (coordF (coord _ i (y : L))) scaler_suml -/n.
+ apply: memv_suml => j _; rewrite -/bF -F0ZEZ memvZ ?memv_span // -!tnth_nth.
+ by apply/imageP; exists (i, j).
+ (* GG: the F0ZEZ lemma avoids serious performance issues here. *)
+apply: memv_suml => k _; rewrite nth_image; case: (enum_val k) => i j /=.
+by rewrite F0ZEZ memvZ ?vbasis_mem ?mem_tnth.
+Qed.
+
+Lemma dim_baseVspace V : \dim (baseVspace V) = (\dim V * n)%N.
+Proof.
+pose bV0 := baseVspace_basis V; set m := \dim V in bV0 *.
+suffices /size_basis->: basis_of (baseVspace V) bV0.
+ by rewrite card_prod !card_ord.
+rewrite /basis_of eqxx.
+apply/freeP=> s sb0 k; rewrite -(enum_valK k); case/enum_val: k => i j.
+have free_baseP := freeP (basis_free (vbasisP _)).
+move: j; apply: (free_baseP _ _ fullv); move: i; apply: (free_baseP _ _ V).
+transitivity (\sum_i \sum_j s (enum_rank (i, j)) *: bV0`_(enum_rank (i, j))).
+ apply: eq_bigr => i _; rewrite scaler_suml; apply: eq_bigr => j _.
+ by rewrite -F0ZEZ nth_image enum_rankK -!tnth_nth.
+rewrite pair_bigA (reindex _ (onW_bij _ (enum_val_bij _))); apply: etrans sb0.
+by apply: eq_bigr => k _; rewrite -{5 6}[k](enum_valK k); case/enum_val: k.
+Qed.
+
+Fact baseAspace_suproof (E : {subfield L}) : is_aspace (baseVspace E).
+Proof.
+rewrite /is_aspace has_algid1; last by rewrite mem_baseVspace (mem1v E).
+by apply/prodvP=> u v; rewrite !mem_baseVspace; exact: memvM.
+Qed.
+Canonical baseAspace E := ASpace (baseAspace_suproof E).
+
+Fact refBaseField_key : unit. Proof. by []. Qed.
+Definition refBaseField := locked_with refBaseField_key (baseAspace 1).
+Canonical refBaseField_unlockable := [unlockable of refBaseField].
+Notation F1 := refBaseField.
+
+Lemma dim_refBaseField : \dim F1 = n.
+Proof. by rewrite [F1]unlock dim_baseVspace dimv1 mul1n. Qed.
+
+Lemma baseVspace_module V (V0 := baseVspace V) : (F1 * V0 <= V0)%VS.
+Proof.
+apply/prodvP=> u v; rewrite [F1]unlock !mem_baseVspace => /vlineP[x ->] Vv.
+by rewrite -(@scalerAl F L) mul1r; exact: memvZ.
+Qed.
+
+Lemma sub_baseField (E : {subfield L}) : (F1 <= baseVspace E)%VS.
+Proof. by rewrite -sup_field_module baseVspace_module. Qed.
+
+Lemma vspaceOver_refBase V : vspaceOver F1 (baseVspace V) =i V.
+Proof.
+move=> v; rewrite mem_vspaceOver field_module_eq ?baseVspace_module //.
+by rewrite mem_baseVspace.
+Qed.
+
+Lemma module_baseVspace M0 :
+ (F1 * M0 <= M0)%VS -> {V | M0 = baseVspace V & M0 =i V}.
+Proof.
+move=> modM0; pose V := <<vbasis (vspaceOver F1 M0) : seq L>>%VS.
+suffices memM0: M0 =i V.
+ by exists V => //; apply/vspaceP=> v; rewrite mem_baseVspace memM0.
+move=> v; rewrite -{1}(field_module_eq modM0) -(mem_vspaceOver M0) {}/V.
+move: (vspaceOver F1 M0) => M.
+apply/idP/idP=> [/coord_vbasis|/coord_span]->; apply/memv_suml=> i _.
+ rewrite /(_ *: _) /= /fieldOver_scale; case: (coord _ i _) => /= x.
+ rewrite {1}[F1]unlock mem_baseVspace => /vlineP[{x}x ->].
+ by rewrite -(@scalerAl F L) mul1r memvZ ?memv_span ?memt_nth.
+move: (coord _ i _) => x; rewrite -[_`_i]mul1r scalerAl -tnth_nth.
+have F1x: x%:A \in F1.
+ by rewrite [F1]unlock mem_baseVspace (@memvZ F L) // mem1v.
+by congr (_ \in M): (memvZ (Subvs F1x) (vbasis_mem (mem_tnth i _))).
+Qed.
+
+Lemma module_baseAspace (E0 : {subfield L0}) :
+ (F1 <= E0)%VS -> {E | E0 = baseAspace E & E0 =i E}.
+Proof.
+rewrite -sup_field_module => /module_baseVspace[E defE0 memE0].
+suffices algE: is_aspace E by exists (ASpace algE); first exact: val_inj.
+rewrite /is_aspace has_algid1 -?memE0 ?mem1v //.
+by apply/prodvP=> u v; rewrite -!memE0; apply: memvM.
+Qed.
+
+End BaseField.
+
+Notation baseFieldType L := (baseField_type (Phant L)).
+
+(* Base of fieldOver, finally. *)
+Section MoreFieldOver.
+
+Variables (F0 : fieldType) (L : fieldExtType F0) (F : {subfield L}).
+
+Lemma base_vspaceOver V : baseVspace (vspaceOver F V) =i (F * V)%VS.
+Proof. by move=> v; rewrite mem_baseVspace mem_vspaceOver. Qed.
+
+Lemma base_moduleOver V : (F * V <= V)%VS -> baseVspace (vspaceOver F V) =i V.
+Proof. by move=> /field_module_eq defV v; rewrite base_vspaceOver defV. Qed.
+
+Lemma base_aspaceOver (E : {subfield L}) :
+ (F <= E)%VS -> baseVspace (vspaceOver F E) =i E.
+Proof. by rewrite -sup_field_module; apply: base_moduleOver. Qed.
+
+End MoreFieldOver.
+
+Section SubFieldExtension.
+
+Local Open Scope quotient_scope.
+
+Variables (F L : fieldType) (iota : {rmorphism F -> L}).
+Variables (z : L) (p : {poly F}).
+
+Local Notation "p ^iota" := (map_poly (GRing.RMorphism.apply iota) p)
+ (at level 2, format "p ^iota") : ring_scope.
+
+Let wf_p := (p != 0) && root p^iota z.
+Let p0 : {poly F} := if wf_p then (lead_coef p)^-1 *: p else 'X.
+Let z0 := if wf_p then z else 0.
+Let n := (size p0).-1.
+
+Let p0_mon : p0 \is monic.
+Proof.
+rewrite /p0; case: ifP => [/andP[nz_p _] | _]; last exact: monicX.
+by rewrite monicE lead_coefZ mulVf ?lead_coef_eq0.
+Qed.
+
+Let nz_p0 : p0 != 0. Proof. by rewrite monic_neq0 // p0_mon. Qed.
+
+Let p0z0 : root p0^iota z0.
+Proof.
+rewrite /p0 /z0; case: ifP => [/andP[_ pz0]|]; last by rewrite map_polyX rootX.
+by rewrite map_polyZ rootE hornerZ (rootP pz0) mulr0.
+Qed.
+
+Let n_gt0: 0 < n.
+Proof.
+rewrite /n -subn1 subn_gt0 -(size_map_poly iota).
+by rewrite (root_size_gt1 _ p0z0) ?map_poly_eq0.
+Qed.
+
+Let z0Ciota : commr_rmorph iota z0. Proof. by move=> x; apply: mulrC. Qed.
+Local Notation iotaPz := (horner_morph z0Ciota).
+Let iotaFz (x : 'rV[F]_n) := iotaPz (rVpoly x).
+
+Definition equiv_subfext x y := (iotaFz x == iotaFz y).
+
+Fact equiv_subfext_is_equiv : equiv_class_of equiv_subfext.
+Proof. by rewrite /equiv_subfext; split=> x // y w /eqP->. Qed.
+
+Canonical equiv_subfext_equiv := EquivRelPack equiv_subfext_is_equiv.
+Canonical equiv_subfext_encModRel := defaultEncModRel equiv_subfext.
+
+Definition subFExtend := {eq_quot equiv_subfext}.
+Canonical subFExtend_eqType := [eqType of subFExtend].
+Canonical subFExtend_choiceType := [choiceType of subFExtend].
+Canonical subFExtend_quotType := [quotType of subFExtend].
+Canonical subFExtend_eqQuotType := [eqQuotType equiv_subfext of subFExtend].
+
+Definition subfx_inj := lift_fun1 subFExtend iotaFz.
+
+Fact pi_subfx_inj : {mono \pi : x / iotaFz x >-> subfx_inj x}.
+Proof.
+unlock subfx_inj => x; apply/eqP; rewrite -/(equiv_subfext _ x).
+by rewrite -eqmodE reprK.
+Qed.
+Canonical pi_subfx_inj_morph := PiMono1 pi_subfx_inj.
+
+Let iotaPz_repr x : iotaPz (rVpoly (repr (\pi_(subFExtend) x))) = iotaFz x.
+Proof. by rewrite -/(iotaFz _) -!pi_subfx_inj reprK. Qed.
+
+Definition subfext0 := lift_cst subFExtend 0.
+Canonical subfext0_morph := PiConst subfext0.
+
+Definition subfext_add := lift_op2 subFExtend +%R.
+Fact pi_subfext_add : {morph \pi : x y / x + y >-> subfext_add x y}.
+Proof.
+unlock subfext_add => x y /=; apply/eqmodP/eqP.
+by rewrite /iotaFz !linearD /= !iotaPz_repr.
+Qed.
+Canonical pi_subfx_add_morph := PiMorph2 pi_subfext_add.
+
+Definition subfext_opp := lift_op1 subFExtend -%R.
+Fact pi_subfext_opp : {morph \pi : x / - x >-> subfext_opp x}.
+Proof.
+unlock subfext_opp => y /=; apply/eqmodP/eqP.
+by rewrite /iotaFz !linearN /= !iotaPz_repr.
+Qed.
+Canonical pi_subfext_opp_morph := PiMorph1 pi_subfext_opp.
+
+Fact addfxA : associative subfext_add.
+Proof. by move=> x y t; rewrite -[x]reprK -[y]reprK -[t]reprK !piE addrA. Qed.
+
+Fact addfxC : commutative subfext_add.
+Proof. by move=> x y; rewrite -[x]reprK -[y]reprK !piE addrC. Qed.
+
+Fact add0fx : left_id subfext0 subfext_add.
+Proof. by move=> x; rewrite -[x]reprK !piE add0r. Qed.
+
+Fact addfxN : left_inverse subfext0 subfext_opp subfext_add.
+Proof. by move=> x; rewrite -[x]reprK !piE addNr. Qed.
+
+Definition subfext_zmodMixin := ZmodMixin addfxA addfxC add0fx addfxN.
+Canonical subfext_zmodType :=
+ Eval hnf in ZmodType subFExtend subfext_zmodMixin.
+
+Let poly_rV_modp_K q : rVpoly (poly_rV (q %% p0) : 'rV[F]_n) = q %% p0.
+Proof. by apply: poly_rV_K; rewrite -ltnS -polySpred // ltn_modp. Qed.
+
+Let iotaPz_modp q : iotaPz (q %% p0) = iotaPz q.
+Proof.
+rewrite {2}(divp_eq q p0) rmorphD rmorphM /=.
+by rewrite [iotaPz p0](rootP p0z0) mulr0 add0r.
+Qed.
+
+Definition subfx_mul_rep (x y : 'rV[F]_n) : 'rV[F]_n :=
+ poly_rV ((rVpoly x) * (rVpoly y) %% p0).
+
+Definition subfext_mul := lift_op2 subFExtend subfx_mul_rep.
+Fact pi_subfext_mul :
+ {morph \pi : x y / subfx_mul_rep x y >-> subfext_mul x y}.
+Proof.
+unlock subfext_mul => x y /=; apply/eqmodP/eqP.
+by rewrite /iotaFz !poly_rV_modp_K !iotaPz_modp !rmorphM /= !iotaPz_repr.
+Qed.
+Canonical pi_subfext_mul_morph := PiMorph2 pi_subfext_mul.
+
+Definition subfext1 := lift_cst subFExtend (poly_rV 1).
+Canonical subfext1_morph := PiConst subfext1.
+
+Fact mulfxA : associative (subfext_mul).
+Proof.
+elim/quotW=> x; elim/quotW=> y; elim/quotW=> w; rewrite !piE /subfx_mul_rep.
+by rewrite !poly_rV_modp_K [_ %% p0 * _]mulrC !modp_mul // mulrA mulrC.
+Qed.
+
+Fact mulfxC : commutative subfext_mul.
+Proof.
+by elim/quotW=> x; elim/quotW=> y; rewrite !piE /subfx_mul_rep /= mulrC.
+Qed.
+
+Fact mul1fx : left_id subfext1 subfext_mul.
+Proof.
+elim/quotW=> x; rewrite !piE /subfx_mul_rep poly_rV_K ?size_poly1 // mul1r.
+by rewrite modp_small ?rVpolyK // (polySpred nz_p0) ltnS size_poly.
+Qed.
+
+Fact mulfx_addl : left_distributive subfext_mul subfext_add.
+Proof.
+elim/quotW=> x; elim/quotW=> y; elim/quotW=> w; rewrite !piE /subfx_mul_rep.
+by rewrite linearD /= mulrDl modp_add linearD.
+Qed.
+
+Fact nonzero1fx : subfext1 != subfext0.
+Proof.
+rewrite !piE /equiv_subfext /iotaFz !linear0.
+by rewrite poly_rV_K ?rmorph1 ?oner_eq0 // size_poly1.
+Qed.
+
+Definition subfext_comRingMixin :=
+ ComRingMixin mulfxA mulfxC mul1fx mulfx_addl nonzero1fx.
+Canonical subfext_Ring := Eval hnf in RingType subFExtend subfext_comRingMixin.
+Canonical subfext_comRing := Eval hnf in ComRingType subFExtend mulfxC.
+
+Definition subfx_poly_inv (q : {poly F}) : {poly F} :=
+ if iotaPz q == 0 then 0 else
+ let r := gdcop q p0 in let: (u, v) := egcdp q r in
+ ((u * q + v * r)`_0)^-1 *: u.
+
+Let subfx_poly_invE q : iotaPz (subfx_poly_inv q) = (iotaPz q)^-1.
+Proof.
+rewrite /subfx_poly_inv.
+have [-> | nzq] := altP eqP; first by rewrite rmorph0 invr0.
+rewrite [nth]lock -[_^-1]mul1r; apply: canRL (mulfK nzq) _; rewrite -rmorphM /=.
+have rz0: iotaPz (gdcop q p0) = 0.
+ by apply/rootP; rewrite gdcop_map root_gdco ?map_poly_eq0 // p0z0 nzq.
+do [case: gdcopP => r _; rewrite (negPf nz_p0) orbF => co_r_q _] in rz0 *.
+case: (egcdp q r) (egcdpE q r) => u v /=/eqp_size/esym/eqP.
+rewrite coprimep_size_gcd 1?coprimep_sym // => /size_poly1P[a nz_a Da].
+rewrite Da -scalerAl (canRL (addrK _) Da) -lock coefC linearZ linearB /=.
+by rewrite rmorphM /= rz0 mulr0 subr0 horner_morphC -rmorphM mulVf ?rmorph1.
+Qed.
+
+Definition subfx_inv_rep (x : 'rV[F]_n) : 'rV[F]_n :=
+ poly_rV (subfx_poly_inv (rVpoly x) %% p0).
+
+Definition subfext_inv := lift_op1 subFExtend subfx_inv_rep.
+Fact pi_subfext_inv : {morph \pi : x / subfx_inv_rep x >-> subfext_inv x}.
+Proof.
+unlock subfext_inv => x /=; apply/eqmodP/eqP; rewrite /iotaFz.
+by rewrite 2!{1}poly_rV_modp_K 2!{1}iotaPz_modp !subfx_poly_invE iotaPz_repr.
+Qed.
+Canonical pi_subfext_inv_morph := PiMorph1 pi_subfext_inv.
+
+Fact subfx_fieldAxiom :
+ GRing.Field.axiom (subfext_inv : subFExtend -> subFExtend).
+Proof.
+elim/quotW=> x; apply: contraNeq; rewrite !piE /equiv_subfext /iotaFz !linear0.
+apply: contraR => nz_x; rewrite poly_rV_K ?size_poly1 // !poly_rV_modp_K.
+by rewrite iotaPz_modp rmorph1 rmorphM /= iotaPz_modp subfx_poly_invE mulVf.
+Qed.
+
+Fact subfx_inv0 : subfext_inv (0 : subFExtend) = (0 : subFExtend).
+Proof.
+apply/eqP; rewrite !piE /equiv_subfext /iotaFz /subfx_inv_rep !linear0.
+by rewrite /subfx_poly_inv rmorph0 eqxx mod0p !linear0.
+Qed.
+
+Definition subfext_unitRingMixin := FieldUnitMixin subfx_fieldAxiom subfx_inv0.
+Canonical subfext_unitRingType :=
+ Eval hnf in UnitRingType subFExtend subfext_unitRingMixin.
+Canonical subfext_comUnitRing := Eval hnf in [comUnitRingType of subFExtend].
+Definition subfext_fieldMixin := @FieldMixin _ _ subfx_fieldAxiom subfx_inv0.
+Definition subfext_idomainMixin := FieldIdomainMixin subfext_fieldMixin.
+Canonical subfext_idomainType :=
+ Eval hnf in IdomainType subFExtend subfext_idomainMixin.
+Canonical subfext_fieldType :=
+ Eval hnf in FieldType subFExtend subfext_fieldMixin.
+
+Fact subfx_inj_is_rmorphism : rmorphism subfx_inj.
+Proof.
+do 2?split; last by rewrite piE /iotaFz poly_rV_K ?rmorph1 ?size_poly1.
+ by elim/quotW=> x; elim/quotW=> y; rewrite !piE /iotaFz linearB rmorphB.
+elim/quotW=> x; elim/quotW=> y; rewrite !piE /subfx_mul_rep /iotaFz.
+by rewrite poly_rV_modp_K iotaPz_modp rmorphM.
+Qed.
+Canonical subfx_inj_additive := Additive subfx_inj_is_rmorphism.
+Canonical subfx_inj_rmorphism := RMorphism subfx_inj_is_rmorphism.
+
+Definition subfx_eval := lift_embed subFExtend (fun q => poly_rV (q %% p0)).
+Canonical subfx_eval_morph := PiEmbed subfx_eval.
+
+Definition subfx_root := subfx_eval 'X.
+
+Lemma subfx_eval_is_rmorphism : rmorphism subfx_eval.
+Proof.
+do 2?split=> [x y|] /=; apply/eqP; rewrite piE.
+- by rewrite -linearB modp_add modNp.
+- by rewrite /subfx_mul_rep !poly_rV_modp_K !(modp_mul, mulrC _ y).
+by rewrite modp_small // size_poly1 -subn_gt0 subn1.
+Qed.
+Canonical subfx_eval_additive := Additive subfx_eval_is_rmorphism.
+Canonical subfx_eval_rmorphism := AddRMorphism subfx_eval_is_rmorphism.
+
+Definition inj_subfx := (subfx_eval \o polyC).
+Canonical inj_subfx_addidive := [additive of inj_subfx].
+Canonical inj_subfx_rmorphism := [rmorphism of inj_subfx].
+
+Lemma subfxE x: exists p, x = subfx_eval p.
+Proof.
+elim/quotW: x => x; exists (rVpoly x); apply/eqP; rewrite piE /equiv_subfext.
+by rewrite /iotaFz poly_rV_modp_K iotaPz_modp.
+Qed.
+
+Definition subfx_scale a x := inj_subfx a * x.
+Fact subfx_scalerA a b x :
+ subfx_scale a (subfx_scale b x) = subfx_scale (a * b) x.
+Proof. by rewrite /subfx_scale rmorphM mulrA. Qed.
+Fact subfx_scaler1r : left_id 1 subfx_scale.
+Proof. by move=> x; rewrite /subfx_scale rmorph1 mul1r. Qed.
+Fact subfx_scalerDr : right_distributive subfx_scale +%R.
+Proof. by move=> a; exact: mulrDr. Qed.
+Fact subfx_scalerDl x : {morph subfx_scale^~ x : a b / a + b}.
+Proof. by move=> a b; rewrite /subfx_scale rmorphD mulrDl. Qed.
+Definition subfx_lmodMixin :=
+ LmodMixin subfx_scalerA subfx_scaler1r subfx_scalerDr subfx_scalerDl.
+Canonical subfx_lmodType := LmodType F subFExtend subfx_lmodMixin.
+
+Fact subfx_scaleAl : GRing.Lalgebra.axiom ( *%R : subFExtend -> _).
+Proof. by move=> a; apply: mulrA. Qed.
+Canonical subfx_lalgType := LalgType F subFExtend subfx_scaleAl.
+
+Fact subfx_scaleAr : GRing.Algebra.axiom subfx_lalgType.
+Proof. by move=> a; apply: mulrCA. Qed.
+Canonical subfx_algType := AlgType F subFExtend subfx_scaleAr.
+Canonical subfext_unitAlgType := [unitAlgType F of subFExtend].
+
+Fact subfx_evalZ : scalable subfx_eval.
+Proof. by move=> a q; rewrite -mul_polyC rmorphM. Qed.
+Canonical subfx_eval_linear := AddLinear subfx_evalZ.
+Canonical subfx_eval_lrmorphism := [lrmorphism of subfx_eval].
+
+Hypothesis (pz0 : root p^iota z).
+
+Section NonZero.
+
+Hypothesis nz_p : p != 0.
+
+Lemma subfx_inj_eval q : subfx_inj (subfx_eval q) = q^iota.[z].
+Proof.
+by rewrite piE /iotaFz poly_rV_modp_K iotaPz_modp /iotaPz /z0 /wf_p nz_p pz0.
+Qed.
+
+Lemma subfx_inj_root : subfx_inj subfx_root = z.
+Proof. by rewrite subfx_inj_eval // map_polyX hornerX. Qed.
+
+Lemma subfx_injZ b x : subfx_inj (b *: x) = iota b * subfx_inj x.
+Proof. by rewrite rmorphM /= subfx_inj_eval // map_polyC hornerC. Qed.
+
+Lemma subfx_inj_base b : subfx_inj b%:A = iota b.
+Proof. by rewrite subfx_injZ rmorph1 mulr1. Qed.
+
+Lemma subfxEroot x : {q | x = (map_poly (in_alg subFExtend) q).[subfx_root]}.
+Proof.
+have /sig_eqW[q ->] := subfxE x; exists q.
+apply: (fmorph_inj subfx_inj_rmorphism).
+rewrite -horner_map /= subfx_inj_root subfx_inj_eval //.
+by rewrite -map_poly_comp (eq_map_poly subfx_inj_base).
+Qed.
+
+Lemma subfx_irreducibleP :
+ (forall q, root q^iota z -> q != 0 -> size p <= size q) <-> irreducible_poly p.
+Proof.
+split=> [min_p | irr_p q qz0 nz_q].
+ split=> [|q nonC_q q_dv_p].
+ by rewrite -(size_map_poly iota) (root_size_gt1 _ pz0) ?map_poly_eq0.
+ have /dvdpP[r Dp] := q_dv_p; rewrite -dvdp_size_eqp // eqn_leq dvdp_leq //=.
+ have [nz_r nz_q]: r != 0 /\ q != 0 by apply/norP; rewrite -mulf_eq0 -Dp.
+ have: root r^iota z || root q^iota z by rewrite -rootM -rmorphM -Dp.
+ case/orP=> /min_p; [case/(_ _)/idPn=> // | exact].
+ rewrite polySpred // -leqNgt Dp size_mul //= polySpred // -subn2 ltn_subRL.
+ by rewrite addSnnS addnC ltn_add2l ltn_neqAle eq_sym nonC_q size_poly_gt0.
+pose r := gcdp p q; have nz_r: r != 0 by rewrite gcdp_eq0 (negPf nz_p).
+suffices /eqp_size <-: r %= p by rewrite dvdp_leq ?dvdp_gcdr.
+rewrite (irr_p _) ?dvdp_gcdl // -(size_map_poly iota) gtn_eqF //.
+by rewrite (@root_size_gt1 _ z) ?map_poly_eq0 // gcdp_map root_gcd pz0.
+Qed.
+
+End NonZero.
+
+Section Irreducible.
+
+Hypothesis irr_p : irreducible_poly p.
+Let nz_p : p != 0. Proof. exact: irredp_neq0. Qed.
+
+(* The Vector axiom requires irreducibility. *)
+Lemma min_subfx_vectAxiom : Vector.axiom (size p).-1 subfx_lmodType.
+Proof.
+move/subfx_irreducibleP: irr_p => /=/(_ nz_p) min_p; set d := (size p).-1.
+have Dd: d.+1 = size p by rewrite polySpred.
+pose Fz2v x : 'rV_d := poly_rV (sval (sig_eqW (subfxE x)) %% p).
+pose vFz : 'rV_d -> subFExtend := subfx_eval \o @rVpoly F d.
+have FLinj: injective subfx_inj by apply: fmorph_inj.
+have Fz2vK: cancel Fz2v vFz.
+ move=> x; rewrite /vFz /Fz2v; case: (sig_eqW _) => /= q ->.
+ apply: FLinj; rewrite !subfx_inj_eval // {2}(divp_eq q p) rmorphD rmorphM /=.
+ by rewrite !hornerE (eqP pz0) mulr0 add0r poly_rV_K // -ltnS Dd ltn_modpN0.
+suffices vFzK: cancel vFz Fz2v.
+ by exists Fz2v; [apply: can2_linear Fz2vK | exists vFz].
+apply: inj_can_sym Fz2vK _ => v1 v2 /(congr1 subfx_inj)/eqP.
+rewrite -subr_eq0 -!raddfB /= subfx_inj_eval // => /min_p/implyP.
+rewrite leqNgt implybNN -Dd ltnS size_poly linearB subr_eq0 /=.
+by move/eqP/(can_inj (@rVpolyK _ _)).
+Qed.
+
+Definition SubfxVectMixin := VectMixin min_subfx_vectAxiom.
+Definition SubfxVectType := VectType F subFExtend SubfxVectMixin.
+Definition SubfxFalgType := Eval simpl in [FalgType F of SubfxVectType].
+Definition SubFieldExtType := Eval simpl in [fieldExtType F of SubfxFalgType].
+
+End Irreducible.
+
+End SubFieldExtension.
+
+Prenex Implicits subfx_inj.
+
+Lemma irredp_FAdjoin (F : fieldType) (p : {poly F}) :
+ irreducible_poly p ->
+ {L : fieldExtType F & \dim {:L} = (size p).-1 &
+ {z | root (map_poly (in_alg L) p) z & <<1; z>>%VS = fullv}}.
+Proof.
+case=> p_gt1 irr_p; set n := (size p).-1; pose vL := [vectType F of 'rV_n].
+have Dn: n.+1 = size p := ltn_predK p_gt1.
+have nz_p: p != 0 by rewrite -size_poly_eq0 -Dn.
+suffices [L dimL [toPF [toL toPF_K toL_K]]]:
+ {L : fieldExtType F & \dim {:L} = (size p).-1
+ & {toPF : {linear L -> {poly F}} & {toL : {lrmorphism {poly F} -> L} |
+ cancel toPF toL & forall q, toPF (toL q) = q %% p}}}.
+- exists L => //; pose z := toL 'X; set iota := in_alg _.
+ suffices q_z q: toPF (map_poly iota q).[z] = q %% p.
+ exists z; first by rewrite /root -(can_eq toPF_K) q_z modpp linear0.
+ apply/vspaceP=> x; rewrite memvf; apply/Fadjoin_polyP.
+ exists (map_poly iota (toPF x)).
+ by apply/polyOverP=> i; rewrite coef_map memvZ ?mem1v.
+ by apply: (can_inj toPF_K); rewrite q_z -toL_K toPF_K.
+ elim/poly_ind: q => [|a q IHq].
+ by rewrite map_poly0 horner0 linear0 mod0p.
+ rewrite rmorphD rmorphM /= map_polyX map_polyC hornerMXaddC linearD /=.
+ rewrite linearZ /= -(rmorph1 toL) toL_K -modp_scalel alg_polyC modp_add.
+ congr (_ + _); rewrite -toL_K rmorphM /= -/z; congr (toPF (_ * z)).
+ by apply: (can_inj toPF_K); rewrite toL_K.
+pose toL q : vL := poly_rV (q %% p); pose toPF (x : vL) := rVpoly x.
+have toL_K q : toPF (toL q) = q %% p.
+ by rewrite /toPF poly_rV_K // -ltnS Dn ?ltn_modp -?Dn.
+have toPF_K: cancel toPF toL.
+ by move=> x; rewrite /toL modp_small ?rVpolyK // -Dn ltnS size_poly.
+have toPinj := can_inj toPF_K.
+pose mul x y := toL (toPF x * toPF y); pose L1 := toL 1.
+have L1K: toPF L1 = 1 by rewrite toL_K modp_small ?size_poly1.
+have mulC: commutative mul by rewrite /mul => x y; rewrite mulrC.
+have mulA: associative mul.
+ by move=> x y z; apply: toPinj; rewrite -!(mulC z) !toL_K !modp_mul mulrCA.
+have mul1: left_id L1 mul.
+ by move=> x; apply: toPinj; rewrite mulC !toL_K modp_mul mulr1 -toL_K toPF_K.
+have mulD: left_distributive mul +%R.
+ move=> x y z; apply: toPinj; rewrite /toPF raddfD /= -!/(toPF _).
+ by rewrite !toL_K /toPF raddfD mulrDl modp_add.
+have nzL1: L1 != 0 by rewrite -(inj_eq toPinj) L1K /toPF raddf0 oner_eq0.
+pose mulM := ComRingMixin mulA mulC mul1 mulD nzL1.
+pose rL := ComRingType (RingType vL mulM) mulC.
+have mulZl: GRing.Lalgebra.axiom mul.
+ move=> a x y; apply: toPinj; rewrite toL_K /toPF !linearZ /= -!/(toPF _).
+ by rewrite toL_K -scalerAl modp_scalel.
+have mulZr: GRing.Algebra.axiom (LalgType F rL mulZl).
+ by move=> a x y; rewrite !(mulrC x) scalerAl.
+pose aL := AlgType F _ mulZr; pose urL := FalgUnitRingType aL.
+pose uaL := [unitAlgType F of AlgType F urL mulZr].
+pose faL := [FalgType F of uaL].
+have unitE: GRing.Field.mixin_of urL.
+ move=> x nz_x; apply/unitrP; set q := toPF x.
+ have nz_q: q != 0 by rewrite -(inj_eq toPinj) /toPF raddf0 in nz_x.
+ have /Bezout_eq1_coprimepP[u upq1]: coprimep p q.
+ apply: contraLR (leq_gcdpr p nz_q) => /irr_p/implyP.
+ rewrite dvdp_gcdl -ltnNge /= => /eqp_size->.
+ by rewrite (polySpred nz_p) ltnS size_poly.
+ suffices: x * toL u.2 = 1 by exists (toL u.2); rewrite mulrC.
+ apply: toPinj; rewrite !toL_K -upq1 modp_mul modp_add mulrC.
+ by rewrite modp_mull add0r.
+pose ucrL := [comUnitRingType of ComRingType urL mulC].
+have mul0 := GRing.Field.IdomainMixin unitE.
+pose fL := FieldType (IdomainType ucrL mul0) unitE.
+exists [fieldExtType F of faL for fL]; first by rewrite dimvf; apply: mul1n.
+exists [linear of toPF as @rVpoly _ _].
+suffices toLM: lrmorphism (toL : {poly F} -> aL) by exists (LRMorphism toLM).
+have toLlin: linear toL.
+ by move=> a q1 q2; rewrite -linearP -modp_scalel -modp_add.
+do ?split; try exact: toLlin; move=> q r /=.
+by apply: toPinj; rewrite !toL_K modp_mul -!(mulrC r) modp_mul.
+Qed.
+
+(*Coq 8.3 processes this shorter proof correctly, but then crashes on Qed.
+Lemma Xirredp_FAdjoin' (F : fieldType) (p : {poly F}) :
+ irreducible_poly p ->
+ {L : fieldExtType F & Vector.dim L = (size p).-1 &
+ {z | root (map_poly (in_alg L) p) z & <<1; z>>%VS = fullv}}.
+Proof.
+case=> p_gt1 irr_p; set n := (size p).-1; pose vL := [vectType F of 'rV_n].
+have Dn: n.+1 = size p := ltn_predK p_gt1.
+have nz_p: p != 0 by rewrite -size_poly_eq0 -Dn.
+pose toL q : vL := poly_rV (q %% p).
+have toL_K q : rVpoly (toL q) = q %% p.
+ by rewrite poly_rV_K // -ltnS Dn ?ltn_modp -?Dn.
+pose mul (x y : vL) : vL := toL (rVpoly x * rVpoly y).
+pose L1 : vL := poly_rV 1.
+have L1K: rVpoly L1 = 1 by rewrite poly_rV_K // size_poly1 -ltnS Dn.
+have mulC: commutative mul by rewrite /mul => x y; rewrite mulrC.
+have mulA: associative mul.
+ by move=> x y z; rewrite -!(mulC z) /mul !toL_K /toL !modp_mul mulrCA.
+have mul1: left_id L1 mul.
+ move=> x; rewrite /mul L1K mul1r /toL modp_small ?rVpolyK // -Dn ltnS.
+ by rewrite size_poly.
+have mulD: left_distributive mul +%R.
+ move=> x y z; apply: canLR (@rVpolyK _ _) _.
+ by rewrite !raddfD mulrDl /= !toL_K /toL modp_add.
+have nzL1: L1 != 0 by rewrite -(can_eq (@rVpolyK _ _)) L1K raddf0 oner_eq0.
+pose mulM := ComRingMixin mulA mulC mul1 mulD nzL1.
+pose rL := ComRingType (RingType vL mulM) mulC.
+have mulZl: GRing.Lalgebra.axiom mul.
+ move=> a x y; apply: canRL (@rVpolyK _ _) _; rewrite !linearZ /= toL_K.
+ by rewrite -scalerAl modp_scalel.
+have mulZr: @GRing.Algebra.axiom _ (LalgType F rL mulZl).
+ by move=> a x y; rewrite !(mulrC x) scalerAl.
+pose aL := AlgType F _ mulZr; pose urL := FalgUnitRingType aL.
+pose uaL := [unitAlgType F of AlgType F urL mulZr].
+pose faL := [FalgType F of uaL].
+have unitE: GRing.Field.mixin_of urL.
+ move=> x nz_x; apply/unitrP; set q := rVpoly x.
+ have nz_q: q != 0 by rewrite -(can_eq (@rVpolyK _ _)) raddf0 in nz_x.
+ have /Bezout_eq1_coprimepP[u upq1]: coprimep p q.
+ have /contraR := irr_p _ _ (dvdp_gcdl p q); apply.
+ have: size (gcdp p q) <= size q by exact: leq_gcdpr.
+ rewrite leqNgt;apply:contra;move/eqp_size ->.
+ by rewrite (polySpred nz_p) ltnS size_poly.
+ suffices: x * toL u.2 = 1 by exists (toL u.2); rewrite mulrC.
+ congr (poly_rV _); rewrite toL_K modp_mul mulrC (canRL (addKr _) upq1).
+ by rewrite -mulNr modp_addl_mul_small ?size_poly1.
+pose ucrL := [comUnitRingType of ComRingType urL mulC].
+pose fL := FieldType (IdomainType ucrL (GRing.Field.IdomainMixin unitE)) unitE.
+exists [fieldExtType F of faL for fL]; first exact: mul1n.
+pose z : vL := toL 'X; set iota := in_alg _.
+have q_z q: rVpoly (map_poly iota q).[z] = q %% p.
+ elim/poly_ind: q => [|a q IHq].
+ by rewrite map_poly0 horner0 linear0 mod0p.
+ rewrite rmorphD rmorphM /= map_polyX map_polyC hornerMXaddC linearD /=.
+ rewrite linearZ /= L1K alg_polyC modp_add; congr (_ + _); last first.
+ by rewrite modp_small // size_polyC; case: (~~ _) => //; apply: ltnW.
+ by rewrite !toL_K IHq mulrC modp_mul mulrC modp_mul.
+exists z; first by rewrite /root -(can_eq (@rVpolyK _ _)) q_z modpp linear0.
+apply/vspaceP=> x; rewrite memvf; apply/Fadjoin_polyP.
+exists (map_poly iota (rVpoly x)).
+ by apply/polyOverP=> i; rewrite coef_map memvZ ?mem1v.
+apply: (can_inj (@rVpolyK _ _)).
+by rewrite q_z modp_small // -Dn ltnS size_poly.
+Qed.
+*)