aboutsummaryrefslogtreecommitdiff
path: root/mathcomp/algebra/polyXY.v
diff options
context:
space:
mode:
Diffstat (limited to 'mathcomp/algebra/polyXY.v')
-rw-r--r--mathcomp/algebra/polyXY.v405
1 files changed, 405 insertions, 0 deletions
diff --git a/mathcomp/algebra/polyXY.v b/mathcomp/algebra/polyXY.v
new file mode 100644
index 0000000..3d2292e
--- /dev/null
+++ b/mathcomp/algebra/polyXY.v
@@ -0,0 +1,405 @@
+(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *)
+Require Import ssreflect ssrfun ssrbool choice eqtype ssrnat seq div fintype.
+Require Import tuple finfun bigop fingroup perm ssralg zmodp matrix mxalgebra.
+Require Import poly polydiv mxpoly binomial.
+
+(******************************************************************************)
+(* This file provides additional primitives and theory for bivariate *)
+(* polynomials (polynomials of two variables), represented as polynomials *)
+(* with (univariate) polynomial coefficients : *)
+(* 'Y == the (generic) second variable (:= 'X%:P). *)
+(* p^:P == the bivariate polynomial p['X], for p univariate. *)
+(* := map_poly polyC p (this notation is defined in poly.v). *)
+(* u.[x, y] == the bivariate polynomial u evaluated at 'X = x, 'Y = y. *)
+(* := u.[x%:P].[y]. *)
+(* sizeY u == the size of u in 'Y (1 + the 'Y-degree of u, if u != 0). *)
+(* := \max_(i < size u) size u`_i. *)
+(* swapXY u == the bivariate polynomial u['Y, 'X], for u bivariate. *)
+(* poly_XaY p == the bivariate polynomial p['X + 'Y], for p univariate. *)
+(* := p^:P \Po ('X + 'Y). *)
+(* poly_XmY p == the bivariate polynomial p['X * 'Y], for p univariate. *)
+(* := P^:P \Po ('X * 'Y). *)
+(* sub_annihilant p q == for univariate p, q != 0, a nonzero polynomial whose *)
+(* roots include all the differences of roots of p and q, in *)
+(* all field extensions (:= resultant (poly_XaY p) q^:P). *)
+(* div_annihilant p q == for polynomials p != 0, q with q.[0] != 0, a nonzero *)
+(* polynomial whose roots include all the quotients of roots *)
+(* of p by roots of q, in all field extensions *)
+(* (:= resultant (poly_XmY p) q^:P). *)
+(* The latter two "annhilants" provide uniform witnesses for an alternative *)
+(* proof of the closure of the algebraicOver predicate (see mxpoly.v). The *)
+(* fact that the annhilant does not depend on the particular choice of roots *)
+(* of p and q is crucial for the proof of the Primitive Element Theorem (file *)
+(* separable.v). *)
+(******************************************************************************)
+
+Set Implicit Arguments.
+Unset Strict Implicit.
+Unset Printing Implicit Defensive.
+
+Local Open Scope ring_scope.
+Import GRing.Theory.
+
+Local Notation "p ^ f" := (map_poly f p) : ring_scope.
+Local Notation eval := horner_eval.
+
+Notation "'Y" := 'X%:P : ring_scope.
+Notation "p ^:P" := (p ^ polyC) (at level 2, format "p ^:P") : ring_scope.
+Notation "p .[ x , y ]" := (p.[x%:P].[y])
+ (at level 2, left associativity, format "p .[ x , y ]") : ring_scope.
+
+Section PolyXY_Ring.
+
+Variable R : ringType.
+Implicit Types (u : {poly {poly R}}) (p q : {poly R}) (x : R).
+
+Fact swapXY_key : unit. Proof. by []. Qed.
+Definition swapXY_def u : {poly {poly R}} := (u ^ map_poly polyC).['Y].
+Definition swapXY := locked_with swapXY_key swapXY_def.
+Canonical swapXY_unlockable := [unlockable fun swapXY].
+
+Definition sizeY u : nat := \max_(i < size u) (size u`_i).
+Definition poly_XaY p : {poly {poly R}} := p^:P \Po ('X + 'Y).
+Definition poly_XmY p : {poly {poly R}} := p^:P \Po ('X * 'Y).
+Definition sub_annihilant p q := resultant (poly_XaY p) q^:P.
+Definition div_annihilant p q := resultant (poly_XmY p) q^:P.
+
+Lemma swapXY_polyC p : swapXY p%:P = p^:P.
+Proof. by rewrite unlock map_polyC hornerC. Qed.
+
+Lemma swapXY_X : swapXY 'X = 'Y.
+Proof. by rewrite unlock map_polyX hornerX. Qed.
+
+Lemma swapXY_Y : swapXY 'Y = 'X.
+Proof. by rewrite swapXY_polyC map_polyX. Qed.
+
+Lemma swapXY_is_additive : additive swapXY.
+Proof. by move=> u v; rewrite unlock rmorphB !hornerE. Qed.
+Canonical swapXY_addf := Additive swapXY_is_additive.
+
+Lemma coef_swapXY u i j : (swapXY u)`_i`_j = u`_j`_i.
+Proof.
+elim/poly_ind: u => [|u p IHu] in i j *; first by rewrite raddf0 !coef0.
+rewrite raddfD !coefD /= swapXY_polyC coef_map /= !coefC coefMX.
+rewrite !(fun_if (fun q : {poly R} => q`_i)) coef0 -IHu; congr (_ + _).
+by rewrite unlock rmorphM /= map_polyX hornerMX coefMC coefMX.
+Qed.
+
+Lemma swapXYK : involutive swapXY.
+Proof. by move=> u; apply/polyP=> i; apply/polyP=> j; rewrite !coef_swapXY. Qed.
+
+Lemma swapXY_map_polyC p : swapXY p^:P = p%:P.
+Proof. by rewrite -swapXY_polyC swapXYK. Qed.
+
+Lemma swapXY_eq0 u : (swapXY u == 0) = (u == 0).
+Proof. by rewrite (inv_eq swapXYK) raddf0. Qed.
+
+Lemma swapXY_is_multiplicative : multiplicative swapXY.
+Proof.
+split=> [u v|]; last by rewrite swapXY_polyC map_polyC.
+apply/polyP=> i; apply/polyP=> j; rewrite coef_swapXY !coefM !coef_sum.
+rewrite (eq_bigr _ (fun _ _ => coefM _ _ _)) exchange_big /=.
+apply: eq_bigr => j1 _; rewrite coefM; apply: eq_bigr=> i1 _.
+by rewrite !coef_swapXY.
+Qed.
+Canonical swapXY_rmorphism := AddRMorphism swapXY_is_multiplicative.
+
+Lemma swapXY_is_scalable : scalable_for (map_poly polyC \; *%R) swapXY.
+Proof. by move=> p u /=; rewrite -mul_polyC rmorphM /= swapXY_polyC. Qed.
+Canonical swapXY_linear := AddLinear swapXY_is_scalable.
+Canonical swapXY_lrmorphism := [lrmorphism of swapXY].
+
+Lemma swapXY_comp_poly p u : swapXY (p^:P \Po u) = p^:P \Po swapXY u.
+Proof.
+rewrite -horner_map; congr _.[_]; rewrite -!map_poly_comp /=.
+by apply: eq_map_poly => x; rewrite /= swapXY_polyC map_polyC.
+Qed.
+
+Lemma max_size_coefXY u i : size u`_i <= sizeY u.
+Proof.
+have [ltiu | /(nth_default 0)->] := ltnP i (size u); last by rewrite size_poly0.
+exact: (bigmax_sup (Ordinal ltiu)).
+Qed.
+
+Lemma max_size_lead_coefXY u : size (lead_coef u) <= sizeY u.
+Proof. by rewrite lead_coefE max_size_coefXY. Qed.
+
+Lemma max_size_evalX u : size u.['X] <= sizeY u + (size u).-1.
+Proof.
+rewrite horner_coef (leq_trans (size_sum _ _ _)) //; apply/bigmax_leqP=> i _.
+rewrite (leq_trans (size_mul_leq _ _)) // size_polyXn addnS.
+by rewrite leq_add ?max_size_coefXY //= -ltnS (leq_trans _ (leqSpred _)).
+Qed.
+
+Lemma max_size_evalC u x : size u.[x%:P] <= sizeY u.
+Proof.
+rewrite horner_coef (leq_trans (size_sum _ _ _)) //; apply/bigmax_leqP=> i _.
+rewrite (leq_trans (size_mul_leq _ _)) // -polyC_exp size_polyC addnC -subn1.
+by rewrite (leq_trans _ (max_size_coefXY _ i)) // leq_subLR leq_add2r leq_b1.
+Qed.
+
+Lemma sizeYE u : sizeY u = size (swapXY u).
+Proof.
+apply/eqP; rewrite eqn_leq; apply/andP; split.
+ apply/bigmax_leqP=> /= i _; apply/leq_sizeP => j /(nth_default 0) u_j_0.
+ by rewrite -coef_swapXY u_j_0 coef0.
+apply/leq_sizeP=> j le_uY_j; apply/polyP=> i; rewrite coef_swapXY coef0.
+by rewrite nth_default // (leq_trans _ le_uY_j) ?max_size_coefXY.
+Qed.
+
+Lemma sizeY_eq0 u : (sizeY u == 0%N) = (u == 0).
+Proof. by rewrite sizeYE size_poly_eq0 swapXY_eq0. Qed.
+
+Lemma sizeY_mulX u : sizeY (u * 'X) = sizeY u.
+Proof.
+rewrite !sizeYE rmorphM /= swapXY_X rreg_size //.
+by have /monic_comreg[_ /rreg_lead] := monicX R.
+Qed.
+
+Lemma swapXY_poly_XaY p : swapXY (poly_XaY p) = poly_XaY p.
+Proof. by rewrite swapXY_comp_poly rmorphD /= swapXY_X swapXY_Y addrC. Qed.
+
+Lemma swapXY_poly_XmY p : swapXY (poly_XmY p) = poly_XmY p.
+Proof.
+by rewrite swapXY_comp_poly rmorphM /= swapXY_X swapXY_Y commr_polyX.
+Qed.
+
+Lemma poly_XaY0 : poly_XaY 0 = 0.
+Proof. by rewrite /poly_XaY rmorph0 comp_poly0. Qed.
+
+Lemma poly_XmY0 : poly_XmY 0 = 0.
+Proof. by rewrite /poly_XmY rmorph0 comp_poly0. Qed.
+
+End PolyXY_Ring.
+
+Prenex Implicits swapXY sizeY poly_XaY poly_XmY sub_annihilant div_annihilant.
+Prenex Implicits swapXYK.
+
+Lemma swapXY_map (R S : ringType) (f : {additive R -> S}) u :
+ swapXY (u ^ map_poly f) = swapXY u ^ map_poly f.
+Proof.
+by apply/polyP=> i; apply/polyP=> j; rewrite !(coef_map, coef_swapXY).
+Qed.
+
+Section PolyXY_ComRing.
+
+Variable R : comRingType.
+Implicit Types (u : {poly {poly R}}) (p : {poly R}) (x y : R).
+
+Lemma horner_swapXY u x : (swapXY u).[x%:P] = u ^ eval x.
+Proof.
+apply/polyP=> i /=; rewrite coef_map /= /eval horner_coef coef_sum -sizeYE.
+rewrite (horner_coef_wide _ (max_size_coefXY u i)); apply: eq_bigr=> j _.
+by rewrite -polyC_exp coefMC coef_swapXY.
+Qed.
+
+Lemma horner_polyC u x : u.[x%:P] = swapXY u ^ eval x.
+Proof. by rewrite -horner_swapXY swapXYK. Qed.
+
+Lemma horner2_swapXY u x y : (swapXY u).[x, y] = u.[y, x].
+Proof. by rewrite horner_swapXY -{1}(hornerC y x) horner_map. Qed.
+
+Lemma horner_poly_XaY p v : (poly_XaY p).[v] = p \Po (v + 'X).
+Proof. by rewrite horner_comp !hornerE. Qed.
+
+Lemma horner_poly_XmY p v : (poly_XmY p).[v] = p \Po (v * 'X).
+Proof. by rewrite horner_comp !hornerE. Qed.
+
+End PolyXY_ComRing.
+
+Section PolyXY_Idomain.
+
+Variable R : idomainType.
+Implicit Types (p q : {poly R}) (x y : R).
+
+Lemma size_poly_XaY p : size (poly_XaY p) = size p.
+Proof. by rewrite size_comp_poly2 ?size_XaddC // size_map_polyC. Qed.
+
+Lemma poly_XaY_eq0 p : (poly_XaY p == 0) = (p == 0).
+Proof. by rewrite -!size_poly_eq0 size_poly_XaY. Qed.
+
+Lemma size_poly_XmY p : size (poly_XmY p) = size p.
+Proof. by rewrite size_comp_poly2 ?size_XmulC ?polyX_eq0 ?size_map_polyC. Qed.
+
+Lemma poly_XmY_eq0 p : (poly_XmY p == 0) = (p == 0).
+Proof. by rewrite -!size_poly_eq0 size_poly_XmY. Qed.
+
+Lemma lead_coef_poly_XaY p : lead_coef (poly_XaY p) = (lead_coef p)%:P.
+Proof.
+rewrite lead_coef_comp ?size_XaddC // -['Y]opprK -polyC_opp lead_coefXsubC.
+by rewrite expr1n mulr1 lead_coef_map_inj //; apply: polyC_inj.
+Qed.
+
+Lemma sub_annihilant_in_ideal p q :
+ 1 < size p -> 1 < size q ->
+ {uv : {poly {poly R}} * {poly {poly R}}
+ | size uv.1 < size q /\ size uv.2 < size p
+ & forall x y,
+ (sub_annihilant p q).[y] = uv.1.[x, y] * p.[x + y] + uv.2.[x, y] * q.[x]}.
+Proof.
+rewrite -size_poly_XaY -(size_map_polyC q) => p1_gt1 q1_gt1.
+have [uv /= [ub_u ub_v Dr]] := resultant_in_ideal p1_gt1 q1_gt1.
+exists uv => // x y; rewrite -[r in r.[y]](hornerC _ x%:P) Dr.
+by rewrite !(hornerE, horner_comp).
+Qed.
+
+Lemma sub_annihilantP p q x y :
+ p != 0 -> q != 0 -> p.[x] = 0 -> q.[y] = 0 ->
+ (sub_annihilant p q).[x - y] = 0.
+Proof.
+move=> nz_p nz_q px0 qy0.
+have p_gt1: size p > 1 by have /rootP/root_size_gt1-> := px0.
+have q_gt1: size q > 1 by have /rootP/root_size_gt1-> := qy0.
+have [uv /= _ /(_ y)->] := sub_annihilant_in_ideal p_gt1 q_gt1.
+by rewrite (addrC y) subrK px0 qy0 !mulr0 addr0.
+Qed.
+
+Lemma sub_annihilant_neq0 p q : p != 0 -> q != 0 -> sub_annihilant p q != 0.
+Proof.
+rewrite resultant_eq0; set p1 := poly_XaY p => nz_p nz_q.
+have [nz_p1 nz_q1]: p1 != 0 /\ q^:P != 0 by rewrite poly_XaY_eq0 map_polyC_eq0.
+rewrite -leqNgt eq_leq //; apply/eqP/Bezout_coprimepPn=> // [[[u v]]] /=.
+rewrite !size_poly_gt0 -andbA => /and4P[nz_u ltuq nz_v _] Duv.
+have /eqP/= := congr1 (size \o (lead_coef \o swapXY)) Duv.
+rewrite ltn_eqF // !rmorphM !lead_coefM (leq_trans (leq_ltn_trans _ ltuq)) //=.
+ rewrite -{2}[u]swapXYK -sizeYE swapXY_poly_XaY lead_coef_poly_XaY.
+ by rewrite mulrC mul_polyC size_scale ?max_size_lead_coefXY ?lead_coef_eq0.
+rewrite swapXY_map_polyC lead_coefC size_map_polyC.
+set v1 := lead_coef _; have nz_v1: v1 != 0 by rewrite lead_coef_eq0 swapXY_eq0.
+rewrite [in rhs in _ <= rhs]polySpred ?mulf_neq0 // size_mul //.
+by rewrite (polySpred nz_v1) addnC addnS polySpred // ltnS leq_addr.
+Qed.
+
+Lemma div_annihilant_in_ideal p q :
+ 1 < size p -> 1 < size q ->
+ {uv : {poly {poly R}} * {poly {poly R}}
+ | size uv.1 < size q /\ size uv.2 < size p
+ & forall x y,
+ (div_annihilant p q).[y] = uv.1.[x, y] * p.[x * y] + uv.2.[x, y] * q.[x]}.
+Proof.
+rewrite -size_poly_XmY -(size_map_polyC q) => p1_gt1 q1_gt1.
+have [uv /= [ub_u ub_v Dr]] := resultant_in_ideal p1_gt1 q1_gt1.
+exists uv => // x y; rewrite -[r in r.[y]](hornerC _ x%:P) Dr.
+by rewrite !(hornerE, horner_comp).
+Qed.
+
+Lemma div_annihilant_neq0 p q : p != 0 -> q.[0] != 0 -> div_annihilant p q != 0.
+Proof.
+have factorX u: u != 0 -> root u 0 -> exists2 v, v != 0 & u = v * 'X.
+ move=> nz_u /factor_theorem[v]; rewrite subr0 => Du; exists v => //.
+ by apply: contraNneq nz_u => v0; rewrite Du v0 mul0r.
+have nzX: 'X != 0 := monic_neq0 (monicX _); have rootC0 := root_polyC _ 0.
+rewrite resultant_eq0 -leqNgt -rootE // => nz_p nz_q0; apply/eq_leq/eqP.
+have nz_q: q != 0 by apply: contraNneq nz_q0 => ->; rewrite root0.
+apply/Bezout_coprimepPn; rewrite ?map_polyC_eq0 ?poly_XmY_eq0 // => [[uv]].
+rewrite !size_poly_gt0 -andbA ltnNge => /and4P[nz_u /negP ltuq nz_v _] Duv.
+pose u := swapXY uv.1; pose v := swapXY uv.2.
+suffices{ltuq}: size q <= sizeY u by rewrite sizeYE swapXYK -size_map_polyC.
+have{nz_u nz_v} [nz_u nz_v Dvu]: [/\ u != 0, v != 0 & q *: v = u * poly_XmY p].
+ rewrite !swapXY_eq0; split=> //; apply: (can_inj swapXYK).
+ by rewrite linearZ rmorphM /= !swapXYK swapXY_poly_XmY Duv mulrC.
+have{Duv} [n ltvn]: {n | size v < n} by exists (size v).+1.
+elim: n {uv} => // n IHn in p (v) (u) nz_u nz_v Dvu nz_p ltvn *.
+have Dp0: root (poly_XmY p) 0 = root p 0 by rewrite root_comp !hornerE rootC0.
+have Dv0: root u 0 || root p 0 = root v 0 by rewrite -Dp0 -rootM -Dvu rootZ.
+have [v0_0 | nz_v0] := boolP (root v 0); last first.
+ have nz_p0: ~~ root p 0 by apply: contra nz_v0; rewrite -Dv0 orbC => ->.
+ apply: (@leq_trans (size (q * v.[0]))).
+ by rewrite size_mul // (polySpred nz_v0) addnS leq_addr.
+ rewrite -hornerZ Dvu !(horner_comp, hornerE) horner_map mulrC size_Cmul //.
+ by rewrite horner_coef0 max_size_coefXY.
+have [v1 nz_v1 Dv] := factorX _ _ nz_v v0_0; rewrite Dv size_mulX // in ltvn.
+have /orP[/factorX[//|u1 nz_u1 Du] | p0_0]: root u 0 || root p 0 by rewrite Dv0.
+ rewrite Du sizeY_mulX; apply: IHn nz_u1 nz_v1 _ nz_p ltvn.
+ by apply: (mulIf (nzX _)); rewrite mulrAC -scalerAl -Du -Dv.
+have /factorX[|v2 nz_v2 Dv1]: root (swapXY v1) 0; rewrite ?swapXY_eq0 //.
+ suffices: root (swapXY v1 * 'Y) 0 by rewrite mulrC mul_polyC rootZ ?polyX_eq0.
+ have: root (swapXY (q *: v)) 0.
+ by rewrite Dvu rmorphM rootM /= swapXY_poly_XmY Dp0 p0_0 orbT.
+ by rewrite linearZ rootM rootC0 (negPf nz_q0) /= Dv rmorphM /= swapXY_X.
+rewrite ltnS (canRL swapXYK Dv1) -sizeYE sizeY_mulX sizeYE in ltvn.
+have [p1 nz_p1 Dp] := factorX _ _ nz_p p0_0.
+apply: IHn nz_u _ _ nz_p1 ltvn; first by rewrite swapXY_eq0.
+apply: (@mulIf _ ('X * 'Y)); first by rewrite mulf_neq0 ?polyC_eq0 ?nzX.
+rewrite -scalerAl mulrA mulrAC -{1}swapXY_X -rmorphM /= -Dv1 swapXYK -Dv Dvu.
+by rewrite /poly_XmY Dp rmorphM /= map_polyX comp_polyM comp_polyX mulrA.
+Qed.
+
+End PolyXY_Idomain.
+
+Section PolyXY_Field.
+
+Variables (F E : fieldType) (FtoE : {rmorphism F -> E}).
+
+Local Notation pFtoE := (map_poly (GRing.RMorphism.apply FtoE)).
+
+Lemma div_annihilantP (p q : {poly E}) (x y : E) :
+ p != 0 -> q != 0 -> y != 0 -> p.[x] = 0 -> q.[y] = 0 ->
+ (div_annihilant p q).[x / y] = 0.
+Proof.
+move=> nz_p nz_q nz_y px0 qy0.
+have p_gt1: size p > 1 by have /rootP/root_size_gt1-> := px0.
+have q_gt1: size q > 1 by have /rootP/root_size_gt1-> := qy0.
+have [uv /= _ /(_ y)->] := div_annihilant_in_ideal p_gt1 q_gt1.
+by rewrite (mulrC y) divfK // px0 qy0 !mulr0 addr0.
+Qed.
+
+Lemma map_sub_annihilantP (p q : {poly F}) (x y : E) :
+ p != 0 -> q != 0 ->(p ^ FtoE).[x] = 0 -> (q ^ FtoE).[y] = 0 ->
+ (sub_annihilant p q ^ FtoE).[x - y] = 0.
+Proof.
+move=> nz_p nz_q px0 qy0; have pFto0 := map_poly_eq0 FtoE.
+rewrite map_resultant ?pFto0 ?lead_coef_eq0 ?map_poly_eq0 ?poly_XaY_eq0 //.
+rewrite map_comp_poly rmorphD /= map_polyC /= !map_polyX -!map_poly_comp /=.
+by rewrite !(eq_map_poly (map_polyC _)) !map_poly_comp sub_annihilantP ?pFto0.
+Qed.
+
+Lemma map_div_annihilantP (p q : {poly F}) (x y : E) :
+ p != 0 -> q != 0 -> y != 0 -> (p ^ FtoE).[x] = 0 -> (q ^ FtoE).[y] = 0 ->
+ (div_annihilant p q ^ FtoE).[x / y] = 0.
+Proof.
+move=> nz_p nz_q nz_y px0 qy0; have pFto0 := map_poly_eq0 FtoE.
+rewrite map_resultant ?pFto0 ?lead_coef_eq0 ?map_poly_eq0 ?poly_XmY_eq0 //.
+rewrite map_comp_poly rmorphM /= map_polyC /= !map_polyX -!map_poly_comp /=.
+by rewrite !(eq_map_poly (map_polyC _)) !map_poly_comp div_annihilantP ?pFto0.
+Qed.
+
+Lemma root_annihilant x p (pEx := (p ^ pFtoE).[x%:P]) :
+ pEx != 0 -> algebraicOver FtoE x ->
+ exists2 r : {poly F}, r != 0 & forall y, root pEx y -> root (r ^ FtoE) y.
+Proof.
+move=> nz_px [q nz_q qx0].
+have [/size1_polyC Dp | p_gt1] := leqP (size p) 1.
+ by rewrite {}/pEx Dp map_polyC hornerC map_poly_eq0 in nz_px *; exists p`_0.
+have nz_p: p != 0 by rewrite -size_poly_gt0 ltnW.
+elim: {q}_.+1 {-2}q (ltnSn (size q)) => // m IHm q le_qm in nz_q qx0 *.
+have nz_q1: q^:P != 0 by rewrite map_poly_eq0.
+have sz_q1: size q^:P = size q by rewrite size_map_polyC.
+have q1_gt1: size q^:P > 1.
+ by rewrite sz_q1 -(size_map_poly FtoE) (root_size_gt1 _ qx0) ?map_poly_eq0.
+have [uv _ Dr] := resultant_in_ideal p_gt1 q1_gt1; set r := resultant p _ in Dr.
+have /eqP q1x0: (q^:P ^ pFtoE).[x%:P] == 0.
+ by rewrite -swapXY_polyC -swapXY_map horner_swapXY !map_polyC polyC_eq0.
+have [|r_nz] := boolP (r == 0); last first.
+ exists r => // y pxy0; rewrite -[r ^ _](hornerC _ x%:P) -map_polyC Dr.
+ by rewrite rmorphD !rmorphM !hornerE q1x0 mulr0 addr0 rootM pxy0 orbT.
+rewrite resultant_eq0 => /gtn_eqF/Bezout_coprimepPn[]// [q2 p1] /=.
+rewrite size_poly_gt0 sz_q1 => /andP[/andP[nz_q2 ltq2] _] Dq.
+pose n := (size (lead_coef q2)).-1; pose q3 := map_poly (coefp n) q2.
+have nz_q3: q3 != 0 by rewrite map_poly_eq0_id0 ?lead_coef_eq0.
+apply: (IHm q3); rewrite ?(leq_ltn_trans (size_poly _ _)) ?(leq_trans ltq2) //.
+have /polyP/(_ n)/eqP: (q2 ^ pFtoE).[x%:P] = 0.
+apply: (mulIf nz_px); rewrite -hornerM -rmorphM Dq rmorphM hornerM /= q1x0.
+ by rewrite mul0r mulr0.
+rewrite coef0; congr (_ == 0); rewrite !horner_coef coef_sum.
+rewrite size_map_poly !size_map_poly_id0 ?map_poly_eq0 ?lead_coef_eq0 //.
+by apply: eq_bigr => i _; rewrite -rmorphX coefMC !coef_map.
+Qed.
+
+Lemma algebraic_root_polyXY x y :
+ (let pEx p := (p ^ map_poly FtoE).[x%:P] in
+ exists2 p, pEx p != 0 & root (pEx p) y) ->
+ algebraicOver FtoE x -> algebraicOver FtoE y.
+Proof. by case=> p nz_px pxy0 /(root_annihilant nz_px)[r]; exists r; auto. Qed.
+
+End PolyXY_Field.