From 06ea22a3f38aa23ab05e9801ff739ccd0f6c3490 Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Fri, 3 Feb 2023 16:13:38 +0100 Subject: [PATCH 01/14] Abel-Galois for any characteristic --- theories/abel.v | 413 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 366 insertions(+), 47 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index b7525f7..183c85b 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -55,22 +55,31 @@ Proof. by case: splitP=> j eq_j; constructor; apply/val_inj. Qed. Section RadicalExtension. Variables (F0 : fieldType) (L : splittingFieldType F0). -Hypothesis (charL : has_char0 L). Section Defs. Implicit Types (U V : {vspace L}). -Definition radical U x n := [&& (n > 0)%N & x ^+ n \in U]. -Definition pradical U x p := [&& prime p & x ^+ p \in U]. +Definition radical U x n := [|| + [&& n%:R != 0 :> F0 & x ^+ n \in U] | + [&& n \in [char L] & x ^+ n - x \in U]]. +Definition pradical U x p := [|| + [&& prime p, p%:R != 0 :> F0 & x ^+ p \in U] | + [&& p \in [char L] & x ^+ p - x \in U]]. -Lemma radicalP U x n : reflect [/\ (n > 0)%N & x ^+ n \in U] - [&& (n > 0)%N & x ^+ n \in U]. -Proof. exact/andP. Qed. +Lemma radicalP U x n : reflect [\/ + [/\ n%:R != 0 :> F0 & x ^+ n \in U] | + [/\ n \in [char L] & x ^+ n - x \in U]] + (radical U x n). +Proof. by apply(iffP orP); (case=>/andP h; [ left | right ]). Qed. -Lemma pradicalP U x p : reflect [/\ prime p & x ^+ p \in U] - [&& prime p & x ^+ p \in U]. -Proof. exact/andP. Qed. +Lemma pradicalP U x p : reflect [\/ + [/\ prime p, p%:R != 0 :> F0 & x ^+ p \in U] | + [/\ p \in [char L] & x ^+ p - x \in U]] + (pradical U x p). +Proof. +by apply(iffP orP); (case=> h; [ left; apply/and3P | right; apply/andP ]). +Qed. Implicit Types r : {vspace L} -> L -> nat -> bool. @@ -115,6 +124,30 @@ Section Properties. Implicit Types r : {vspace L} -> L -> nat -> bool. Implicit Types (U V : {subfield L}). +(* TODO: rename and move to the proper place *) +Lemma primitive_unity_root_char (w : L) (n : nat) : + n.-primitive_root w -> n%:R != (0 : F0). +Proof. +case: n => // n /andP[_ /forallP w1]. +rewrite natf_neq0; apply/andP; split=>//. +rewrite -(negbK (all _ _)) -has_predC. +apply/negP => /hasP[p]; rewrite mem_primes => /and3P[p_prime _ /dvdnP][]. +case=>// m nE. +rewrite /negn inE negbK => /andP [_ p0]. +have: p \in [char L] by rewrite (char_lalg L) inE; apply/andP; split=>//. +move=> {p0} p_char. +move:(w1 (Ordinal (ltnSn n))) => /= /eqP. +rewrite eqxx /root_of_unity /root 3!hornerE hornerXn. +rewrite nE exprM -(@expr1n _ p). +rewrite -(Frobenius_autE p_char (w ^+ m.+1)) -(Frobenius_autE p_char 1) subr_eq0=>/eqP/fmorph_inj wm1. +have mn: (m.+1 < n.+1)%N. + by rewrite nE; apply ltn_Pmulr=>//; apply prime_gt1. + have: ((Ordinal (ltn_trans (ltnSn m) mn)).+1).-unity_root w. + by rewrite /root_of_unity /root/= 3!hornerE hornerXn wm1 subrr. +move:(w1 (Ordinal (ltn_trans (ltnSn m) mn))) => /eqP -> /= /eqP mnE. +by move:mn; rewrite mnE ltnn. +Qed. + Lemma rext_refl r (E : {subfield L}) : r.-ext E E. Proof. by exists trivExt; rewrite ?Fadjoin_nil//=; apply/towerP => -[]. Qed. @@ -149,46 +182,69 @@ Lemma solvable_by_radicals_radicalext (E F : {subfield L}) : radical.-ext E F -> solvable_by radical E F. Proof. by move=> extEF; exists F. Qed. -Lemma radical_Fadjoin (n : nat) (x : L) (E : {subfield L}) : - (0 < n)%N -> x ^+ n \in E -> radical E x n. -Proof. by move=> ? ?; apply/radicalP. Qed. +Lemma radical_Fadjoin1 (n : nat) (x : L) (E : {subfield L}) : + n%:R != 0 :> F0 -> x ^+ n \in E -> radical E x n. +Proof. by move=> ? ?; apply/radicalP; left. Qed. + +Lemma radical_Fadjoin2 (n : nat) (x : L) (E : {subfield L}) : + n \in [char L] -> x ^+ n - x \in E -> radical E x n. +Proof. by move=> ? ?; apply/radicalP; right. Qed. -Lemma pradical_Fadjoin (n : nat) (x : L) (E : {subfield L}) : - prime n -> x ^+ n \in E -> pradical E x n. -Proof. by move=> ? ?; apply/pradicalP. Qed. +Lemma pradical_Fadjoin1 (n : nat) (x : L) (E : {subfield L}) : + prime n -> n%:R != 0 :> F0 -> x ^+ n \in E -> pradical E x n. +Proof. by move=> ? ? ?; apply/pradicalP; left. Qed. -Lemma radical_ext_Fadjoin (n : nat) (x : L) (E : {subfield L}) : - (0 < n)%N -> x ^+ n \in E -> radical.-ext E <>%VS. -Proof. by move=> n_gt0 xnE; apply/rext_r/(radical_Fadjoin n_gt0 xnE). Qed. +Lemma pradical_Fadjoin2 (n : nat) (x : L) (E : {subfield L}) : + n \in [char L] -> x ^+ n - x \in E -> pradical E x n. +Proof. by move=> ? ?; apply/pradicalP; right. Qed. + +Lemma radical_ext_Fadjoin1 (n : nat) (x : L) (E : {subfield L}) : + n%:R != 0 :> F0 -> x ^+ n \in E -> radical.-ext E <>%VS. +Proof. move=> n_gt0 xnE; apply/rext_r/(radical_Fadjoin1 n_gt0 xnE). Qed. + +Lemma radical_ext_Fadjoin2 (n : nat) (x : L) (E : {subfield L}) : + n \in [char L] -> x ^+ n - x \in E-> radical.-ext E <>%VS. +Proof. by move=> nL xnE; apply/rext_r/(radical_Fadjoin2 nL xnE). Qed. + +Lemma pradical_ext_Fadjoin1 (n : nat) (x : L) (E : {subfield L}) : + prime n -> n%:R != 0 :> F0 -> x ^+ n \in E -> pradical.-ext E <>%VS. +Proof. +by move=> n_prime n0 xnE; apply/rext_r/(pradical_Fadjoin1 n_prime n0 xnE). +Qed. -Lemma pradical_ext_Fadjoin (p : nat) (x : L) (E : {subfield L}) : - prime p -> x ^+ p \in E -> pradical.-ext E <>%AS. -Proof. by move=> p_prime Exn; apply/rext_r/(pradical_Fadjoin p_prime Exn). Qed. +Lemma pradical_ext_Fadjoin2 (n : nat) (x : L) (E : {subfield L}) : + n \in [char L] -> x ^+ n - x \in E-> pradical.-ext E <>%VS. +Proof. by move=> nL xnE; apply/rext_r/(pradical_Fadjoin2 nL xnE). Qed. Lemma pradicalext_radical n (x : L) (E : {subfield L}) : radical E x n -> pradical.-ext E << E; x >>%VS. Proof. -move=> /radicalP[n_gt0 xnE]; have [k] := ubnP n. +move=> /radicalP; case=>[[n_gt0] | [nL]] xnE; last first. + by apply (pradical_ext_Fadjoin2 nL xnE). +have [k] := ubnP n. elim: k => // k IHk in n x E n_gt0 xnE *; rewrite ltnS => lenk. have [prime_n|primeN_n] := boolP (prime n). - by apply: (@pradical_ext_Fadjoin n). + by apply: (@pradical_ext_Fadjoin1 n). case/boolP: (2 <= n)%N; last first. case: n {lenk primeN_n} => [|[]]// in xnE n_gt0 * => _. + by move:n_gt0; rewrite eqxx. suff ->: <>%VS = E by apply: rext_refl. by rewrite (Fadjoin_idP _). move: primeN_n => /primePn[|[d /andP[d_gt1 d_ltn] dvd_dn n_gt1]]. by case: ltngtP. have [m n_eq_md]: {k : nat | n = (k * d)%N}. by exists (n %/ d)%N; rewrite [LHS](divn_eq _ d) (eqP dvd_dn) addn0. -have m_gt0 : (m > 0)%N. - by move: n_gt0; rewrite !lt0n n_eq_md; apply: contra_neq => ->. +have m_gt0 : m%:R != 0 :> F0. + by move: n_gt0; rewrite n_eq_md natrM; apply: contra_neq => ->; rewrite mul0r. apply: (@rext_trans _ <>) => //. apply: (@IHk m (x ^+ d)) => //. by rewrite -exprM mulnC -n_eq_md//. - by rewrite (leq_trans _ lenk)// n_eq_md ltn_Pmulr. + rewrite (leq_trans _ lenk)// n_eq_md ltn_Pmulr// lt0n. + by move: m_gt0; apply: contra_neq => ->. suff -> : <>%AS = <<<>; x>>%AS. apply: (IHk d) => //. - - by rewrite (leq_trans _ d_gt1)//. + - by move: n_gt0; rewrite n_eq_md natrM; apply: contra_neq => ->; + rewrite mulr0. - by rewrite memv_adjoin. - by rewrite (leq_trans _ lenk). apply/val_inj; rewrite /= adjoinC [<<_; x ^+ d>>%VS](Fadjoin_idP _)//. @@ -202,8 +258,9 @@ Proof. by move=> sub_r /forallP /= h; apply/forallP=> /= i; apply/sub_r/h. Qed. Lemma radical_pradical U x p : pradical U x p -> radical U x p. Proof. -case/pradicalP=> prime_p xpU; apply/radicalP; split=> //. -by case/primeP: prime_p => /ltnW. +move=>/pradicalP x_rad; apply/radicalP. +case:x_rad=>x_rad; last by right. +by case:x_rad=> prime_p xpU; left; split. Qed. Lemma radicalext_pradicalext (E F : {subfield L}) : @@ -239,8 +296,8 @@ Proof. by case=> [R /pradicalext_radicalext ERe FR]; exists R. Qed. Lemma radicalext_Fadjoin_cyclotomic (E : {subfield L}) (w : L) (n : nat) : n.-primitive_root w -> radical.-ext E <>%AS. Proof. -move=> wprim; apply: (@radical_ext_Fadjoin n w E). - exact: prim_order_gt0 wprim. +move=> wprim; apply: (@radical_ext_Fadjoin1 n w E). + exact: (primitive_unity_root_char wprim). by rewrite (prim_expr_order wprim) mem1v. Qed. @@ -282,6 +339,7 @@ Section Abel. Section Part1. Variables (F0 : fieldType) (L : splittingFieldType F0). Implicit Types (E F K : {subfield L}) (w : L) (n : nat). +Let radical := @radical F0 L. Lemma cyclic_radical_ext w E F (n := \dim_E F) : n.-primitive_root w -> w \in E -> galois E F -> @@ -289,7 +347,9 @@ Lemma cyclic_radical_ext w E F (n := \dim_E F) : Proof. set G := (X in cyclic X) => w_root wE galois_EF /cyclicP[g GE]. have EF := galois_subW galois_EF. -have n_gt0 : (n > 0)%N by rewrite /n -dim_aspaceOver ?adim_gt0. +move: (primitive_unity_root_char w_root) => n_ne0. +have n_gt0: (0 < n)%N. + by rewrite lt0n; move: n_ne0; apply: contra_neq => ->. have Gg : generator G g by rewrite GE generator_cycle. have gG : g \in G by rewrite GE cycle_id. have HT90g := Hilbert's_theorem_90 Gg (subvP EF _ wE). @@ -297,7 +357,7 @@ have /eqP/HT90g[x [xF xN0]] : galNorm E F w = 1. rewrite /galNorm; under eq_bigr => g' g'G. rewrite (fixed_gal EF g'G)//. over. by rewrite prodr_const -galois_dim// (prim_expr_order w_root). have gxN0 : g x != 0 by rewrite fmorph_eq0. -have wN0 : w != 0 by rewrite (primitive_root_eq0 w_root) -lt0n. +have wN0 : w != 0. rewrite (primitive_root_eq0 w_root) -lt0n //. move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. have gXx i : (g ^+ i)%g x = w ^- i * x. elim: i => [|i IHi]. @@ -306,7 +366,7 @@ have gXx i : (g ^+ i)%g x = w ^- i * x. by rewrite (fixed_gal EF gG) ?rpredV ?rpredX. have ExF : (<> <= F)%VS by exact/FadjoinP. suff -> : F = <>%AS. - apply: radical_ext_Fadjoin n_gt0 _. + apply: radical_ext_Fadjoin1 n_ne0 _. rewrite -(galois_fixedField galois_EF) -/G GE. apply/fixedFieldP; first by rewrite rpredX. move=> _ /cycleP[i ->]; rewrite rmorphX/= gXx exprMn exprVn exprAC. @@ -333,7 +393,9 @@ Lemma solvableWradical_ext w E F (n := \dim_E F) : Proof. move=> + + galEF; have [k] := ubnP n; elim: k => // k IHk in w E F n galEF *. rewrite ltnS => le_nk; have subEF : (E <= F)%VS by case/andP: galEF. -have n_gt0 : (0 < n)%N by rewrite ltn_divRL ?field_dimS// mul0n adim_gt0. +move=> /[dup]/primitive_unity_root_char n_ne0. +have n_gt0: (0 < n)%N. + by rewrite lt0n; move: n_ne0; apply: contra_neq => ->. move=> wn Ew solEF; have [n_le1|n_gt1] := leqP n 1%N. have /eqP : n = 1%N by case: {+}n n_gt0 n_le1 => [|[]]. rewrite -eqn_mul ?adim_gt0 ?field_dimS// mul1n eq_sym dimv_leqif_eq//. @@ -547,13 +609,266 @@ rewrite (@pradical_solvable p _ _ w)// ?memv_adjoin//. by rewrite (isog_sol (normalField_isog _ _ _)) ?galois_normalW ?subv_adjoin. Qed. +Section ArtinSchreier. +Variable (p : nat) (F0 : fieldType) (L : splittingFieldType F0). +Variable (E : {subfield L}) (x : L). +Hypothesis (pchar : p \in [char L]) (xpE : x ^+ p - x \in E). + +Let pprim : prime p. +Proof. by move: pchar=>/andP[]. Qed. + +Let p0 : p%:R == 0 :> L. +Proof. by move: pchar=>/andP[_]. Qed. + +Let p1 : (1 < p)%N. +Proof. by apply prime_gt1. Qed. + +Lemma ArtinScheier_factorize : + 'X^p - 'X - (x ^+ p - x)%:P = + \prod_(z <- [seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]) + ('X - z%:P). +Proof. +case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. +apply/eqP; rewrite -eqp_monic; first last. +- by apply monic_prod_XsubC. +- apply/monicP; rewrite -addrA -opprD lead_coefDl ?lead_coefXn//. + by rewrite size_opp size_XaddC size_polyXn ltnS. +- rewrite eqp_sym -dvdp_size_eqp. + rewrite big_map size_prod; last first. + move=> [i]/= _ _; apply/negP => /eqP + /(congr1 (fun p : {poly L} => size p)). + by rewrite size_XsubC size_polyC eqxx. + have ->: \big[addn/0%N]_(i < n.+1) size ('X - (x + (val i)%:R)%:P)%R = + \big[addn/0%N]_(i < n.+1) 2%N. + by apply eq_bigr=> i _; rewrite size_XsubC. + rewrite big_const_ord iter_addn_0. + rewrite -add1n mul2n -addnn addnA card_ord -addnBA// subnn addn0 add1n. + rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. + by move: pchar => /andP [ /prime_gt1 ]. + apply uniq_roots_dvdp. + apply/allP => + /mapP [i _ ->] => _. + rewrite/root 6!hornerE hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). + rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). + rewrite opprD opprB addrACA -addrA 2![x+_]addrA subrr add0r. + by rewrite addrAC addrCA subrr addr0 addrC subrr. + rewrite uniq_rootsE; apply/(uniqP 0) => i j. + rewrite 2!inE size_map => ilt jlt. + rewrite (nth_map ord0)// (nth_map ord0)// => /addrI/esym/eqP. + set ip := nth ord0 (index_enum (ordinal_finType n.+1)) i. + set jp := nth ord0 (index_enum (ordinal_finType n.+1)) j. + move=>ijE. + suff: jp = ip. + rewrite/ip/jp => /esym ijE0. + by move: (index_enum_uniq (ordinal_finType n.+1))=>/uniqP + /(_ i j ilt jlt ijE0). + move:ijE. + wlog ij : {i} {j} {ilt} {jlt} ip jp / (val ip <= val jp)%N. + move=> h. + move: (Order.TotalTheory.le_total (val ip) (val jp)) => /orP; case => ij. + by apply h. + by rewrite eq_sym=> ijE; apply /esym/h. + rewrite -subr_eq0 -natrB// -(dvdn_charf nchar). + case /posnP: (val jp - val ip)%N. + move=>/eqP; rewrite subn_eq0 => ji _; apply/val_inj/eqP. + by rewrite Order.POrderTheory.eq_le; apply/andP; split. + move=>ij0 /(dvdn_leq ij0); rewrite ltn_subRL -addnS. + move=>/(leq_trans (leq_addl _ _)). + have: (val jp < n.+1)%N by destruct jp. + by rewrite ltnS => jle; move => /(leq_ltn_trans jle); rewrite ltnn. +Qed. + +Lemma ArtinSchreier_splitting : + splittingFieldFor E ('X^p - 'X - (x ^+ p - x)%:P) <>%AS. +Proof. +exists ([seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]). + by rewrite ArtinScheier_factorize big_map eqpxx. +apply/eqP; rewrite eqEsubv; apply/andP; split. + apply/Fadjoin_seqP; split; first by apply subv_adjoin. + move=>+ /mapP [i _ ->] => _. + apply (@rpredD _ _ (memv_addrPred <>%AS)); first by apply memv_adjoin. + by apply rpred_nat. +apply/FadjoinP; split; first by apply subv_adjoin_seq. +case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. +apply/seqv_sub_adjoin/mapP; exists ord0; first by apply mem_index_enum. +by rewrite addr0. +Qed. + +Lemma ArtinSchreier_polyOver : + 'X^p - 'X - (x ^+ p - x)%:P \is a polyOver E. +Proof. by rewrite rpredB ?polyOverC// rpredB ?rpredX// polyOverX. Qed. + +Lemma ArtinSchreier_galois : + galois E <>. +Proof. +apply/splitting_galoisField; exists ('X^p - 'X - (x ^+ p - x)%:P); split. +- exact ArtinSchreier_polyOver. +- rewrite/separable_poly derivB derivC subr0 derivB derivXn derivX -scaler_nat. + move: pchar; rewrite inE => /andP[_ /eqP ->]. + rewrite scale0r add0r. + apply/Bezout_eq1_coprimepP; exists (0, (-1)) => /=. + by rewrite mul0r add0r mulN1r opprK. +- by apply ArtinSchreier_splitting. +Qed. + + +(*** TODO: move to its proper place *********************) + +Lemma big_split_cond (R : Type) (idx : R) (op : Monoid.com_law idx) (I : Type) + (r : seq I) (P Q : pred I) (F G : I -> R) : + \big[op/idx]_(i <- r | P i) (if Q i then F i else G i) = + op (\big[op/idx]_(i <- r | P i && Q i) F i) + (\big[op/idx]_(i <- r | P i && ~~ Q i) G i). +Proof. +elim: r => [| a r IHr]; first by rewrite 3!big_nil Monoid.mulm1. +rewrite 3!big_cons. +case: (P a) => //=. +case: (Q a) => /=; first by rewrite IHr Monoid.mulmA. +by rewrite IHr Monoid.mulmCA. +Qed. + +Lemma bigA_distr_bigA2 (R : Type) (zero one : R) (times : Monoid.mul_law zero) + (plus : Monoid.add_law zero times) (I : finType) (F G : I -> R) : + \big[times/one]_i plus (F i) (G i) = + \big[plus/zero]_(J in {set I}) \big[times/one]_i (if i \in J then F i else G i). +Proof. +transitivity (\big[times/one]_i \big[plus/zero]_(b : bool) if b then F i else G i); first by apply eq_bigr => i _; rewrite big_bool. +rewrite bigA_distr_bigA. +set f := fun J : {set I} => val J. +transitivity (\big[plus/zero]_(f0 in (imset f (mem setT))) \big[times/one]_i (if f0 i then F i else G i)). + suff <-: setT = imset f (mem setT) by apply congr_big=>// i; rewrite in_setT. + apply/esym/eqP; rewrite -subTset; apply/subsetP => b _. + by apply/imsetP; exists (FinSet b). +rewrite big_imset; last by case => g; case => h _ _; rewrite /f/= => ->. +apply congr_big=>//; case => g; first by rewrite in_setT. +move=>_; apply eq_bigr => i _; congr (if _ then _ else _). +by rewrite SetDef.pred_of_setE. +Qed. + +Lemma coefn_prod_XsubC {R : comRingType} (ps : seq R) (n : nat) : + (n <= size ps)%N -> + (\prod_(p <- ps) ('X - p%:P))`_n = + (-1) ^+ (size ps - n)%N * + \sum_(I in {set 'I_(size ps)} | #|I| == (size ps - n)%N) + \prod_(i in I) ps`_i. +Proof. +move=> nle. +have psE: ps = tval (Tuple (eqxx (size ps))) by []. +transitivity (\prod_(p <- ps) ((- p)%:P + 'X))`_n. + by congr ((polyseq _)`_n); apply eq_bigr => i _; rewrite addrC polyCN. +rewrite {1}psE -(map_tnth_enum (Tuple _)) big_map enumT bigA_distr_bigA2 /=. +rewrite coef_sum. +transitivity (\sum_(I in {set 'I_(size ps)}) if #|I| == (size ps - n)%N then \prod_(i < size ps | i \in I) - (tnth (Tuple (eqxx (size ps))) i) else 0). + apply eq_bigr => I _. + rewrite big_split_cond/= big_const iter_mulr_1. + rewrite -(rmorph_prod (@polyC_rmorphism R))/= coefCM coefXn. + rewrite -[#|I| == _](eqn_add2l n) addnBA// [(_ + (size ps))%N]addnC -addnBA// subnn addn0 [(n + _)%N]addnC. + rewrite -[in X in _ = if _ == X then _ else _](card_ord (size ps)) -(cardC I) eqn_add2l. + by case: (n == #|[predC I]|); rewrite ?mulr1 ?mulr0. +rewrite -big_mkcond mulr_sumr/=; apply eq_bigr => I /eqP cardI. +rewrite prodrN cardI; congr GRing.mul; apply eq_bigr => i _. +by rewrite (tnth_nth (GRing.zero R)) -psE. +Qed. + +Lemma coefPn_prod_XsubC {R : comRingType} (ps : seq R) : + size ps != 0%N -> + (\prod_(p <- ps) ('X - p%:P))`_((size ps).-1) = + - \sum_(p <- ps) p. +Proof. +rewrite coefn_prod_XsubC ?leq_pred// => ps0. +have ->: (size ps - (size ps).-1 = 1)%N. + by move: ps0; case: (size ps)=>// n _; apply subSnn. +rewrite expr1 mulN1r; congr GRing.opp. +set f : 'I_(size ps) -> {set 'I_(size ps)} := fun a => [set a]. +transitivity (\sum_(I in imset f (mem setT)) \prod_(i in I) ps`_i). + apply congr_big=>// I /=. + apply/cards1P/imsetP. + by move=>[a ->]; exists a. + by move=>[a _ ->]; exists a. +rewrite big_imset/=; last by move=> i j _ _; rewrite/f => ij; apply/set1P; rewrite -ij set11. +have psE: ps = tval (Tuple (eqxx (size ps))) by []. +rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. +apply congr_big => // i; first by rewrite in_setT. +by move=>_; rewrite big_set1 (tnth_nth (GRing.zero R)) -psE. +Qed. + +Lemma coefP0_prod_XsubC {R : comRingType} (ps : seq R) : + (\prod_(p <- ps) ('X - p%:P))`_0 = + (-1) ^+ (size ps) * \prod_(p <- ps) p. +Proof. +rewrite coefn_prod_XsubC// subn0; congr GRing.mul. +transitivity (\sum_(I in [set setT : {set 'I_(size ps)}]) \prod_(i in I) ps`_i). + apply congr_big=>// i/=. + apply/idP/set1P. + by move=>/eqP cardE; apply/eqP; rewrite eqEcard subsetT cardsT card_ord cardE leqnn. + by move=>->; rewrite cardsT card_ord. +rewrite big_set1. +have psE: ps = tval (Tuple (eqxx (size ps))) by []. +rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. +apply congr_big => // i; first by rewrite in_setT. +by move=>_; rewrite (tnth_nth (GRing.zero R)) -psE. +Qed. + +(********************************) + +Lemma minPoly_ArtinSchreier : (x \notin E) -> + minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. +Proof. +move=> xE. +have /(minPoly_dvdp ArtinSchreier_polyOver): root ('X^p - 'X - (x ^+ p - x)%:P) x. + rewrite ArtinScheier_factorize root_prod_XsubC. + case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. + apply/mapP; exists ord0; first by rewrite mem_index_enum. + by rewrite addr0. +rewrite ArtinScheier_factorize big_map. +move=> /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last first. + by rewrite monic_prod// => i _; rewrite monic_XsubC. +have [{}m sm ->] := resize_mask m (index_enum (ordinal_finType p)). +set s := mask _ _ => /eqP mEx. +have [|smp_gt0] := posnP (size s). + case: s mEx => // /(congr1 (horner^~x))/esym/eqP. + by rewrite minPolyxx big_nil hornerC oner_eq0. +suff leq_pm : (p <= size s)%N. + move: mEx; suff /eqP->: s == index_enum (ordinal_finType p) by []. + rewrite -(geq_leqif (size_subseq_leqif _)) ?mask_subseq//. + by rewrite/index_enum; case: index_enum_key=>/=; rewrite -enumT size_enum_ord. +have /polyOverP/(_ (size s).-1%N) := minPolyOver E x; rewrite {}mEx. +have ->: \prod_(i <- s) ('X - (x + (val i)%:R)%:P) = \prod_(i <- [seq x + (val i)%:R | i <- s]) ('X - i%:P) by rewrite big_map. +rewrite -(size_map (fun i => x + (val i)%:R)) coefPn_prod_XsubC size_map -?lt0n// big_map. +rewrite memvN big_split/= big_const_seq count_predT iter_addr_0 => DE. +have sE: \sum_(i <- s) i%:R \in E by apply rpred_sum => i _; apply rpred_nat. +move:(rpredB DE sE) => {DE} {sE}. +rewrite -addrA subrr addr0 => xsE. +apply/negP => sltp. +have /coprimeP: coprime (size s) p. + by rewrite coprime_sym (prime_coprime _ pprim); apply/negP => /(dvdn_leq smp_gt0). +move=> /(_ smp_gt0) [[u v]]/= uv1. +have /ltnW vltu: (v * p < u * size s)%N by rewrite ltnNge -subn_eq0 uv1. +move:uv1 => /eqP; rewrite -(eqn_add2l (v * p)) addnBA// addnC -addnBA// subnn addn0 => /eqP sE. +move: xsE => /(rpredMn u); rewrite -mulrnA mulnC sE addn1 mulrS mulrnA -mulr_natr. +move: p0 => /eqP ->; rewrite mulr0 addr0. +by move: xE => /negP. +Qed. + +Lemma ArtinSchreier_solvable_ext : + x \notin E -> solvable_ext E <>. +Proof. +move=> xE. +apply/solvable_extP; exists <>%AS; rewrite subvv/=. +rewrite ArtinSchreier_galois/=. +apply/abelian_sol/cyclic_abelian/prime_cyclic. +rewrite -(galois_dim ArtinSchreier_galois) -adjoin_degreeE. +rewrite (pred_Sn (adjoin_degree E x)) -size_minPoly minPoly_ArtinSchreier//. +by rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. +Qed. + +End ArtinSchreier. + Lemma radical_ext_solvable_ext (F0 : fieldType) (L : splittingFieldType F0) - (E F : {subfield L}) : has_char0 L -> (E <= F)%VS -> + (E F : {subfield L}) : (E <= F)%VS -> solvable_by radical E F -> solvable_ext E F. Proof. -move=> charL EF. +move=> EF. move=> [_ /pradicalext_radicalext[[/= n e pw] /towerP epwP <- FK]]. -have charF0 : [char F0] =i pred0 by move=> i; rewrite -charL char_lalg. pose k := n; suff {FK} : solvable_ext E <>. by rewrite take_oversize ?size_tuple//; apply: sub_solvable_ext. elim: k => /= [|k IHsol]; first by rewrite take0 Fadjoin_nil. @@ -563,9 +878,11 @@ rewrite (take_nth 0) ?size_tuple// adjoin_rcons. apply: solvable_ext_trans IHsol _. by rewrite /= subv_adjoin_seq subv_adjoin. have := epwP (Ordinal kn); rewrite (tnth_nth 0) (tnth_nth 0%N)/=. -move=> /pradicalP[pwk_prime epwEk]. -apply: (pradical_solvable_ext pwk_prime) => //. -by have /charf0P-> := charF0; rewrite -lt0n prime_gt0. +move=> /pradicalP; case=>[[pwk_prime] | [pwkL]] epwEk. + by apply: (pradical_solvable_ext pwk_prime). +case /boolP: (e`_k \in <>%VS). + move=> /Fadjoin_idP ->; exact: solvable_ext_refl. +by apply (ArtinSchreier_solvable_ext pwkL). Qed. (******************************************************************************) @@ -576,11 +893,11 @@ Qed. (** Ok **) Lemma AbelGalois (F0 : fieldType) (L : splittingFieldType F0) (w : L) - (E F : {subfield L}) : (E <= F)%VS -> has_char0 L -> + (E F : {subfield L}) : (E <= F)%VS -> (\dim_E (normalClosure E F)).-primitive_root w -> solvable_by radical E F <-> solvable_ext E F. Proof. -move=> EF charL wprim; split; first exact: radical_ext_solvable_ext. +move=> EF wprim; split; first exact: radical_ext_solvable_ext. exact: (ext_solvable_by_radical wprim). Qed. @@ -707,7 +1024,6 @@ split => sol_p; last first. apply: classic_bind sol_p => -[L [rs [prs sol_p]]]; apply/classicW. exists L, rs; split => //; rewrite -galois_solvable. apply: radical_ext_solvable_ext; rewrite ?sub1v// => v. - by rewrite char_lalg charF0. have charL : has_char0 L by move=> n; rewrite char_lalg charF0. rewrite char0_galois// ?sub1v//. apply/splitting_normalField; rewrite ?sub1v//. @@ -1504,7 +1820,8 @@ have Cchar := Cchar => p_neq0; split. - by move=> _ [f1 <-] _ [f2 <-]; exists (BinOp op f1 f2). have /Fadjoin_polyP[q qk ->] := subvsP s. have /towerP/(_ ord0) := epw; rewrite !tnth0/= Fadjoin_nil. - move=> /radicalP[]; case: i => // i in epw * => _ uik. + move=> /radicalP[][]; last by rewrite char_ext. + case: i => // i in epw * => _ uik. pose v := i.+1.-root (iota (u ^+ i.+1)). have : ('X ^+ i.+1 - (v ^+ i.+1)%:P).[iota u] == 0. by rewrite !hornerE ?hornerXn rootCK// rmorphX subrr. @@ -1603,7 +1920,8 @@ elim: f => //= [x|c|u f1 IHf1|b f1 IHf1 f2 IHf2] in k {r fr} als1 als1E *. exact: rext_refl. + rewrite fmorph_eq1 => /eqP->; rewrite (Fadjoin_idP _) ?rpred1//. exact: rext_refl. - + apply/(@rext_r _ _ _ n.+1)/radicalP; split => //. + + apply/(@rext_r _ _ _ n.+1)/radicalP; left; split. + by apply/negP; rewrite pnatr_eq0. rewrite prim_expr_order ?rpred1//. by rewrite -(fmorph_primitive_root iota) yomega prim1rootP. - case: als1 als1E => //= a l [IHl IHlu]. @@ -1619,7 +1937,8 @@ elim: f => //= [x|c|u f1 IHf1|b f1 IHf1 f2 IHf2] in k {r fr} als1 als1E *. by have /fmorph_inj-> := IHl; rewrite rpredV. + rewrite (Fadjoin_idP _); first exact: rext_refl. by have := IHl; rewrite -rmorphX => /fmorph_inj->; rewrite rpredX. - apply/(@rext_r _ _ _ n.+1)/radicalP; split => //. + apply/(@rext_r _ _ _ n.+1)/radicalP; left; split. + by apply/negP; rewrite pnatr_eq0. have /(congr1 ((@GRing.exp _)^~ n.+1)) := IHl. by rewrite rootCK// -rmorphX => /fmorph_inj->. - case: als1 als1E => //= a l [IHl IHlu]. From 4ab6ab8dfe719d21567242f668952ec3fc5d223d Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Fri, 3 Feb 2023 18:52:33 +0100 Subject: [PATCH 02/14] fix hornerE changing behaviour between mc versions --- theories/abel.v | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 183c85b..05ad81c 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -137,13 +137,15 @@ rewrite /negn inE negbK => /andP [_ p0]. have: p \in [char L] by rewrite (char_lalg L) inE; apply/andP; split=>//. move=> {p0} p_char. move:(w1 (Ordinal (ltnSn n))) => /= /eqP. -rewrite eqxx /root_of_unity /root 3!hornerE hornerXn. +rewrite eqxx /root_of_unity /root !hornerE ?hornerXn. + (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) rewrite nE exprM -(@expr1n _ p). rewrite -(Frobenius_autE p_char (w ^+ m.+1)) -(Frobenius_autE p_char 1) subr_eq0=>/eqP/fmorph_inj wm1. have mn: (m.+1 < n.+1)%N. by rewrite nE; apply ltn_Pmulr=>//; apply prime_gt1. have: ((Ordinal (ltn_trans (ltnSn m) mn)).+1).-unity_root w. - by rewrite /root_of_unity /root/= 3!hornerE hornerXn wm1 subrr. + by rewrite /root_of_unity /root/= !hornerE ?hornerXn wm1 subrr. + (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) move:(w1 (Ordinal (ltn_trans (ltnSn m) mn))) => /eqP -> /= /eqP mnE. by move:mn; rewrite mnE ltnn. Qed. @@ -647,7 +649,8 @@ apply/eqP; rewrite -eqp_monic; first last. by move: pchar => /andP [ /prime_gt1 ]. apply uniq_roots_dvdp. apply/allP => + /mapP [i _ ->] => _. - rewrite/root 6!hornerE hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). + rewrite/root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). + (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). rewrite opprD opprB addrACA -addrA 2![x+_]addrA subrr add0r. by rewrite addrAC addrCA subrr addr0 addrC subrr. From 6664b1107a0913e7f23908026cec03919f6a0c0a Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Fri, 3 Feb 2023 22:07:03 +0100 Subject: [PATCH 03/14] update on suggestions --- theories/abel.v | 108 ++--------------------------------- theories/xmathcomp/various.v | 101 ++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 104 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 05ad81c..9c4673c 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -125,7 +125,7 @@ Implicit Types r : {vspace L} -> L -> nat -> bool. Implicit Types (U V : {subfield L}). (* TODO: rename and move to the proper place *) -Lemma primitive_unity_root_char (w : L) (n : nat) : +Lemma prim_root_natf_neq0 (w : L) (n : nat) : n.-primitive_root w -> n%:R != (0 : F0). Proof. case: n => // n /andP[_ /forallP w1]. @@ -299,7 +299,7 @@ Lemma radicalext_Fadjoin_cyclotomic (E : {subfield L}) (w : L) (n : nat) : n.-primitive_root w -> radical.-ext E <>%AS. Proof. move=> wprim; apply: (@radical_ext_Fadjoin1 n w E). - exact: (primitive_unity_root_char wprim). + exact: (prim_root_natf_neq0 wprim). by rewrite (prim_expr_order wprim) mem1v. Qed. @@ -349,7 +349,7 @@ Lemma cyclic_radical_ext w E F (n := \dim_E F) : Proof. set G := (X in cyclic X) => w_root wE galois_EF /cyclicP[g GE]. have EF := galois_subW galois_EF. -move: (primitive_unity_root_char w_root) => n_ne0. +move: (prim_root_natf_neq0 w_root) => n_ne0. have n_gt0: (0 < n)%N. by rewrite lt0n; move: n_ne0; apply: contra_neq => ->. have Gg : generator G g by rewrite GE generator_cycle. @@ -395,7 +395,7 @@ Lemma solvableWradical_ext w E F (n := \dim_E F) : Proof. move=> + + galEF; have [k] := ubnP n; elim: k => // k IHk in w E F n galEF *. rewrite ltnS => le_nk; have subEF : (E <= F)%VS by case/andP: galEF. -move=> /[dup]/primitive_unity_root_char n_ne0. +move=> /[dup]/prim_root_natf_neq0 n_ne0. have n_gt0: (0 < n)%N. by rewrite lt0n; move: n_ne0; apply: contra_neq => ->. move=> wn Ew solEF; have [n_le1|n_gt1] := leqP n 1%N. @@ -713,106 +713,6 @@ apply/splitting_galoisField; exists ('X^p - 'X - (x ^+ p - x)%:P); split. - by apply ArtinSchreier_splitting. Qed. - -(*** TODO: move to its proper place *********************) - -Lemma big_split_cond (R : Type) (idx : R) (op : Monoid.com_law idx) (I : Type) - (r : seq I) (P Q : pred I) (F G : I -> R) : - \big[op/idx]_(i <- r | P i) (if Q i then F i else G i) = - op (\big[op/idx]_(i <- r | P i && Q i) F i) - (\big[op/idx]_(i <- r | P i && ~~ Q i) G i). -Proof. -elim: r => [| a r IHr]; first by rewrite 3!big_nil Monoid.mulm1. -rewrite 3!big_cons. -case: (P a) => //=. -case: (Q a) => /=; first by rewrite IHr Monoid.mulmA. -by rewrite IHr Monoid.mulmCA. -Qed. - -Lemma bigA_distr_bigA2 (R : Type) (zero one : R) (times : Monoid.mul_law zero) - (plus : Monoid.add_law zero times) (I : finType) (F G : I -> R) : - \big[times/one]_i plus (F i) (G i) = - \big[plus/zero]_(J in {set I}) \big[times/one]_i (if i \in J then F i else G i). -Proof. -transitivity (\big[times/one]_i \big[plus/zero]_(b : bool) if b then F i else G i); first by apply eq_bigr => i _; rewrite big_bool. -rewrite bigA_distr_bigA. -set f := fun J : {set I} => val J. -transitivity (\big[plus/zero]_(f0 in (imset f (mem setT))) \big[times/one]_i (if f0 i then F i else G i)). - suff <-: setT = imset f (mem setT) by apply congr_big=>// i; rewrite in_setT. - apply/esym/eqP; rewrite -subTset; apply/subsetP => b _. - by apply/imsetP; exists (FinSet b). -rewrite big_imset; last by case => g; case => h _ _; rewrite /f/= => ->. -apply congr_big=>//; case => g; first by rewrite in_setT. -move=>_; apply eq_bigr => i _; congr (if _ then _ else _). -by rewrite SetDef.pred_of_setE. -Qed. - -Lemma coefn_prod_XsubC {R : comRingType} (ps : seq R) (n : nat) : - (n <= size ps)%N -> - (\prod_(p <- ps) ('X - p%:P))`_n = - (-1) ^+ (size ps - n)%N * - \sum_(I in {set 'I_(size ps)} | #|I| == (size ps - n)%N) - \prod_(i in I) ps`_i. -Proof. -move=> nle. -have psE: ps = tval (Tuple (eqxx (size ps))) by []. -transitivity (\prod_(p <- ps) ((- p)%:P + 'X))`_n. - by congr ((polyseq _)`_n); apply eq_bigr => i _; rewrite addrC polyCN. -rewrite {1}psE -(map_tnth_enum (Tuple _)) big_map enumT bigA_distr_bigA2 /=. -rewrite coef_sum. -transitivity (\sum_(I in {set 'I_(size ps)}) if #|I| == (size ps - n)%N then \prod_(i < size ps | i \in I) - (tnth (Tuple (eqxx (size ps))) i) else 0). - apply eq_bigr => I _. - rewrite big_split_cond/= big_const iter_mulr_1. - rewrite -(rmorph_prod (@polyC_rmorphism R))/= coefCM coefXn. - rewrite -[#|I| == _](eqn_add2l n) addnBA// [(_ + (size ps))%N]addnC -addnBA// subnn addn0 [(n + _)%N]addnC. - rewrite -[in X in _ = if _ == X then _ else _](card_ord (size ps)) -(cardC I) eqn_add2l. - by case: (n == #|[predC I]|); rewrite ?mulr1 ?mulr0. -rewrite -big_mkcond mulr_sumr/=; apply eq_bigr => I /eqP cardI. -rewrite prodrN cardI; congr GRing.mul; apply eq_bigr => i _. -by rewrite (tnth_nth (GRing.zero R)) -psE. -Qed. - -Lemma coefPn_prod_XsubC {R : comRingType} (ps : seq R) : - size ps != 0%N -> - (\prod_(p <- ps) ('X - p%:P))`_((size ps).-1) = - - \sum_(p <- ps) p. -Proof. -rewrite coefn_prod_XsubC ?leq_pred// => ps0. -have ->: (size ps - (size ps).-1 = 1)%N. - by move: ps0; case: (size ps)=>// n _; apply subSnn. -rewrite expr1 mulN1r; congr GRing.opp. -set f : 'I_(size ps) -> {set 'I_(size ps)} := fun a => [set a]. -transitivity (\sum_(I in imset f (mem setT)) \prod_(i in I) ps`_i). - apply congr_big=>// I /=. - apply/cards1P/imsetP. - by move=>[a ->]; exists a. - by move=>[a _ ->]; exists a. -rewrite big_imset/=; last by move=> i j _ _; rewrite/f => ij; apply/set1P; rewrite -ij set11. -have psE: ps = tval (Tuple (eqxx (size ps))) by []. -rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. -apply congr_big => // i; first by rewrite in_setT. -by move=>_; rewrite big_set1 (tnth_nth (GRing.zero R)) -psE. -Qed. - -Lemma coefP0_prod_XsubC {R : comRingType} (ps : seq R) : - (\prod_(p <- ps) ('X - p%:P))`_0 = - (-1) ^+ (size ps) * \prod_(p <- ps) p. -Proof. -rewrite coefn_prod_XsubC// subn0; congr GRing.mul. -transitivity (\sum_(I in [set setT : {set 'I_(size ps)}]) \prod_(i in I) ps`_i). - apply congr_big=>// i/=. - apply/idP/set1P. - by move=>/eqP cardE; apply/eqP; rewrite eqEcard subsetT cardsT card_ord cardE leqnn. - by move=>->; rewrite cardsT card_ord. -rewrite big_set1. -have psE: ps = tval (Tuple (eqxx (size ps))) by []. -rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. -apply congr_big => // i; first by rewrite in_setT. -by move=>_; rewrite (tnth_nth (GRing.zero R)) -psE. -Qed. - -(********************************) - Lemma minPoly_ArtinSchreier : (x \notin E) -> minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. Proof. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index d4057eb..ccec87b 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -1174,3 +1174,104 @@ Lemma solvable_SymF : 4 < #|T| -> solvable 'Sym_T = false. Proof. by rewrite (series_sol (Alt_normal T)) => /solvable_AltF->. Qed. End Perm_solvable. + +Section Coef_root_relations. + +Lemma big_if (R : Type) (idx : R) (op : Monoid.com_law idx) (I : Type) + (r : seq I) (P Q : pred I) (F G : I -> R) : + \big[op/idx]_(i <- r | P i) (if Q i then F i else G i) = + op (\big[op/idx]_(i <- r | P i && Q i) F i) + (\big[op/idx]_(i <- r | P i && ~~ Q i) G i). +Proof. +elim: r => [| a r IHr]; first by rewrite 3!big_nil Monoid.mulm1. +rewrite 3!big_cons. +case: (P a) => //=. +case: (Q a) => /=; first by rewrite IHr Monoid.mulmA. +by rewrite IHr Monoid.mulmCA. +Qed. + +Lemma bigA_distr_bigA2 (R : Type) (zero one : R) (times : Monoid.mul_law zero) + (plus : Monoid.add_law zero times) (I : finType) (F G : I -> R) : + \big[times/one]_i plus (F i) (G i) = + \big[plus/zero]_(J in {set I}) \big[times/one]_i (if i \in J then F i else G i). +Proof. +transitivity (\big[times/one]_i \big[plus/zero]_(b : bool) if b then F i else G i); first by apply eq_bigr => i _; rewrite big_bool. +rewrite bigA_distr_bigA. +set f := fun J : {set I} => val J. +transitivity (\big[plus/zero]_(f0 in (imset f (mem setT))) \big[times/one]_i (if f0 i then F i else G i)). + suff <-: setT = imset f (mem setT) by apply congr_big=>// i; rewrite in_setT. + apply/esym/eqP; rewrite -subTset; apply/subsetP => b _. + by apply/imsetP; exists (FinSet b). +rewrite big_imset; last by case => g; case => h _ _; rewrite /f/= => ->. +apply congr_big=>//; case => g; first by rewrite in_setT. +move=>_; apply eq_bigr => i _; congr (if _ then _ else _). +by rewrite SetDef.pred_of_setE. +Qed. + +Lemma coefn_prod_XsubC {R : comRingType} (ps : seq R) (n : nat) : + (n <= size ps)%N -> + (\prod_(p <- ps) ('X - p%:P))`_n = + (-1) ^+ (size ps - n)%N * + \sum_(I in {set 'I_(size ps)} | #|I| == (size ps - n)%N) + \prod_(i in I) ps`_i. +Proof. +move=> nle. +have psE: ps = tval (Tuple (eqxx (size ps))) by []. +transitivity (\prod_(p <- ps) ((- p)%:P + 'X))`_n. + by congr ((polyseq _)`_n); apply eq_bigr => i _; rewrite addrC polyCN. +rewrite {1}psE -(map_tnth_enum (Tuple _)) big_map enumT bigA_distr_bigA2 /=. +rewrite coef_sum. +transitivity (\sum_(I in {set 'I_(size ps)}) if #|I| == (size ps - n)%N then \prod_(i < size ps | i \in I) - (tnth (Tuple (eqxx (size ps))) i) else 0). + apply eq_bigr => I _. + rewrite big_if/= big_const iter_mulr_1. + rewrite -(rmorph_prod (@polyC_rmorphism R))/= coefCM coefXn. + rewrite -[#|I| == _](eqn_add2l n) addnBA// [(_ + (size ps))%N]addnC -addnBA// subnn addn0 [(n + _)%N]addnC. + rewrite -[in X in _ = if _ == X then _ else _](card_ord (size ps)) -(cardC I) eqn_add2l. + by case: (n == #|[predC I]|); rewrite ?mulr1 ?mulr0. +rewrite -big_mkcond mulr_sumr/=; apply eq_bigr => I /eqP cardI. +rewrite prodrN cardI; congr GRing.mul; apply eq_bigr => i _. +by rewrite (tnth_nth (GRing.zero R)) -psE. +Qed. + +Lemma coefPn_prod_XsubC {R : comRingType} (ps : seq R) : + size ps != 0%N -> + (\prod_(p <- ps) ('X - p%:P))`_((size ps).-1) = + - \sum_(p <- ps) p. +Proof. +rewrite coefn_prod_XsubC ?leq_pred// => ps0. +have ->: (size ps - (size ps).-1 = 1)%N. + by move: ps0; case: (size ps)=>// n _; apply subSnn. +rewrite expr1 mulN1r; congr GRing.opp. +set f : 'I_(size ps) -> {set 'I_(size ps)} := fun a => [set a]. +transitivity (\sum_(I in imset f (mem setT)) \prod_(i in I) ps`_i). + apply congr_big=>// I /=. + apply/cards1P/imsetP. + by move=>[a ->]; exists a. + by move=>[a _ ->]; exists a. +rewrite big_imset/=; last by move=> i j _ _; rewrite/f => ij; apply/set1P; rewrite -ij set11. +have psE: ps = tval (Tuple (eqxx (size ps))) by []. +rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. +apply congr_big => // i; first by rewrite in_setT. +by move=>_; rewrite big_set1 (tnth_nth (GRing.zero R)) -psE. +Qed. + +Lemma coefP0_prod_XsubC {R : comRingType} (ps : seq R) : + (\prod_(p <- ps) ('X - p%:P))`_0 = + (-1) ^+ (size ps) * \prod_(p <- ps) p. +Proof. +rewrite coefn_prod_XsubC// subn0; congr GRing.mul. +transitivity (\sum_(I in [set setT : {set 'I_(size ps)}]) \prod_(i in I) ps`_i). + apply congr_big=>// i/=. + apply/idP/set1P. + by move=>/eqP cardE; apply/eqP; rewrite eqEcard subsetT cardsT card_ord cardE leqnn. + by move=>->; rewrite cardsT card_ord. +rewrite big_set1. +have psE: ps = tval (Tuple (eqxx (size ps))) by []. +rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. +apply congr_big => // i; first by rewrite in_setT. +by move=>_; rewrite (tnth_nth (GRing.zero R)) -psE. +Qed. + + +End Coef_root_relations. + From a57ab3ea5108be47b01607d50518ac3196d34fa7 Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Fri, 21 Apr 2023 14:54:34 +0200 Subject: [PATCH 04/14] byproducts --- _CoqProject | 4 +- theories/xmathcomp/artin_scheier.v | 156 ++++++++++++ theories/xmathcomp/temp.v | 374 +++++++++++++++++++++++++++++ 3 files changed, 533 insertions(+), 1 deletion(-) create mode 100644 theories/xmathcomp/artin_scheier.v create mode 100644 theories/xmathcomp/temp.v diff --git a/_CoqProject b/_CoqProject index 7f764d8..57140ef 100644 --- a/_CoqProject +++ b/_CoqProject @@ -6,6 +6,8 @@ theories/xmathcomp/map_gal.v theories/xmathcomp/char0.v theories/xmathcomp/cyclotomic_ext.v theories/xmathcomp/real_closed_ext.v +theories/xmathcomp/artin_scheier.v +theories/xmathcomp/temp.v -R theories Abel -arg -w -arg -projection-no-head-constant @@ -15,4 +17,4 @@ theories/xmathcomp/real_closed_ext.v -arg -w -arg -ambiguous-paths -arg -w -arg +non-primitive-record -arg -w -arg +undeclared-scope --arg -w -arg +implicit-core-hint-db \ No newline at end of file +-arg -w -arg +implicit-core-hint-db diff --git a/theories/xmathcomp/artin_scheier.v b/theories/xmathcomp/artin_scheier.v new file mode 100644 index 0000000..e5fc917 --- /dev/null +++ b/theories/xmathcomp/artin_scheier.v @@ -0,0 +1,156 @@ +From mathcomp Require Import all_ssreflect all_fingroup all_algebra. +From mathcomp Require Import all_solvable all_field polyrcf. +From Abel Require Import various classic_ext map_gal algR. +From Abel Require Import char0 cyclotomic_ext real_closed_ext. + +Set Implicit Arguments. +Unset Strict Implicit. +Unset Printing Implicit Defensive. + +Import GRing.Theory. + +Local Open Scope ring_scope. + +Section ArtinSchreier. +Variable (p : nat) (F0 : fieldType) (L : splittingFieldType F0). +Variable (E : {subfield L}) (x : L). +Hypothesis (pchar : p \in [char L]) (xpE : x ^+ p - x \in E). + +Let pprim : prime p. +Proof. by move: pchar=>/andP[]. Qed. + +Let p0 : p%:R == 0 :> L. +Proof. by move: pchar=>/andP[_]. Qed. + +Let p1 : (1 < p)%N. +Proof. by apply prime_gt1. Qed. + +Lemma ArtinScheier_factorize : + 'X^p - 'X - (x ^+ p - x)%:P = + \prod_(z <- [seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]) + ('X - z%:P). +Proof. +case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. +apply/eqP; rewrite -eqp_monic; first last. +- by apply monic_prod_XsubC. +- apply/monicP; rewrite -addrA -opprD lead_coefDl ?lead_coefXn//. + by rewrite size_opp size_XaddC size_polyXn ltnS. +- rewrite eqp_sym -dvdp_size_eqp. + rewrite big_map size_prod; last first. + move=> [i]/= _ _; apply/negP => /eqP + /(congr1 (fun p : {poly L} => size p)). + by rewrite size_XsubC size_polyC eqxx. + have ->: \big[addn/0%N]_(i < n.+1) size ('X - (x + (val i)%:R)%:P)%R = + \big[addn/0%N]_(i < n.+1) 2%N. + by apply eq_bigr=> i _; rewrite size_XsubC. + rewrite big_const_ord iter_addn_0. + rewrite -add1n mul2n -addnn addnA card_ord -addnBA// subnn addn0 add1n. + rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. + by move: pchar => /andP [ /prime_gt1 ]. + apply uniq_roots_dvdp. + apply/allP => + /mapP [i _ ->] => _. + rewrite/root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). + (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) + rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). + rewrite opprD opprB addrACA -addrA 2![x+_]addrA subrr add0r. + by rewrite addrAC addrCA subrr addr0 addrC subrr. + rewrite uniq_rootsE; apply/(uniqP 0) => i j. + rewrite 2!inE size_map => ilt jlt. + rewrite (nth_map ord0)// (nth_map ord0)// => /addrI/esym/eqP. + set ip := nth ord0 (index_enum (ordinal_finType n.+1)) i. + set jp := nth ord0 (index_enum (ordinal_finType n.+1)) j. + move=>ijE. + suff: jp = ip. + rewrite/ip/jp => /esym ijE0. + by move: (index_enum_uniq (ordinal_finType n.+1))=>/uniqP + /(_ i j ilt jlt ijE0). + move:ijE. + wlog ij : {i} {j} {ilt} {jlt} ip jp / (val ip <= val jp)%N. + move=> h. + move: (Order.TotalTheory.le_total (val ip) (val jp)) => /orP; case => ij. + by apply h. + by rewrite eq_sym=> ijE; apply /esym/h. + rewrite -subr_eq0 -natrB// -(dvdn_charf nchar). + case /posnP: (val jp - val ip)%N. + move=>/eqP; rewrite subn_eq0 => ji _; apply/val_inj/eqP. + by rewrite Order.POrderTheory.eq_le; apply/andP; split. + move=>ij0 /(dvdn_leq ij0); rewrite ltn_subRL -addnS. + move=>/(leq_trans (leq_addl _ _)). + have: (val jp < n.+1)%N by destruct jp. + by rewrite ltnS => jle; move => /(leq_ltn_trans jle); rewrite ltnn. +Qed. + +Lemma ArtinSchreier_splitting : + splittingFieldFor E ('X^p - 'X - (x ^+ p - x)%:P) <>%AS. +Proof. +exists ([seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]). + by rewrite ArtinScheier_factorize big_map eqpxx. +apply/eqP; rewrite eqEsubv; apply/andP; split. + apply/Fadjoin_seqP; split; first by apply subv_adjoin. + move=>+ /mapP [i _ ->] => _. + apply (@rpredD _ _ (memv_addrPred <>%AS)); first by apply memv_adjoin. + by apply rpred_nat. +apply/FadjoinP; split; first by apply subv_adjoin_seq. +case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. +apply/seqv_sub_adjoin/mapP; exists ord0; first by apply mem_index_enum. +by rewrite addr0. +Qed. + +Lemma ArtinSchreier_polyOver : + 'X^p - 'X - (x ^+ p - x)%:P \is a polyOver E. +Proof. by rewrite rpredB ?polyOverC// rpredB ?rpredX// polyOverX. Qed. + +Lemma ArtinSchreier_galois : + galois E <>. +Proof. +apply/splitting_galoisField; exists ('X^p - 'X - (x ^+ p - x)%:P); split. +- exact ArtinSchreier_polyOver. +- rewrite/separable_poly derivB derivC subr0 derivB derivXn derivX -scaler_nat. + move: pchar; rewrite inE => /andP[_ /eqP ->]. + rewrite scale0r add0r. + apply/Bezout_eq1_coprimepP; exists (0, (-1)) => /=. + by rewrite mul0r add0r mulN1r opprK. +- by apply ArtinSchreier_splitting. +Qed. + +Lemma minPoly_ArtinSchreier : (x \notin E) -> + minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. +Proof. +move=> xE. +have /(minPoly_dvdp ArtinSchreier_polyOver): root ('X^p - 'X - (x ^+ p - x)%:P) x. + rewrite ArtinScheier_factorize root_prod_XsubC. + case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. + apply/mapP; exists ord0; first by rewrite mem_index_enum. + by rewrite addr0. +rewrite ArtinScheier_factorize big_map. +move=> /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last first. + by rewrite monic_prod// => i _; rewrite monic_XsubC. +have [{}m sm ->] := resize_mask m (index_enum (ordinal_finType p)). +set s := mask _ _ => /eqP mEx. +have [|smp_gt0] := posnP (size s). + case: s mEx => // /(congr1 (horner^~x))/esym/eqP. + by rewrite minPolyxx big_nil hornerC oner_eq0. +suff leq_pm : (p <= size s)%N. + move: mEx; suff /eqP->: s == index_enum (ordinal_finType p) by []. + rewrite -(geq_leqif (size_subseq_leqif _)) ?mask_subseq//. + by rewrite/index_enum; case: index_enum_key=>/=; rewrite -enumT size_enum_ord. +have /polyOverP/(_ (size s).-1%N) := minPolyOver E x; rewrite {}mEx. +have ->: \prod_(i <- s) ('X - (x + (val i)%:R)%:P) = \prod_(i <- [seq x + (val i)%:R | i <- s]) ('X - i%:P) by rewrite big_map. +rewrite -(size_map (fun i => x + (val i)%:R)) coefPn_prod_XsubC size_map -?lt0n// big_map. +rewrite memvN big_split/= big_const_seq count_predT iter_addr_0 => DE. +have sE: \sum_(i <- s) i%:R \in E by apply rpred_sum => i _; apply rpred_nat. +move:(rpredB DE sE) => {DE} {sE}. +rewrite -addrA subrr addr0 => xsE. +apply/negP => sltp. +have /coprimeP: coprime (size s) p. + by rewrite coprime_sym (prime_coprime _ pprim); apply/negP => /(dvdn_leq smp_gt0). +move=> /(_ smp_gt0) [[u v]]/= uv1. +have /ltnW vltu: (v * p < u * size s)%N by rewrite ltnNge -subn_eq0 uv1. +move:uv1 => /eqP; rewrite -(eqn_add2l (v * p)) addnBA// addnC -addnBA// subnn addn0 => /eqP sE. +move: xsE => /(rpredMn u); rewrite -mulrnA mulnC sE addn1 mulrS mulrnA -mulr_natr. +move: p0 => /eqP ->; rewrite mulr0 addr0. +by move: xE => /negP. +Qed. + +End ArtinSchreier. + diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v new file mode 100644 index 0000000..a2be78c --- /dev/null +++ b/theories/xmathcomp/temp.v @@ -0,0 +1,374 @@ +From mathcomp Require Import all_ssreflect all_fingroup all_algebra. +From mathcomp Require Import all_solvable all_field polyrcf. +From Abel Require Import various classic_ext map_gal algR. +From Abel Require Import char0 cyclotomic_ext real_closed_ext artin_scheier. + +Set Implicit Arguments. +Unset Strict Implicit. +Unset Printing Implicit Defensive. + +Import GRing.Theory. + +Local Open Scope ring_scope. + +Section Temp. + +Lemma ord_S_split n (i: 'I_n.+1): {j: 'I_n | i = lift ord0 j} + {i = ord0}. +Proof. +case: i; case=>[| i] ilt. + by right; apply val_inj. +by left; exists (Ordinal (ltnSE ilt)); apply val_inj. +Qed. + +(* NB : rpredM and mulrPred uses that 1 is in the subset, which is useless. Predicates should be defined for {aspace aT}. *) + +Lemma memv_mulr_2closed [K : fieldType] [aT : FalgType K] (U : {aspace aT}) : GRing.mulr_2closed U. +Proof. +move: U => [U]/[dup]/andP[_ /subvP UU] Ualg. +move=> u v uU vU; apply/UU/memv_mulP; exists 1%N, (@Tuple _ _ [:: u] (eqxx _)), (@Tuple _ _ [:: v] (eqxx _)); split => /=. +- by rewrite uU. +- by rewrite vU. +- by rewrite big_ord1 2!(tnth_nth 1)/=. +Qed. + +Lemma polyOver_mulr_2closed [R : ringType] [S : {pred R}] [addS : addrPred S] (kS : keyed_pred addS) : GRing.mulr_2closed kS -> GRing.mulr_2closed (polyOver kS). +Proof. +move=>SM u vz /polyOverP uS /polyOverP vS; apply/polyOverP => i. +by rewrite coefM rpred_sum // => j _; apply SM. +Qed. + +Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] (f g : 'AHom(K, rT)) + (U : {subfield K}) (x : K) : + {in U, f =1 g} -> f x = g x -> {in <>%VS, f =1 g}. +Proof. +move=>fgU fgx y /Fadjoin_poly_eq <-. +move:(Fadjoin_polyOver U x y); generalize (Fadjoin_poly U x y) => p /polyOverP pU. +rewrite -(coefK p) horner_poly 2!rmorph_sum/=; apply eq_bigr => i _. +by rewrite 2!rmorphM /= fgU// 2!rmorphX/= fgx. +Qed. + +Lemma ahom_eq_adjoin_seq [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] (f g : 'AHom(K, rT)) + (U : {aspace K}) (xs : seq K) : + {in U, f =1 g} -> all (fun x => f x == g x) xs -> {in <>%VS, f =1 g}. +Proof. +elim: xs U => [|x xs IHxs] U fgU fgxs. + by rewrite adjoin_nil subfield_closed. +rewrite adjoin_cons. +have ->: <>%VS = ASpace (agenv_is_aspace <>%VS) by rewrite /= agenv_id. +move: fgxs (IHxs (ASpace (agenv_is_aspace <>))) => /andP[/eqP fgx fgxs] /=. +by rewrite agenv_id => /(_ (ahom_eq_adjoin fgU fgx) fgxs). +Qed. + +Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. +Proof. +move=>->. +suff ->: (1+U)%VS = U by rewrite subfield_closed. +rewrite -{2}(subfield_closed U) (agenvEr U) subfield_closed. +by congr (1 + _)%VS; apply/esym/field_module_eq; rewrite sup_field_module. +Qed. + +Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f g : FinGroup.finType (gal_finGroupType E)) : f = g \/ exists x, x \in E /\ f x != g x. +Proof. +move:(vbasisP E)=>/span_basis/agenv_span LE. +case/boolP: (all (fun x => f x == g x) (vbasis E)) => [fgE | /allPn[x] xE fgx]; [ left | right ]. + 2: by exists x; split=>//; apply vbasis_mem. +apply/eqP/gal_eqP. +rewrite -{1}LE; apply ahom_eq_adjoin_seq=>//. +move:(gal1 f)(gal1 g). +rewrite gal_kHom ?sub1v// gal_kHom ?sub1v// => /andP [_ /subvP f1] /andP [_ /subvP g1]. +by move=>x /[dup] /f1/fixedSpaceP -> /g1/fixedSpaceP ->. +Qed. + +Lemma tnth_cons (T : Type) (x : T) (l : seq T) (i : 'I_(size l)): tnth (in_tuple (x :: l)) (lift ord0 i) = tnth (in_tuple l) i. +Proof. by rewrite/tnth/=; apply set_nth_default. Qed. + +Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f : seq (FinGroup.finType (gal_finGroupType E))) (k : 'I_(size f) -> L) : uniq f -> (forall i, k i = 0) \/ (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). +Proof. +move:(Logic.eq_refl (size f)); generalize (size f) at 1 => n. +elim: n f k => [|n IHn] f k fsize funiq. + by left; case; move: k; rewrite -fsize. +destruct f as [| s f] => //. +destruct n; destruct f as [| s0 f] => //. + case/boolP: (k 0 == 0). + move=>/eqP k0; left => i. + by move: k0; congr (k _ = 0); apply val_inj; case i; case. + move=>/negPf k0; right; exists 1; rewrite big_ord1 /= rmorph1; split. + by apply mem1v. + by apply/negP; rewrite mulr1 k0. +move: funiq => /=; rewrite negb_or => /andP [/andP[ss0 sf]] /[dup] s0f /andP[_ funiq]. +case: (gal_ne s s0) => [/eqP ss0E | [x [xE /negPf ss0x]]]. + by move: ss0; rewrite ss0E. +move:fsize=>/eqP; rewrite eqSS=>/eqP fsize. +case: (IHn [:: s0 & f] (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) i x - s x))) fsize s0f). + move=>/(_ ord0)/=/eqP; rewrite mulf_eq0 subr_eq0 [s0 x == _]eq_sym ss0x orbF => k10. + set k' := fun i : 'I_(size f).+1 => k (if ord_S_split i then lift ord0 i else ord0). + move: (IHn [:: s & f] k' fsize). + have /[swap]/[apply]: uniq (s :: f) by apply/andP; split. + case => [k0 | [a [aE fne0]]]; [left => i | right; exists a]. + case: i; case. + move: (k0 ord0); rewrite/k'. + case: (ord_S_split _) => [[i /=/(congr1 val)//] | /= _ /[swap] ilt]. + by congr (k _ = 0); apply val_inj. + case => [|i] ilt. + by move: k10 => /eqP; congr (k _ = 0); apply val_inj. + have ile: (i.+1 < (size f).+1)%N by rewrite -ltnS. + move:(k0 (Ordinal ile)); rewrite/k'. + case: (ord_S_split _) => [/= _| /[dup]/(congr1 val)//]. + by congr (k _ = 0); apply val_inj. + split=>//. + move:k10 fne0 => /eqP k10. + rewrite 3!big_ord_recl/= k10 mul0r add0r. + congr (_ * _ + _ != 0). + by rewrite/k'; case: (ord_S_split _) => // [[i]] /=/(congr1 val). + apply eq_bigr => i _; rewrite tnth_cons (@tnth_cons _ s (s0 :: f) (lift ord0 i)) tnth_cons; congr (_ * _). + by rewrite/k'; case: (ord_S_split _). +move=>[y [yE fne0]]; right. +case /boolP: (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) => [| yne0]. + 2: by exists y. +rewrite big_ord_recl/= addrC addr_eq0 {2}/tnth/= => /eqP. +under eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)); move=> y0. +exists (x*y); split; first by apply rpredM. +move: fne0; congr (_ != 0). +under [\sum_(_ < (size f).+1) _]eq_bigr do rewrite mulrBr mulrBl [X in _ - X * _]mulrC -mulrA -rmorphM/= -[X in _ - X]mulrA. +rewrite sumrB -mulr_sumr y0 mulrN mulrA opprK [s x * _]mulrC -mulrA -rmorphM/= addrC [in RHS]big_ord_recl {2}/tnth/=. +by under [in RHS]eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)). +Qed. + +Lemma galTrace_ne_0 (F : fieldType) (L : splittingFieldType F) (K E : {subfield L}) : exists a, a \in E /\ galTrace K E a != 0. +Proof. +set l := index_enum (FinGroup.finType (gal_finGroupType E)). +case: (gal_free (fun i : 'I_(size l) => (1 *+ ((tnth (in_tuple l) i) \in (galoisG E K) : nat))%:A) (index_enum_uniq _)). + have /[dup] l1: 1%g \in l by apply mem_index_enum. + rewrite -index_mem => lt1. + by move=>/(_ (Ordinal lt1))/=/eqP; rewrite /tnth (nth_index _ l1) group1/= scaler_eq0 2!oner_eq0. +move=>[x [xE s0]]; exists x; split=>//; move:s0; congr (_ != 0). +rewrite/galTrace -(big_tuple _ _ _ xpredT (fun f => (f \in galoisG E K)%:R%:A * f x))/=/l. +rewrite [in RHS]big_mkcond/=; apply eq_bigr => i _. +case: (i \in galoisG E K) => /=; first by rewrite mulr1n scale1r mul1r. +by rewrite mulr0n scale0r mul0r. +Qed. + +Lemma ffun_sum [T : finType] [R : ringType] [E : vectType R] + (f : seq (ffun_vectType T E)) (x : T) : + (\sum_(i <- f) i) x = \sum_(i <- f) i x. +Proof. +elim: f; first by rewrite 2!big_nil ffunE. +move=> a f IHf. +by rewrite 2!big_cons ffunE IHf. +Qed. + + +Definition Zp_succ n (i : 'I_n) := Ordinal ( + match n with + | 0 => fun i0 : 'I_0 => match i0 with | @Ordinal _ _ i0 => i0 end + | n0.+1 => fun i0 => (ltn_pmod i0.+1 (is_true_true : (is_true (0 < n0.+1)%N))) + end i). + +Lemma cycle_imset [gT : finGroupType] (g : gT) : <[g]>%g = @Imset.imset (ordinal_finType #[g]%g) (FinGroup.finType gT) (fun i => (g ^+ (val i))%g) (mem setT). +Proof. +apply/eqP; rewrite eqEsubset; apply/andP; split; apply/subsetP => x. + move=>/cycleP [i ->]; apply/imsetP. + exists (Ordinal (ltn_pmod i (order_gt0 g))); rewrite ?in_setT//. + by rewrite expg_mod_order. +by move=>/imsetP [i] _ ->; apply/cycleP; exists i. +Qed. + +Lemma cycle_imset_inj [gT : finGroupType] (g : gT) : {in setT &, injective (fun i : 'I_(#[g]%g) => (g ^+ i)%g)}. +Proof. +move=>[i ilt] [j jlt]/= _ _ /eqP; rewrite eq_expg_mod_order. +rewrite modn_small// modn_small// => /eqP ijE. +by apply val_inj. +Qed. + +Lemma big_condT [R : Type] [idx : R] (op : Monoid.com_law idx) + [I : finType] (A : {pred I}) (F : I -> R) : + \big[op/idx]_(i in A | true) F i = \big[op/idx]_(i in A) F i. +Proof. by apply congr_big => // i; rewrite andbT. Qed. + +Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) + [I : finType] (F : I -> R) : + \big[op/idx]_(i in [set: I]) F i = \big[op/idx]_i F i. +Proof. by apply congr_big => // i; rewrite in_setT. Qed. + +Lemma Hilbert's_theorem_90_additive + [F : fieldType] [L : splittingFieldType F] + [K E : {subfield L}] [x : gal_finGroupType E] + [a : L] : + galois K E -> + generator 'Gal(E / K) x -> + a \in E -> + reflect (exists2 b : L, b \in E & a = b - x b) + (galTrace K E a == 0). +Proof. +move=>Egal /(_ =P <[x]>%g) DgalE Ea. +have galEx: x \in 'Gal(E / K)%g by rewrite DgalE cycle_id. +apply: (iffP eqP) => [normEa1 | [b Eb ->]]; last first. + by rewrite galTrace_is_additive galTrace_gal// subrr. +move:(galTrace_ne_0 K E) => [b [bE tb]]. +remember (\dim_K E) as n. +have ordx: #[x]%g = n by rewrite orderE -DgalE -(galois_dim Egal). +move:(expg_order x); rewrite ordx => xord. +move:(Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). +rewrite mul0n adim_gt0 => dimgt0 /(_ 1%N); rewrite mul1n => dimgt1. +destruct n; first by move:dimgt0; rewrite -Heqn. +destruct n. + move:dimgt1; rewrite -Heqn ltnn => /esym/negbT; rewrite -leqNgt => dimEK. + move:(eqEdim K E); rewrite dimEK (galois_subW Egal) => /=/eqP KE. + move:normEa1; rewrite/galTrace. + have ->: \sum_(x0 in ('Gal(E / K))%g) x0 a = \sum_(x0 in ('Gal(E / K))%g) a. + apply eq_bigr => f fgal. + move:Egal=>/galois_fixedField Kfix. + by move:(Ea); rewrite -{1}KE -Kfix => /fixedFieldP => /(_ Ea f fgal). + rewrite sumr_const; rewrite -(galois_dim Egal) -Heqn mulr1n => a0. + by exists a => //; rewrite a0 rmorph0 subr0. +set c := (galTrace K E b)^-1 * \sum_(i < n.+1) (\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. +have tbE: galTrace K E b \in E by rewrite /galTrace rpred_sum// => f _; apply memv_gal. +exists c. + apply rpredM; first by rewrite rpredV. + rewrite rpred_sum// => i _. + apply rpredM; last by apply memv_gal. + by rewrite rpred_sum// => j _; apply memv_gal. +rewrite/c rmorphM/= rmorphV/= ?unitfE//. +move:(galTrace_fixedField K bE) => /fixedFieldP => /(_ tbE x galEx) ->. +rewrite -mulrBr rmorph_sum/=. +rewrite big_ord_recl big_ord1 expg0 gal_id expg1 big_ord_recr/=. +rewrite opprD addrAC [_ - x _]addrC addrA -addrA [- _ + _]addrC -sumrB. +have ->: \sum_(i < n) ((\sum_(j < (bump 0 i).+1) (x ^+ j)%g a) * (x ^+ (bump 0 i).+1)%g b - + x ((\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b)) = + \sum_(i < n) a * (x ^+ i.+2)%g b. + apply eq_bigr; case => i ilt _ /=. + rewrite/bump/= add1n rmorphM/= rmorph_sum/= expgSr galM// -mulrBl; congr (_ * _). + rewrite big_ord_recl/= -addrA -sumrB expg0 gal_id -[in RHS](addr0 a); congr (a + _). + transitivity (\sum_(j < i.+1) (0 : L)); last by rewrite sumr_const mul0rn. + by apply eq_bigr => j _; rewrite/bump/= add1n expgSr galM// subrr. +rewrite -mulr_sumr rmorphM/= rmorph_sum/=. +have tE: forall d, d \in E -> galTrace K E d = \sum_(i < n.+2) (x ^+ i)%g d. + move=>d dE. + rewrite/galTrace DgalE cycle_imset => /=. + rewrite -big_condT/=. + rewrite (big_imset_cond _ _ _ (@cycle_imset_inj _ x)). + by rewrite big_condT /= ordx big_setT/= big_ord_recl expg0 gal_id. +move:normEa1; rewrite tE// big_ord_recl expg0 gal_id => /eqP. +under [in X in X -> _]eq_bigr do rewrite /=/bump/=add1n expgSr galM//. +rewrite addrC addr_eq0 => /eqP ->. +rewrite mulNr opprK -2!mulrDr mulrCA -(galM _ x bE) -expgSr xord gal_id [x b + b]addrC. +have <-: galTrace K E b = b + x b + \sum_(i < n) (x ^+ i.+2)%g b. + rewrite (tE b bE) big_ord_recl/= expg0 gal_id big_ord_recl/= expg1 addrA. + by under eq_bigr do rewrite /bump/= 2!add1n. +by rewrite mulVf// mulr1. +Qed. + +Lemma natf_partn_ne0 (R : idomainType) n : + (n`_[char R]^')%:R != 0 :> R. +Proof. +have n_gt0 := (part_gt0 [char R]^' n). +apply/negP; rewrite/partn natr_prod prodf_seq_eq0 => /hasP [i] i0n. +rewrite unfold_in/= natrX expf_eq0 logn_gt0 mem_primes => /andP[/negP ichar]. +move=>/andP[/andP[iprim _] i0]; apply ichar; rewrite unfold_in/=. +by apply/andP. +Qed. + +Lemma natf0_partn (R : idomainType) n : (0 < n)%N -> (n%:R == 0 :> R) = (n`_[char R] != 1)%N. +Proof. +move=>n_gt0. +apply/idP/idP => [n0 |]. + apply/negP => /eqP nchar1. + move:n0; rewrite -(partnC [char R] n_gt0) nchar1 mul1n => n0. + by move:(natf_partn_ne0 R n); rewrite n0. +rewrite partn_eq1// /pnat n_gt0/= => /allPn [p]. +rewrite mem_primes => /andP [pprim /andP [_ pn]]. +rewrite /negn/mem/= 2!unfold_in negbK /= => pchar. +by rewrite -(dvdn_charf pchar). +Qed. + +Lemma primes_dvdn (m n : nat) : + (0 < n)%N -> (m %| n)%N -> primes m = [seq p <- primes n | p \in primes m]. +Proof. +move=>n0 mn. +apply Order.POrderTheory.lt_sorted_eq. +- apply sorted_primes. +- apply sorted_filter. + apply Order.POrderTheory.lt_trans. +apply sorted_primes. +- move=>p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. +rewrite 2!mem_primes => /andP[->/=]/andP[m0 pm]. +by rewrite n0/=; apply (dvdn_trans pm). +Qed. + +Lemma dvdn_leq_logP (m n : nat) : + (0 < n)%N -> (0 < m)%N -> reflect (forall p, prime p -> logn p m <= logn p n)%N (m %| n)%N. +Proof. +move=>n0 m0; apply (iffP idP) => [mn p prim | vp_leq]. + by apply dvdn_leq_log. +apply/dvdnP; exists (\prod_(p <- primes n) p ^ (logn p n - logn p m))%N. +rewrite {1}(prod_prime_decomp n0) {2}(prod_prime_decomp m0) 2!prime_decompE 2!big_map/=. +have ->: primes m = [seq i <- primes n | i \in primes m]. + apply Order.POrderTheory.lt_sorted_eq. + - apply sorted_primes. + - apply sorted_filter. + apply Order.POrderTheory.lt_trans. + apply sorted_primes. + - move=>p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. + move=>/[dup]; rewrite {1}mem_primes => /andP[pprim _]. + rewrite -2!logn_gt0 => pm. + apply (leq_trans pm (vp_leq p pprim)). +rewrite big_filter [in X in (_ * X)%N]big_mkcond/= -big_split/= 2!big_seq. +apply eq_bigr => p; rewrite mem_primes => /andP[pprim _]. +have ->: ((if p \in primes m then p ^ logn p m else 1) = p ^ logn p m)%N. + case/boolP: (p \in primes m) => //. + by rewrite -logn_gt0 lt0n negbK => /eqP ->; rewrite expn0. +by rewrite -expnD subnK// vp_leq. +Qed. + +Lemma muln_gt0 [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : + all (fun n : I => P n ==> (0 < F n)%N) r -> + (0 < \prod_(n <- r | P n) F n)%N. +Proof. +elim: r => [|n r IHn /andP[Fn0 Fr0]]; first by rewrite big_nil. +rewrite big_cons; case /boolP: (P n) => Pn; last by apply IHn. +rewrite muln_gt0. +by move:Fn0; rewrite Pn/= IHn ?andbT. +Qed. + +Lemma logn_prod [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : + all (fun n : I => P n ==> (0 < F n)%N) r -> + (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. +Proof. +elim: r => [|n r IHn /andP[Fn0 Fr0]]; first by rewrite 2!big_nil logn1. +rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply IHn. +move:Fn0; rewrite Pn => /= Fn0. +by rewrite lognM// ?muln_gt0// IHn. +Qed. + +Lemma logn_partn (p n : nat) (pi : nat_pred) : + logn p (n`_pi)%N = ((p \in pi) * logn p n)%N. +Proof. +rewrite/partn logn_prod; last by apply/allP => i _; rewrite pfactor_gt0 implybT. +under eq_bigr do rewrite lognX. +have logp (i : nat): (i == p) || (logn i n * logn p i == 0)%N. + case /boolP: (i == p) => //= /negPf ip. + case /boolP: (prime i) => [|/negPf] iprim; last first. + by rewrite/logn iprim mul0n. + by rewrite (logn_prime _ iprim) [p == i]eq_sym ip muln0. +case /boolP: (p < n.+1)%N => [plt |]; last first. + rewrite -leqNgt => np. + suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i = \sum_(0 <= i < n.+1 | i \in pi) 0)%N. + by rewrite big_const_seq iter_addn_0 mul0n ltn_log0// muln0. + apply eq_bigr => i _. + move: (logp i) => /orP [|]/eqP ->//. + by rewrite ltn_log0// mul0n. +suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i = \sum_(i < n.+1 | pred1 (Ordinal plt) i) (p \in pi) * logn i n)%N. + by rewrite (big_pred1 (Ordinal plt)). +rewrite big_mkord big_mkcond/= [in RHS]big_mkcond/=. +apply eq_bigr => i _. +have ->: (i == Ordinal plt = (val i == p)). + by apply/eqP/eqP => [/(congr1 val)// | ] ip; apply val_inj. +move: (logp i); case /boolP: (val i == p)%N => /= [|_] /eqP ->. + 2: by case: (val i \in pi). +move=>_; case: (p \in pi); last by rewrite mul0n. +rewrite mul1n. +case /boolP: (prime p) => [| /negPf] pprim; last by rewrite/logn pprim. +by rewrite -{3}(expn1 p) pfactorK// muln1. +Qed. + +End Temp. From 959f75d5adfbe1688837113df4435b06bc0fc928 Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Fri, 21 Apr 2023 14:55:03 +0200 Subject: [PATCH 05/14] characteristic independant AbelGalois --- theories/abel.v | 399 ++++++++++++++++++++++-------------------------- 1 file changed, 182 insertions(+), 217 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 9c4673c..33e9a84 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -1,12 +1,12 @@ From mathcomp Require Import all_ssreflect all_fingroup all_algebra. From mathcomp Require Import all_solvable all_field polyrcf. From Abel Require Import various classic_ext map_gal algR. -From Abel Require Import char0 cyclotomic_ext real_closed_ext. +From Abel Require Import char0 cyclotomic_ext real_closed_ext artin_scheier temp. (*****************************************************************************) (* We work inside a enclosing splittingFieldType L over a base field F0 *) (* *) -(* radical U x n := x is a radical element of degree n over U *) +(* radical U x n := x is a radical elemen,ct of degree n over U *) (* pradical U x p := x is a radical element of prime degree p over U *) (* r.-tower U e pw := e is a chain of elements of L such that *) (* forall i, r <> e`_i pw`_i *) @@ -338,66 +338,159 @@ Section Abel. (* *) (******************************************************************************) +Lemma radical_aimg (F0 : fieldType) (L L' : splittingFieldType F0) + (iota : 'AHom(L, L')) (U : {vspace L}) + (x : Falgebra.vect_ringType L) (n : nat) : + radical (iota @: U) (iota x) n = radical U x n. +Proof. +rewrite/radical (fmorph_char (ahom_rmorphism iota))/=-rmorphX/= -rmorphB/=. +have inE: forall y, iota y \in (iota @: U)%VS = (y \in U). + move=>y; apply/idP/idP. + by move=>/memv_imgP [u uU] /fmorph_inj ->. + by move=>/(memv_img iota). +by rewrite 2!inE. +Qed. + +Lemma radical_tower_aimg (F0 : fieldType) (L L' : splittingFieldType F0) + (iota : 'AHom(L, L')) (E : {subfield L}) (e : ext_data L) : + radical.-tower (ext_size e) (iota @: E) + [tuple of [seq iota x | x <- ext_ep e]] (ext_pw e) = + radical.-tower (ext_size e) E (ext_ep e) (ext_pw e). +Proof. +apply/forallP/forallP => tower i /=. + move:(tower i). + by rewrite -map_take -aimg_adjoin_seq tnth_map radical_aimg. +by rewrite -map_take -aimg_adjoin_seq tnth_map radical_aimg. +Qed. + +Lemma radical_ext_aimg (F0 : fieldType) (L L' : splittingFieldType F0) + (iota : 'AHom(L, L')) (E F : {subfield L}): + radical.-ext (iota @: E) (iota @: F) <-> radical.-ext E F. +Proof. +split => [[]|[]] e tower img; last first. + exists (ExtData [tuple of [seq iota x | x <- ext_ep e]] (ext_pw e))=>/=. + by rewrite radical_tower_aimg. + by rewrite -aimg_adjoin_seq img. +have /subset_limgP [f fF ef]: {subset (ext_ep e) <= (iota @: F)%VS}. + rewrite -img; exact: seqv_sub_adjoin. +have sizef: size f == ext_size e by rewrite -(size_map iota) -ef size_tuple. +set e' := ExtData (Tuple sizef) (ext_pw e). +exists e'. + rewrite -(radical_tower_aimg iota)/=. + suff <-: ext_ep e = [tuple of [seq iota x | x <- ext_ep e']] by []. + by apply val_inj. +apply/eqP; rewrite -(@eq_limg_ker0 _ _ _ iota) ?AHom_lker0// aimg_adjoin_seq/=. +by rewrite -ef img. +Qed. + Section Part1. Variables (F0 : fieldType) (L : splittingFieldType F0). Implicit Types (E F K : {subfield L}) (w : L) (n : nat). -Let radical := @radical F0 L. - -Lemma cyclic_radical_ext w E F (n := \dim_E F) : - n.-primitive_root w -> w \in E -> galois E F -> - cyclic 'Gal(F / E) -> radical.-ext E F. -Proof. -set G := (X in cyclic X) => w_root wE galois_EF /cyclicP[g GE]. -have EF := galois_subW galois_EF. -move: (prim_root_natf_neq0 w_root) => n_ne0. -have n_gt0: (0 < n)%N. - by rewrite lt0n; move: n_ne0; apply: contra_neq => ->. -have Gg : generator G g by rewrite GE generator_cycle. -have gG : g \in G by rewrite GE cycle_id. -have HT90g := Hilbert's_theorem_90 Gg (subvP EF _ wE). -have /eqP/HT90g[x [xF xN0]] : galNorm E F w = 1. - rewrite /galNorm; under eq_bigr => g' g'G. rewrite (fixed_gal EF g'G)//. over. - by rewrite prodr_const -galois_dim// (prim_expr_order w_root). -have gxN0 : g x != 0 by rewrite fmorph_eq0. -have wN0 : w != 0. rewrite (primitive_root_eq0 w_root) -lt0n //. -move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. -have gXx i : (g ^+ i)%g x = w ^- i * x. - elim: i => [|i IHi]. - by rewrite expg0 expr0 invr1 mul1r gal_id. - rewrite expgSr exprSr invfM galM// IHi rmorphM/= gx mulrA. - by rewrite (fixed_gal EF gG) ?rpredV ?rpredX. -have ExF : (<> <= F)%VS by exact/FadjoinP. -suff -> : F = <>%AS. - apply: radical_ext_Fadjoin1 n_ne0 _. - rewrite -(galois_fixedField galois_EF) -/G GE. - apply/fixedFieldP; first by rewrite rpredX. - move=> _ /cycleP[i ->]; rewrite rmorphX/= gXx exprMn exprVn exprAC. - by rewrite (prim_expr_order w_root)// expr1n invr1 mul1r. -apply/val_inj/eqP => /=. -have -> : F = fixedField (1%g : {set gal_of F}) :> {vspace L}. - by apply/esym/eqP; rewrite -galois_eq ?galvv ?galois_refl//. -rewrite -galois_eq; last by apply: galoisS galois_EF; rewrite subv_adjoin. -rewrite -subG1; apply/subsetP => g' g'G'. -have /cycleP[i g'E]: g' \in <[g]>%g. - rewrite -GE gal_kHom//; apply/kAHomP => y yE. - by rewrite (fixed_gal _ g'G') ?subvP_adjoin. -rewrite g'E in g'G' *. -have : (g ^+ i)%g x = x by rewrite (fixed_gal _ g'G') ?memv_adjoin. -rewrite gXx => /(canRL (mulfK xN0))/eqP; rewrite divff// invr_eq1. -rewrite -(prim_order_dvd w_root) => dvdni. -have /exponentP->// : (exponent G %| i)%N. -by rewrite GE exponent_cycle orderE -GE -galois_dim. + +Lemma cyclic_radical_ext w E F : + ((\dim_E F)`_[char L]^').-primitive_root w -> w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F. +Proof. +case /boolP: (E == F :> {vspace L}) => [/eqP -> _ _ _ _ | EneF]. + by apply rext_refl. +remember (\dim_E F) as n. +move: w E F Heqn EneF. +refine (@ltn_ind (fun n => forall (w : L) (E F : {subfield L}), n = \dim_E F -> ((E : {vspace L}) != F)%VS -> (n`_[char L]^').-primitive_root w -> w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F) _ n). +move: n => _ n IHn w E F dimEF EneF wroot wE galEF /[dup] cycEF /cyclicP[g GE]. +have ggen : generator ('Gal(F / E))%g g by rewrite GE generator_cycle. +have ggal : g \in ('Gal(F / E))%g by rewrite GE cycle_id. +have EF := galois_subW galEF. +have n_gt0: (0 < n)%N by rewrite dimEF divn_gt0 ?adim_gt0//; apply/dimvS. +have [k [a [k0 [aE [aF /rext_r arad]]]]]: exists (k : nat) (a : L), (0 < k)%N /\ a \notin E /\ a \in F /\ radical E a k. + case /boolP: (n%:R == (0 : L)) => [n0 | n_ne0]. + move:(natf0_char n_gt0 n0) => [p pchar]; exists p. + have /eqP: galTrace E F (-1) = 0. + rewrite/galTrace. + transitivity (\sum_(x in ('Gal(F / E))%g) (-1 : L)). + apply eq_bigr => x xgal. + by rewrite (fixed_gal EF) ?rpredN1. + move: n0 => /eqP n0. + by rewrite sumr_const -(galois_dim galEF) -dimEF -mulr_natl n0 mul0r. + have FN1: -1 \in F by rewrite rpredN1. + move=>/(Hilbert's_theorem_90_additive galEF ggen FN1) [a] aF /(congr1 (@GRing.opp L))/(congr1 (GRing.add a)). + rewrite opprK opprB addrCA subrr addr0 => /esym ga. + have apF: a ^+ p - a \in F by rewrite rpredB// rpredX. + have: a ^+ p - a \in fixedField ('Gal(F / E))%g. + apply/fixedFieldP => //. + move=> x; rewrite GE => /cycleP[+ ->]; elim => [|m IHm]. + by rewrite expg0 gal_id. + rewrite expgSr galM// IHm rmorphB/= rmorphX/= ga. + rewrite -(Frobenius_autE pchar (a+1)) rmorphD/= (Frobenius_autE pchar a). + by rewrite rmorph1 opprD addrACA subrr addr0. + move:(galEF) => /galois_fixedField -> apE. + case /boolP: (a \in E) => aE. + move: ga; rewrite (fixed_gal EF)//. + move=> /(congr1 (fun x => x-a))/esym/eqP. + by rewrite addrAC subrr add0r oner_eq0. + exists a; repeat split => //. + by move:pchar => /andP [/prime_gt0]. + by apply/orP; right; apply/andP. + move:(n_ne0) wroot => /negPf; rewrite natf0_partn//. + move=>/negbT; rewrite negbK => /eqP/(congr1 (fun x => (x * n`_[char L]^'))%N). + rewrite mul1n partnC => // <- wroot. + exists n. + have HT90g := Hilbert's_theorem_90 ggen (subvP EF _ wE). + have /eqP/HT90g[x [xF xN0]] : galNorm E F w = 1. + rewrite /galNorm; under eq_bigr => g' g'G. rewrite (fixed_gal EF g'G)//. over. + by rewrite prodr_const -galois_dim// -dimEF (prim_expr_order wroot). + have gxN0 : g x != 0 by rewrite fmorph_eq0. + have wN0 : w != 0. rewrite (primitive_root_eq0 wroot) -lt0n //. + move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. + have gXx i : (g ^+ i)%g x = w ^- i * x. + elim: i => [|i IHi]. + by rewrite expg0 expr0 invr1 mul1r gal_id. + rewrite expgSr exprSr invfM galM// IHi rmorphM/= gx mulrA. + by rewrite (fixed_gal EF ggal) ?rpredV ?rpredX. + exists x; repeat split=>//. + - apply/negP=>xE. + move:gx; rewrite (fixed_gal EF)// => /(congr1 (fun y => w * y / x)). + rewrite mulrA -2!mulrA mulfV// 2!mulr1 mulfV// => w1; subst w. + move:wroot; rewrite prim_root1 => /eqP n1; subst n. + move:n1 => /eqP; rewrite -eqn_mul ?adim_gt0 ?(field_dimS EF)// mul1n => /eqP dimEFe. + by move:EneF => /negP; apply => /=; rewrite eqEdim EF dimEFe leqnn. + - apply/orP; left; apply/andP; split. + apply/negP => /eqP n0. + by move: n_ne0; rewrite -scaler_nat n0 scale0r eqxx. + move:galEF => /galois_fixedField <-; apply/fixedFieldP. + by apply rpredX. + rewrite GE => + /cycleP [i ->] => _. + by rewrite rmorphX/= gXx exprMn exprVn exprAC (prim_expr_order wroot)// expr1n invr1 mul1r. +apply (rext_trans arad). +have gala: galois <> F. + refine (galoisS _ galEF); apply/andP; split; first by apply subv_adjoin. + by apply/FadjoinP; split=>//; apply/galois_subW. +have dimEaF: (\dim_(<>) F < n)%N. + rewrite dimEF ltn_divRL; last by apply/field_dimS/galois_subW. + rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. + rewrite ltn_divLR ?adim_gt0// mulnC ltn_mul2l adim_gt0/=. + rewrite ltnNge; apply/negP => dimE. + move:(eqEdim E <>); rewrite dimE subv_adjoin/= => /eqP EE. + by move: aE; rewrite EE memv_adjoin. +case /boolP: (<>%AS == F) => [FE | Fne]. + move:FE => /eqP ->; apply rext_refl. +apply (IHn _ dimEaF (w ^+ (n`_[char L]^' %/ (\dim_(<>) F)`_[char L]^')%N)) => //. +- rewrite dvdn_prim_root// partn_dvd//. + rewrite dimEF dvdn_divRL; last by apply/field_dimS/galois_subW. + rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. + rewrite dvdn_divLR ?adim_gt0//. + by rewrite mulnC dvdn_mul//; apply/field_dimS/subv_adjoin. + by apply dvdn_mull; apply/field_dimS/FadjoinP; rewrite EF aF. +- by apply/rpredX/subvP_adjoin. +- exact (cyclicS (galS F (subv_adjoin E a)) cycEF). Qed. Lemma solvableWradical_ext w E F (n := \dim_E F) : - n.-primitive_root w -> w \in E -> galois E F -> + (n`_[char L]^').-primitive_root w -> w \in E -> galois E F -> solvable 'Gal(F / E) -> radical.-ext E F. Proof. move=> + + galEF; have [k] := ubnP n; elim: k => // k IHk in w E F n galEF *. rewrite ltnS => le_nk; have subEF : (E <= F)%VS by case/andP: galEF. move=> /[dup]/prim_root_natf_neq0 n_ne0. -have n_gt0: (0 < n)%N. - by rewrite lt0n; move: n_ne0; apply: contra_neq => ->. +have n_gt0: (0 < n)%N by rewrite divn_gt0 ?adim_gt0//; apply/dimvS. move=> wn Ew solEF; have [n_le1|n_gt1] := leqP n 1%N. have /eqP : n = 1%N by case: {+}n n_gt0 n_le1 => [|[]]. rewrite -eqn_mul ?adim_gt0 ?field_dimS// mul1n eq_sym dimv_leqif_eq//. @@ -412,38 +505,40 @@ pose d := \dim_E (fixedField H); pose p := \dim_(fixedField H) F. have p_gt0 : (p > 0)%N by rewrite divn_gt0 ?adim_gt0 ?dimvS ?fixedField_bound. have n_eq : n = (p * d)%N by rewrite /p /d -dim_fixedField dim_fixed_galois; rewrite ?Lagrange ?normal_sub -?galois_dim. -have Ewm : w ^+ (n %/ d) \in E by rewrite rpredX. +have Ewm : w ^+ (n`_[char L]^' %/ d`_[char L]^')%N \in E by rewrite rpredX. move=> /prime_cyclic/cyclic_radical_ext-/(_ _ _ Ewm galEH)/=. -rewrite dvdn_prim_root// => [/(_ isT)|]; last by rewrite n_eq dvdn_mull. -move=> /rext_trans; apply; apply: (IHk (w ^+ (n %/ p))) => /=. +rewrite -/d dvdn_prim_root// => [/(_ isT)|]; last by rewrite partn_dvd// n_eq dvdn_mull. +move=> /rext_trans; apply; apply: (IHk (w ^+ (n`_[char L]^' %/ p`_[char L]^'))) => /=. - exact: fixedField_galois. - rewrite (leq_trans _ le_nk)// -dim_fixedField /n galois_dim// proper_card//. by rewrite properEneq H_neq normal_sub. -- by rewrite dvdn_prim_root// n_eq dvdn_mulr. +- by rewrite -/p dvdn_prim_root// partn_dvd// n_eq dvdn_mulr. - by rewrite rpredX//; apply: subvP Ew. - by rewrite gal_fixedField (solvableS (normal_sub Hnormal)). Qed. +(* TODO : remove wprim *) Lemma galois_solvable_by_radical w E F (n := \dim_E F) : - n.-primitive_root w -> galois E F -> + (n`_[char L]^')%N.-primitive_root w -> galois E F -> solvable 'Gal(F / E) -> solvable_by radical E F. Proof. move=> w_root galEF solEF; have [EF Ew] := (galois_subW galEF, subv_adjoin E w). exists (F * <>)%AS; last by rewrite field_subvMr. apply: rext_trans (radicalext_Fadjoin_cyclotomic _ w_root) _. have galEwFEw: galois <> (F * <>) by apply: galois_prodvr galEF. -pose m := \dim_<> (F * <>); pose w' := w ^+ (n %/ m). +pose m := \dim_<> (F * <>); pose w' := w ^+ (n`_[char L]^' %/ m`_[char L]^')%N. have w'Ew : w' \in <>%VS by rewrite rpredX ?memv_adjoin. -have w'prim : m.-primitive_root w'. +have w'prim : (m`_[char L]^')%N.-primitive_root w'. rewrite dvdn_prim_root // /m /n !galois_dim//. - by rewrite (card_isog (galois_isog galEF _)) ?cardSg ?galS ?subv_cap ?EF//. + by rewrite (card_isog (galois_isog galEF _))// partn_dvd// cardSg ?galS ?subv_cap ?EF//. apply: (@solvableWradical_ext w'); rewrite // (isog_sol (galois_isog galEF _))//. by rewrite (solvableS _ solEF) ?galS// subv_cap EF. Qed. (* Main lemma of part 1 *) +(* TODO : remove wprim *) Lemma ext_solvable_by_radical w E F (n := \dim_E (normalClosure E F)) : - n.-primitive_root w -> solvable_ext E F -> solvable_by radical E F. + (n`_[char L]^')%N.-primitive_root w -> solvable_ext E F -> solvable_by radical E F. Proof. move=> wprim /andP[sepEF]; have galEF := normalClosure_galois sepEF. move=> /(galois_solvable_by_radical wprim galEF) [M EM EFM]; exists M => //. @@ -611,161 +706,22 @@ rewrite (@pradical_solvable p _ _ w)// ?memv_adjoin//. by rewrite (isog_sol (normalField_isog _ _ _)) ?galois_normalW ?subv_adjoin. Qed. -Section ArtinSchreier. -Variable (p : nat) (F0 : fieldType) (L : splittingFieldType F0). -Variable (E : {subfield L}) (x : L). -Hypothesis (pchar : p \in [char L]) (xpE : x ^+ p - x \in E). - -Let pprim : prime p. -Proof. by move: pchar=>/andP[]. Qed. - -Let p0 : p%:R == 0 :> L. -Proof. by move: pchar=>/andP[_]. Qed. - -Let p1 : (1 < p)%N. -Proof. by apply prime_gt1. Qed. - -Lemma ArtinScheier_factorize : - 'X^p - 'X - (x ^+ p - x)%:P = - \prod_(z <- [seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]) - ('X - z%:P). -Proof. -case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. -apply/eqP; rewrite -eqp_monic; first last. -- by apply monic_prod_XsubC. -- apply/monicP; rewrite -addrA -opprD lead_coefDl ?lead_coefXn//. - by rewrite size_opp size_XaddC size_polyXn ltnS. -- rewrite eqp_sym -dvdp_size_eqp. - rewrite big_map size_prod; last first. - move=> [i]/= _ _; apply/negP => /eqP - /(congr1 (fun p : {poly L} => size p)). - by rewrite size_XsubC size_polyC eqxx. - have ->: \big[addn/0%N]_(i < n.+1) size ('X - (x + (val i)%:R)%:P)%R = - \big[addn/0%N]_(i < n.+1) 2%N. - by apply eq_bigr=> i _; rewrite size_XsubC. - rewrite big_const_ord iter_addn_0. - rewrite -add1n mul2n -addnn addnA card_ord -addnBA// subnn addn0 add1n. - rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. - by move: pchar => /andP [ /prime_gt1 ]. - apply uniq_roots_dvdp. - apply/allP => + /mapP [i _ ->] => _. - rewrite/root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). - (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) - rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). - rewrite opprD opprB addrACA -addrA 2![x+_]addrA subrr add0r. - by rewrite addrAC addrCA subrr addr0 addrC subrr. - rewrite uniq_rootsE; apply/(uniqP 0) => i j. - rewrite 2!inE size_map => ilt jlt. - rewrite (nth_map ord0)// (nth_map ord0)// => /addrI/esym/eqP. - set ip := nth ord0 (index_enum (ordinal_finType n.+1)) i. - set jp := nth ord0 (index_enum (ordinal_finType n.+1)) j. - move=>ijE. - suff: jp = ip. - rewrite/ip/jp => /esym ijE0. - by move: (index_enum_uniq (ordinal_finType n.+1))=>/uniqP - /(_ i j ilt jlt ijE0). - move:ijE. - wlog ij : {i} {j} {ilt} {jlt} ip jp / (val ip <= val jp)%N. - move=> h. - move: (Order.TotalTheory.le_total (val ip) (val jp)) => /orP; case => ij. - by apply h. - by rewrite eq_sym=> ijE; apply /esym/h. - rewrite -subr_eq0 -natrB// -(dvdn_charf nchar). - case /posnP: (val jp - val ip)%N. - move=>/eqP; rewrite subn_eq0 => ji _; apply/val_inj/eqP. - by rewrite Order.POrderTheory.eq_le; apply/andP; split. - move=>ij0 /(dvdn_leq ij0); rewrite ltn_subRL -addnS. - move=>/(leq_trans (leq_addl _ _)). - have: (val jp < n.+1)%N by destruct jp. - by rewrite ltnS => jle; move => /(leq_ltn_trans jle); rewrite ltnn. -Qed. - -Lemma ArtinSchreier_splitting : - splittingFieldFor E ('X^p - 'X - (x ^+ p - x)%:P) <>%AS. -Proof. -exists ([seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]). - by rewrite ArtinScheier_factorize big_map eqpxx. -apply/eqP; rewrite eqEsubv; apply/andP; split. - apply/Fadjoin_seqP; split; first by apply subv_adjoin. - move=>+ /mapP [i _ ->] => _. - apply (@rpredD _ _ (memv_addrPred <>%AS)); first by apply memv_adjoin. - by apply rpred_nat. -apply/FadjoinP; split; first by apply subv_adjoin_seq. -case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. -apply/seqv_sub_adjoin/mapP; exists ord0; first by apply mem_index_enum. -by rewrite addr0. -Qed. - -Lemma ArtinSchreier_polyOver : - 'X^p - 'X - (x ^+ p - x)%:P \is a polyOver E. -Proof. by rewrite rpredB ?polyOverC// rpredB ?rpredX// polyOverX. Qed. - -Lemma ArtinSchreier_galois : - galois E <>. +Lemma ArtinSchreier_solvable_ext (p : nat) (F0 : fieldType) (L : splittingFieldType F0) + (E : {subfield L}) (x : L) : + p \in [char L] -> + x ^+ p - x \in E -> x \notin E -> solvable_ext E <>. Proof. -apply/splitting_galoisField; exists ('X^p - 'X - (x ^+ p - x)%:P); split. -- exact ArtinSchreier_polyOver. -- rewrite/separable_poly derivB derivC subr0 derivB derivXn derivX -scaler_nat. - move: pchar; rewrite inE => /andP[_ /eqP ->]. - rewrite scale0r add0r. - apply/Bezout_eq1_coprimepP; exists (0, (-1)) => /=. - by rewrite mul0r add0r mulN1r opprK. -- by apply ArtinSchreier_splitting. -Qed. - -Lemma minPoly_ArtinSchreier : (x \notin E) -> - minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. -Proof. -move=> xE. -have /(minPoly_dvdp ArtinSchreier_polyOver): root ('X^p - 'X - (x ^+ p - x)%:P) x. - rewrite ArtinScheier_factorize root_prod_XsubC. - case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. - apply/mapP; exists ord0; first by rewrite mem_index_enum. - by rewrite addr0. -rewrite ArtinScheier_factorize big_map. -move=> /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last first. - by rewrite monic_prod// => i _; rewrite monic_XsubC. -have [{}m sm ->] := resize_mask m (index_enum (ordinal_finType p)). -set s := mask _ _ => /eqP mEx. -have [|smp_gt0] := posnP (size s). - case: s mEx => // /(congr1 (horner^~x))/esym/eqP. - by rewrite minPolyxx big_nil hornerC oner_eq0. -suff leq_pm : (p <= size s)%N. - move: mEx; suff /eqP->: s == index_enum (ordinal_finType p) by []. - rewrite -(geq_leqif (size_subseq_leqif _)) ?mask_subseq//. - by rewrite/index_enum; case: index_enum_key=>/=; rewrite -enumT size_enum_ord. -have /polyOverP/(_ (size s).-1%N) := minPolyOver E x; rewrite {}mEx. -have ->: \prod_(i <- s) ('X - (x + (val i)%:R)%:P) = \prod_(i <- [seq x + (val i)%:R | i <- s]) ('X - i%:P) by rewrite big_map. -rewrite -(size_map (fun i => x + (val i)%:R)) coefPn_prod_XsubC size_map -?lt0n// big_map. -rewrite memvN big_split/= big_const_seq count_predT iter_addr_0 => DE. -have sE: \sum_(i <- s) i%:R \in E by apply rpred_sum => i _; apply rpred_nat. -move:(rpredB DE sE) => {DE} {sE}. -rewrite -addrA subrr addr0 => xsE. -apply/negP => sltp. -have /coprimeP: coprime (size s) p. - by rewrite coprime_sym (prime_coprime _ pprim); apply/negP => /(dvdn_leq smp_gt0). -move=> /(_ smp_gt0) [[u v]]/= uv1. -have /ltnW vltu: (v * p < u * size s)%N by rewrite ltnNge -subn_eq0 uv1. -move:uv1 => /eqP; rewrite -(eqn_add2l (v * p)) addnBA// addnC -addnBA// subnn addn0 => /eqP sE. -move: xsE => /(rpredMn u); rewrite -mulrnA mulnC sE addn1 mulrS mulrnA -mulr_natr. -move: p0 => /eqP ->; rewrite mulr0 addr0. -by move: xE => /negP. -Qed. - -Lemma ArtinSchreier_solvable_ext : - x \notin E -> solvable_ext E <>. -Proof. -move=> xE. +move=> pchar xpE xE. apply/solvable_extP; exists <>%AS; rewrite subvv/=. -rewrite ArtinSchreier_galois/=. +rewrite (ArtinSchreier_galois pchar xpE)/=. apply/abelian_sol/cyclic_abelian/prime_cyclic. -rewrite -(galois_dim ArtinSchreier_galois) -adjoin_degreeE. -rewrite (pred_Sn (adjoin_degree E x)) -size_minPoly minPoly_ArtinSchreier//. -by rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. +rewrite -(galois_dim (ArtinSchreier_galois pchar xpE)) -adjoin_degreeE. +rewrite (pred_Sn (adjoin_degree E x)) -size_minPoly (minPoly_ArtinSchreier pchar)//. +move: pchar => /andP[pprim _]. +rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. +by apply prime_gt1. Qed. -End ArtinSchreier. - Lemma radical_ext_solvable_ext (F0 : fieldType) (L : splittingFieldType F0) (E F : {subfield L}) : (E <= F)%VS -> solvable_by radical E F -> solvable_ext E F. @@ -796,8 +752,8 @@ Qed. (** Ok **) Lemma AbelGalois (F0 : fieldType) (L : splittingFieldType F0) (w : L) - (E F : {subfield L}) : (E <= F)%VS -> - (\dim_E (normalClosure E F)).-primitive_root w -> + (E F : {subfield L}) (n := \dim_E (normalClosure E F)) : (E <= F)%VS -> + (n`_[char L]^')%N.-primitive_root w -> solvable_by radical E F <-> solvable_ext E F. Proof. move=> EF wprim; split; first exact: radical_ext_solvable_ext. @@ -825,9 +781,12 @@ by move=> /and3P[EF sEF nEF]; rewrite /solvable_ext sEF normalClosure_id. Qed. Lemma normal_solvable (F0 : fieldType) (L : splittingFieldType F0) - (E F : {subfield L}) : has_char0 L -> + (E F : {subfield L}) : separable E F -> (E <= F)%VS -> normalField E F -> solvable_ext E F = solvable 'Gal(F / E). -Proof. by move=> charL EF /(char0_galois charL EF)/galois_solvable. Qed. +Proof. +move=> /normalClosure_galois /[swap] EF /[swap] /(normalClosure_id EF) ->. +by apply: galois_solvable. +Qed. Lemma AbelGaloisPoly (F : fieldType) (p : {poly F}) : has_char0 F -> solvable_ext_poly p <-> solvable_by_radical_poly p. @@ -837,8 +796,11 @@ move=> charF; split=> + L rs pE => [/(_ L rs pE) + w w_prim|solrs]/=. have normal_rs : normalField 1 <<1 & rs>>. apply/splitting_normalField; rewrite ?sub1v//. by exists (p ^^ in_alg _); [apply/polyOver1P; exists p | exists rs]. - by move=> solrs; apply/(@AbelGalois _ _ w); - rewrite ?char0_solvable_extE ?normalClosure_id ?sub1v ?dimv1 ?divn1. + move=> solrs; apply/(@AbelGalois _ _ w); + rewrite ?char0_solvable_extE ?normalClosure_id ?sub1v ?dimv1 ?divn1//. + rewrite (eq_partn _ (eq_negn charL)). + move:(partnC pred0 (adim_gt0 <<1 & rs >>%AS)). + rewrite{1}/partn big_pred0// mul1n => ->//. have charL : has_char0 L by move=> i; rewrite char_lalg. have seprs: separable 1 <<1 & rs>> by apply/char0_separable. have normal_rs : normalField 1 <<1 & rs>>. @@ -854,7 +816,10 @@ have charL' : [char L'] =i pred0 by move=> i; rewrite char_lalg. apply/(@AbelGalois _ _ w) => //. - by rewrite limgS// sub1v. - rewrite -aimg_normalClosure //= aimg1 dimv1 divn1 dim_aimg/=. - by rewrite normalClosure_id ?dimv1 ?divn1 ?sub1v//. + rewrite normalClosure_id ?dimv1 ?divn1 ?sub1v//. + rewrite (eq_partn _ (eq_negn charL')). + move:(partnC pred0 (adim_gt0 <<1 & rs >>%AS)). + by rewrite{1}/partn big_pred0// mul1n => ->//. have /= := solrs L' (map iota rs) _ w. rewrite -(aimg1 iota) -!aimg_adjoin_seq dim_aimg. apply => //; have := pE; rewrite -(eqp_map [rmorphism of iota]). From e5b4036167e2a410e88df410d4948d398dbcb0c2 Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Sat, 22 Apr 2023 14:24:06 +0200 Subject: [PATCH 06/14] comments --- theories/xmathcomp/artin_scheier.v | 28 +++++----- theories/xmathcomp/temp.v | 83 ++++++++++++++---------------- 2 files changed, 52 insertions(+), 59 deletions(-) diff --git a/theories/xmathcomp/artin_scheier.v b/theories/xmathcomp/artin_scheier.v index e5fc917..91e7fd5 100644 --- a/theories/xmathcomp/artin_scheier.v +++ b/theories/xmathcomp/artin_scheier.v @@ -26,9 +26,7 @@ Let p1 : (1 < p)%N. Proof. by apply prime_gt1. Qed. Lemma ArtinScheier_factorize : - 'X^p - 'X - (x ^+ p - x)%:P = - \prod_(z <- [seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]) - ('X - z%:P). + 'X^p - 'X - (x ^+ p - x)%:P = \prod_(i < p) ('X - (x + i%:R)%:P). Proof. case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. apply/eqP; rewrite -eqp_monic; first last. @@ -36,7 +34,7 @@ apply/eqP; rewrite -eqp_monic; first last. - apply/monicP; rewrite -addrA -opprD lead_coefDl ?lead_coefXn//. by rewrite size_opp size_XaddC size_polyXn ltnS. - rewrite eqp_sym -dvdp_size_eqp. - rewrite big_map size_prod; last first. + rewrite size_prod; last first. move=> [i]/= _ _; apply/negP => /eqP /(congr1 (fun p : {poly L} => size p)). by rewrite size_XsubC size_polyC eqxx. @@ -47,13 +45,14 @@ apply/eqP; rewrite -eqp_monic; first last. rewrite -add1n mul2n -addnn addnA card_ord -addnBA// subnn addn0 add1n. rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. by move: pchar => /andP [ /prime_gt1 ]. - apply uniq_roots_dvdp. + have: all (root ('X^n.+1 - 'X - (x ^+ n.+1 - x)%:P)) [seq (x + (val i)%:R) | i <- index_enum (ordinal_finType n.+1)]. apply/allP => + /mapP [i _ ->] => _. rewrite/root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). - rewrite opprD opprB addrACA -addrA 2![x+_]addrA subrr add0r. + rewrite opprB opprD addrACA -addrA 2![x+_]addrA subrr add0r. by rewrite addrAC addrCA subrr addr0 addrC subrr. + move=>/uniq_roots_dvdp; rewrite big_map; apply. rewrite uniq_rootsE; apply/(uniqP 0) => i j. rewrite 2!inE size_map => ilt jlt. rewrite (nth_map ord0)// (nth_map ord0)// => /addrI/esym/eqP. @@ -117,25 +116,26 @@ Lemma minPoly_ArtinSchreier : (x \notin E) -> minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. Proof. move=> xE. +have pE: ('X^p - 'X - (x ^+ p - x)%:P) = \prod_(i <- [seq x + (val i)%:R | i : 'I_p]) ('X - i%:P). + by rewrite ArtinScheier_factorize big_map; apply congr_big => //; rewrite enumT. have /(minPoly_dvdp ArtinSchreier_polyOver): root ('X^p - 'X - (x ^+ p - x)%:P) x. - rewrite ArtinScheier_factorize root_prod_XsubC. + rewrite pE root_prod_XsubC. case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. - apply/mapP; exists ord0; first by rewrite mem_index_enum. + apply/mapP; exists ord0; first by rewrite enumT mem_index_enum. by rewrite addr0. -rewrite ArtinScheier_factorize big_map. -move=> /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last first. +rewrite pE => /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last first. by rewrite monic_prod// => i _; rewrite monic_XsubC. -have [{}m sm ->] := resize_mask m (index_enum (ordinal_finType p)). +rewrite -map_mask. +have [{}m sm ->] := resize_mask m (enum 'I_p). set s := mask _ _ => /eqP mEx. have [|smp_gt0] := posnP (size s). case: s mEx => // /(congr1 (horner^~x))/esym/eqP. by rewrite minPolyxx big_nil hornerC oner_eq0. suff leq_pm : (p <= size s)%N. - move: mEx; suff /eqP->: s == index_enum (ordinal_finType p) by []. + move: mEx; suff /eqP->: s == enum 'I_p by []. rewrite -(geq_leqif (size_subseq_leqif _)) ?mask_subseq//. - by rewrite/index_enum; case: index_enum_key=>/=; rewrite -enumT size_enum_ord. + by rewrite/index_enum; case: index_enum_key=>/=; rewrite size_enum_ord. have /polyOverP/(_ (size s).-1%N) := minPolyOver E x; rewrite {}mEx. -have ->: \prod_(i <- s) ('X - (x + (val i)%:R)%:P) = \prod_(i <- [seq x + (val i)%:R | i <- s]) ('X - i%:P) by rewrite big_map. rewrite -(size_map (fun i => x + (val i)%:R)) coefPn_prod_XsubC size_map -?lt0n// big_map. rewrite memvN big_split/= big_const_seq count_predT iter_addr_0 => DE. have sE: \sum_(i <- s) i%:R \in E by apply rpred_sum => i _; apply rpred_nat. diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v index a2be78c..19fe799 100644 --- a/theories/xmathcomp/temp.v +++ b/theories/xmathcomp/temp.v @@ -13,13 +13,6 @@ Local Open Scope ring_scope. Section Temp. -Lemma ord_S_split n (i: 'I_n.+1): {j: 'I_n | i = lift ord0 j} + {i = ord0}. -Proof. -case: i; case=>[| i] ilt. - by right; apply val_inj. -by left; exists (Ordinal (ltnSE ilt)); apply val_inj. -Qed. - (* NB : rpredM and mulrPred uses that 1 is in the subset, which is useless. Predicates should be defined for {aspace aT}. *) Lemma memv_mulr_2closed [K : fieldType] [aT : FalgType K] (U : {aspace aT}) : GRing.mulr_2closed U. @@ -41,22 +34,23 @@ Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] ( (U : {subfield K}) (x : K) : {in U, f =1 g} -> f x = g x -> {in <>%VS, f =1 g}. Proof. -move=>fgU fgx y /Fadjoin_poly_eq <-. -move:(Fadjoin_polyOver U x y); generalize (Fadjoin_poly U x y) => p /polyOverP pU. +move=> fgU fgx y /Fadjoin_poly_eq <-. +move: (Fadjoin_poly U x y) (Fadjoin_polyOver U x y) => p /polyOverP pU. rewrite -(coefK p) horner_poly 2!rmorph_sum/=; apply eq_bigr => i _. by rewrite 2!rmorphM /= fgU// 2!rmorphX/= fgx. Qed. Lemma ahom_eq_adjoin_seq [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] (f g : 'AHom(K, rT)) (U : {aspace K}) (xs : seq K) : - {in U, f =1 g} -> all (fun x => f x == g x) xs -> {in <>%VS, f =1 g}. + {in U, f =1 g} -> {in xs, forall x, f x = g x} -> {in <>%VS, f =1 g}. Proof. elim: xs U => [|x xs IHxs] U fgU fgxs. by rewrite adjoin_nil subfield_closed. rewrite adjoin_cons. have ->: <>%VS = ASpace (agenv_is_aspace <>%VS) by rewrite /= agenv_id. -move: fgxs (IHxs (ASpace (agenv_is_aspace <>))) => /andP[/eqP fgx fgxs] /=. -by rewrite agenv_id => /(_ (ahom_eq_adjoin fgU fgx) fgxs). +move: fgxs (IHxs (ASpace (agenv_is_aspace <>))) => fgxs /=. +rewrite agenv_id; apply; first by apply/ahom_eq_adjoin/fgxs=>//; apply mem_head. +by move=>a axs; apply fgxs; rewrite in_cons axs orbT. Qed. Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. @@ -67,13 +61,13 @@ rewrite -{2}(subfield_closed U) (agenvEr U) subfield_closed. by congr (1 + _)%VS; apply/esym/field_module_eq; rewrite sup_field_module. Qed. -Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f g : FinGroup.finType (gal_finGroupType E)) : f = g \/ exists x, x \in E /\ f x != g x. +Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f g : gal_of E) : f = g \/ exists x, x \in E /\ f x != g x. Proof. move:(vbasisP E)=>/span_basis/agenv_span LE. -case/boolP: (all (fun x => f x == g x) (vbasis E)) => [fgE | /allPn[x] xE fgx]; [ left | right ]. +case/boolP: (all (fun x => f x == g x) (vbasis E)) => [/allP fgE | /allPn[x] xE fgx]; [ left | right ]. 2: by exists x; split=>//; apply vbasis_mem. apply/eqP/gal_eqP. -rewrite -{1}LE; apply ahom_eq_adjoin_seq=>//. +rewrite -{1}LE; apply ahom_eq_adjoin_seq=>//; last by move=>x /fgE/eqP. move:(gal1 f)(gal1 g). rewrite gal_kHom ?sub1v// gal_kHom ?sub1v// => /andP [_ /subvP f1] /andP [_ /subvP g1]. by move=>x /[dup] /f1/fixedSpaceP -> /g1/fixedSpaceP ->. @@ -82,7 +76,7 @@ Qed. Lemma tnth_cons (T : Type) (x : T) (l : seq T) (i : 'I_(size l)): tnth (in_tuple (x :: l)) (lift ord0 i) = tnth (in_tuple l) i. Proof. by rewrite/tnth/=; apply set_nth_default. Qed. -Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f : seq (FinGroup.finType (gal_finGroupType E))) (k : 'I_(size f) -> L) : uniq f -> (forall i, k i = 0) \/ (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). +Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f : seq (gal_of E)) (k : 'I_(size f) -> L) : uniq f -> (forall i, k i = 0) \/ (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). Proof. move:(Logic.eq_refl (size f)); generalize (size f) at 1 => n. elim: n f k => [|n IHn] f k fsize funiq. @@ -101,27 +95,30 @@ case: (gal_ne s s0) => [/eqP ss0E | [x [xE /negPf ss0x]]]. move:fsize=>/eqP; rewrite eqSS=>/eqP fsize. case: (IHn [:: s0 & f] (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) i x - s x))) fsize s0f). move=>/(_ ord0)/=/eqP; rewrite mulf_eq0 subr_eq0 [s0 x == _]eq_sym ss0x orbF => k10. - set k' := fun i : 'I_(size f).+1 => k (if ord_S_split i then lift ord0 i else ord0). + set k' := fun i : 'I_(size f).+1 => k + (match splitP (i : 'I_(1 + size f)%N) with + | SplitLo _ _ => ord0 + | SplitHi _ _ => lift ord0 i + end). move: (IHn [:: s & f] k' fsize). have /[swap]/[apply]: uniq (s :: f) by apply/andP; split. case => [k0 | [a [aE fne0]]]; [left => i | right; exists a]. case: i; case. move: (k0 ord0); rewrite/k'. - case: (ord_S_split _) => [[i /=/(congr1 val)//] | /= _ /[swap] ilt]. - by congr (k _ = 0); apply val_inj. + by case: splitP => // + _ + ilt => _; congr (k _ = 0); apply val_inj. case => [|i] ilt. by move: k10 => /eqP; congr (k _ = 0); apply val_inj. have ile: (i.+1 < (size f).+1)%N by rewrite -ltnS. move:(k0 (Ordinal ile)); rewrite/k'. - case: (ord_S_split _) => [/= _| /[dup]/(congr1 val)//]. + case: splitP => [[j]/=/[swap]<-// | /= _ _]. by congr (k _ = 0); apply val_inj. split=>//. move:k10 fne0 => /eqP k10. rewrite 3!big_ord_recl/= k10 mul0r add0r. congr (_ * _ + _ != 0). - by rewrite/k'; case: (ord_S_split _) => // [[i]] /=/(congr1 val). + by rewrite/k'; case: splitP => // [[i]] /=/(congr1 val). apply eq_bigr => i _; rewrite tnth_cons (@tnth_cons _ s (s0 :: f) (lift ord0 i)) tnth_cons; congr (_ * _). - by rewrite/k'; case: (ord_S_split _). + by rewrite/k'; case: splitP => // [[j]]/=/[swap]<-. move=>[y [yE fne0]]; right. case /boolP: (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) => [| yne0]. 2: by exists y. @@ -157,12 +154,14 @@ move=> a f IHf. by rewrite 2!big_cons ffunE IHf. Qed. - -Definition Zp_succ n (i : 'I_n) := Ordinal ( - match n with - | 0 => fun i0 : 'I_0 => match i0 with | @Ordinal _ _ i0 => i0 end - | n0.+1 => fun i0 => (ltn_pmod i0.+1 (is_true_true : (is_true (0 < n0.+1)%N))) - end i). +Definition Zp_succ n (i : 'I_n) := + match i with + | @Ordinal _ k klt => Ordinal ( + match n as n0 return (k < n0)%N -> (k.+1 %% n0 < n0)%N with + | 0 => id + | n0.+1 => fun=> ltn_pmod k.+1 (is_true_true : 0 < n0.+1)%N + end klt) + end. Lemma cycle_imset [gT : finGroupType] (g : gT) : <[g]>%g = @Imset.imset (ordinal_finType #[g]%g) (FinGroup.finType gT) (fun i => (g ^+ (val i))%g) (mem setT). Proof. @@ -192,7 +191,7 @@ Proof. by apply congr_big => // i; rewrite in_setT. Qed. Lemma Hilbert's_theorem_90_additive [F : fieldType] [L : splittingFieldType F] - [K E : {subfield L}] [x : gal_finGroupType E] + [K E : {subfield L}] [x : gal_of E] [a : L] : galois K E -> generator 'Gal(E / K) x -> @@ -320,30 +319,24 @@ have ->: ((if p \in primes m then p ^ logn p m else 1) = p ^ logn p m)%N. by rewrite -expnD subnK// vp_leq. Qed. -Lemma muln_gt0 [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : - all (fun n : I => P n ==> (0 < F n)%N) r -> - (0 < \prod_(n <- r | P n) F n)%N. -Proof. -elim: r => [|n r IHn /andP[Fn0 Fr0]]; first by rewrite big_nil. -rewrite big_cons; case /boolP: (P n) => Pn; last by apply IHn. -rewrite muln_gt0. -by move:Fn0; rewrite Pn/= IHn ?andbT. -Qed. - -Lemma logn_prod [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : - all (fun n : I => P n ==> (0 < F n)%N) r -> +Lemma logn_prod [I : eqType] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : + {in r, forall n, P n -> (0 < F n)%N} -> (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. Proof. -elim: r => [|n r IHn /andP[Fn0 Fr0]]; first by rewrite 2!big_nil logn1. +elim: r => [|n r IHn Fnr0]; first by rewrite 2!big_nil logn1. +have Fr0: {in r, forall n : I, P n -> (0 < F n)%N}. + by move=> i ir; apply Fnr0; rewrite in_cons ir orbT. rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply IHn. -move:Fn0; rewrite Pn => /= Fn0. -by rewrite lognM// ?muln_gt0// IHn. +move:(Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. +rewrite lognM// ?IHn//. +rewrite big_seq_cond big_mkcond prodn_gt0// => i. +by case /boolP: ((i \in r) && P i) => // /andP[/Fr0]. Qed. Lemma logn_partn (p n : nat) (pi : nat_pred) : logn p (n`_pi)%N = ((p \in pi) * logn p n)%N. Proof. -rewrite/partn logn_prod; last by apply/allP => i _; rewrite pfactor_gt0 implybT. +rewrite/partn logn_prod; last by move=> i _; rewrite pfactor_gt0. under eq_bigr do rewrite lognX. have logp (i : nat): (i == p) || (logn i n * logn p i == 0)%N. case /boolP: (i == p) => //= /negPf ip. From 484881283e3452722dd91bbe60d09f66940908b6 Mon Sep 17 00:00:00 2001 From: Quentin VERMANDE Date: Sat, 22 Apr 2023 22:25:42 +0200 Subject: [PATCH 07/14] remove has_char0 hypotheses --- theories/abel.v | 78 ++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 33e9a84..800fcc3 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -765,7 +765,7 @@ End Abel. Definition solvable_by_radical_poly (F : fieldType) (p : {poly F}) := forall (L : splittingFieldType F) (rs : seq L), p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> - forall w : L, (\dim <<1 & rs>>%VS).-primitive_root w -> + forall w : L, ((\dim <<1 & rs>>%VS)`_[char L]^')%N.-primitive_root w -> solvable_by radical 1 <<1 & rs>>. Definition solvable_ext_poly (F : fieldType) (p : {poly F}) := @@ -788,52 +788,49 @@ move=> /normalClosure_galois /[swap] EF /[swap] /(normalClosure_id EF) ->. by apply: galois_solvable. Qed. -Lemma AbelGaloisPoly (F : fieldType) (p : {poly F}) : has_char0 F -> +(* TODO: check if there is another way to write the first hypothesis. *) + +Lemma AbelGaloisPoly (F : fieldType) (p : {poly F}) : + (forall (L : splittingFieldType F) (rs : seq L), + p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> separable 1 <<1 & rs>>) -> solvable_ext_poly p <-> solvable_by_radical_poly p. Proof. -move=> charF; split=> + L rs pE => [/(_ L rs pE) + w w_prim|solrs]/=. - have charL : has_char0 L by move=> i; rewrite char_lalg. +move=>psep. +split=> + L rs pE => [/(_ L rs pE) + w w_prim|solrs]/=. have normal_rs : normalField 1 <<1 & rs>>. apply/splitting_normalField; rewrite ?sub1v//. by exists (p ^^ in_alg _); [apply/polyOver1P; exists p | exists rs]. - move=> solrs; apply/(@AbelGalois _ _ w); - rewrite ?char0_solvable_extE ?normalClosure_id ?sub1v ?dimv1 ?divn1//. - rewrite (eq_partn _ (eq_negn charL)). - move:(partnC pred0 (adim_gt0 <<1 & rs >>%AS)). - rewrite{1}/partn big_pred0// mul1n => ->//. -have charL : has_char0 L by move=> i; rewrite char_lalg. -have seprs: separable 1 <<1 & rs>> by apply/char0_separable. + move=> solrs; apply/(@AbelGalois _ _ w); rewrite ?normalClosure_id ?sub1v ?dimv1 ?divn1//. + by rewrite/solvable_ext normalClosure_id ?sub1v// solrs andbT psep. have normal_rs : normalField 1 <<1 & rs>>. apply/splitting_normalField; rewrite ?sub1v//. by exists (p ^^ in_alg _); [apply/polyOver1P; exists p | exists rs]. pose n := \dim <<1 & rs>>. -have nFN0 : n%:R != 0 :> F by have /charf0P-> := charF; rewrite -lt0n adim_gt0. -apply: (@classic_cycloSplitting _ L _ nFN0) => - [L' [w [iota wL' w_prim]]]. +apply: (@classic_cycloSplitting _ L _ (natf_partn_ne0 F n)) => - [L' [w [iota wL' w_prim]]]. suff: solvable_ext 1 <<1 & rs>>. - by rewrite /solvable_ext seprs normalClosure_id ?sub1v. + by rewrite /solvable_ext psep// normalClosure_id ?sub1v. rewrite -(solvable_ext_aimg iota). -have charL' : [char L'] =i pred0 by move=> i; rewrite char_lalg. +have nE: ((\dim <<1 & rs>>%AS)`_[char L']^' = n`_[char F]^')%N. + apply/eq_partn/eq_negn => x. + by rewrite -(char_lalg L); apply/fmorph_char/ahom_rmorphism. apply/(@AbelGalois _ _ w) => //. - by rewrite limgS// sub1v. - rewrite -aimg_normalClosure //= aimg1 dimv1 divn1 dim_aimg/=. - rewrite normalClosure_id ?dimv1 ?divn1 ?sub1v//. - rewrite (eq_partn _ (eq_negn charL')). - move:(partnC pred0 (adim_gt0 <<1 & rs >>%AS)). - by rewrite{1}/partn big_pred0// mul1n => ->//. + by rewrite normalClosure_id ?sub1v// nE. have /= := solrs L' (map iota rs) _ w. rewrite -(aimg1 iota) -!aimg_adjoin_seq dim_aimg. apply => //; have := pE; rewrite -(eqp_map [rmorphism of iota]). -by rewrite -map_poly_comp/= (eq_map_poly (rmorph_alg _)) map_prod_XsubC. + by rewrite -map_poly_comp/= (eq_map_poly (rmorph_alg _)) map_prod_XsubC. +by rewrite nE. Qed. Lemma solvable_ext_polyP (F : fieldType) (p : {poly F}) : p != 0 -> - has_char0 F -> solvable_ext_poly p <-> classically (exists (L : splittingFieldType F) (rs : seq L), p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) /\ solvable 'Gal(<<1 & rs>> / 1)). Proof. -move=> p_neq0 charF; split => sol_p. +move=> p_neq0; split => sol_p. have FoE (v : F^o) : v = in_alg F^o v by rewrite /= /(_%:A)/= mulr1. apply: classic_bind (@classic_fieldExtFor _ _ (p : {poly F^o}) p_neq0). move=> [L [rs [iota rsf p_eq]]]; apply/classicW. @@ -848,8 +845,6 @@ apply: classic_bind (@classic_fieldExtFor _ _ (p : {poly F^o}) p_neq0). exists S, rs; split => //=; first by rewrite -(eq_map_poly iotaF). by apply: (sol_p S rs); rewrite -(eq_map_poly iotaF). move=> L rs prs; apply: sol_p => -[M [rs' [prs']]]. -have charL : has_char0 L by move=> n; rewrite char_lalg charF. -have charM : has_char0 M by move=> n; rewrite char_lalg charF. pose K := [fieldExtType F of subvs_of <<1 & rs>>%VS]. pose rsK := map (vsproj <<1 & rs>>%VS) rs. have pKrs : p ^^ in_alg K %= \prod_(x <- rsK) ('X - x%:P). @@ -880,22 +875,24 @@ by rewrite -imgg -(aimg1 g)/= -img_map_gal injm_sol ?map_gal_inj ?subsetT//. Qed. Lemma solvable_by_radical_polyP (F : fieldType) (p : {poly F}) : p != 0 -> - has_char0 F -> + (forall (L : splittingFieldType F) (rs : seq L), + p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> separable 1 <<1 & rs>>) -> solvable_by_radical_poly p <-> classically (exists (L : splittingFieldType F) (rs : seq L), p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) /\ solvable_by radical 1 <<1 & rs>>). Proof. -move=> p_neq0 charF0; +move=> p_neq0 psep; split => sol_p; last first. apply/AbelGaloisPoly => //; apply/solvable_ext_polyP => //. apply: classic_bind sol_p => -[L [rs [prs sol_p]]]; apply/classicW. exists L, rs; split => //; rewrite -galois_solvable. apply: radical_ext_solvable_ext; rewrite ?sub1v// => v. - have charL : has_char0 L by move=> n; rewrite char_lalg charF0. - rewrite char0_galois// ?sub1v//. - apply/splitting_normalField; rewrite ?sub1v//. - by exists (p ^^ in_alg _); [apply/polyOver1P; exists p | exists rs]. + move: (psep L rs prs) => /normalClosure_galois; congr galois. + apply normalClosure_id; first by rewrite sub1v. + apply/splitting_normalField; first by rewrite sub1v. + exists (p ^^ in_alg L); first by apply/polyOver1P; exists p. + by exists rs. have FoE (v : F^o) : v = in_alg F^o v by rewrite /= /(_%:A)/= mulr1. apply: classic_bind (@classic_fieldExtFor _ _ (p : {poly F^o}) p_neq0). move=> [L [rs [f rsf p_eq]]]. @@ -906,15 +903,16 @@ have splitL : SplittingField.axiom L. apply/eqP; rewrite eqEsubv sub1v andbT; apply/subvP => v. by move=> /memv_imgP[u _ ->]; rewrite fF/= rpredZ// rpred1. pose S := SplittingFieldType F L splitL. -pose d := \dim <<1 & (rs : seq S)>>. -have /classic_cycloSplitting-/(_ S) : d%:R != 0 :> F. - by have /charf0P-> := charF0; rewrite -lt0n adim_gt0. +pose d := ((\dim <<1 & (rs : seq S)>>)`_[char F]^')%N. +have /classic_cycloSplitting-/(_ S) : d%:R != 0 :> F by apply natf_partn_ne0. apply/classic_bind => -[C [w [g wg w_prim]]]; apply/classicW. have gf : g \o f =1 in_alg C by move=> v /=; rewrite fF rmorph_alg. have pgrs : p ^^ in_alg C %= \prod_(x <- [seq g i | i <- rs]) ('X - x%:P). by rewrite -(eq_map_poly gf) map_poly_comp/= -map_prod_XsubC eqp_map//. exists C, (map g rs); split => //=; apply: (sol_p C (map g rs) _ w) => //. -by rewrite -(aimg1 g) -aimg_adjoin_seq dim_aimg. +rewrite -(aimg1 g) -aimg_adjoin_seq dim_aimg. +move: w_prim; congr (_.-primitive_root w); apply/eq_partn/eq_negn => x. +by rewrite -(char_lalg C). Qed. Import GRing.Theory Order.Theory Num.Theory. @@ -958,7 +956,10 @@ have splitS : splittingFieldFor 1 (p ^^ in_alg S) fullv by exists rs. have splitS' : splittingFieldFor 1 (p ^^ in_alg S') <<1 & rs'>> by exists rs'. have [f /= imgf] := splitting_ahom splitS splitS'. exists S', iota', rs'; split => //. -by apply: (p_sol S' rs' prs' w); rewrite -imgf dim_aimg/= -rsf. +apply: (p_sol S' rs' prs' w); rewrite -imgf dim_aimg/= -rsf. +move:w_prim; congr (_.-primitive_root w). +rewrite -(partnC [char L'] d_gt0) (eq_partn _ (char_ext L')) -/d {1}/partn. +by rewrite -big_filter filter_pred0 big_nil mul1n. Qed. Lemma splitting_num_field (p : {poly rat}) : @@ -991,6 +992,7 @@ move=> p_neq0; split. by exists L, <<1 & rs>>%AS; first by exists rs. have charrat : [char rat] =i pred0 by exact: char_num. move=> [L [K [rs prs <-] solK]]; apply/solvable_by_radical_polyP => //. + by move=>L' rs' _; apply/char0_separable/char_ext. by apply/classicW; exists L, rs. Qed. @@ -1039,7 +1041,8 @@ apply: (equivP idP); rewrite -AbelGaloisPoly//. have [rs prs <-] := numfieldP p_neq0. split; last by move=> /(_ (numfield p) rs prs). move=> solp; apply/solvable_ext_polyP => //. -by apply/classicW; exists (numfield p); exists rs; split. + by apply/classicW; exists (numfield p); exists rs; split. +by move=>L rs _; apply/char0_separable/char_ext. Qed. Definition numfield_roots (p : {poly rat}) := @@ -1709,7 +1712,8 @@ have Cchar := Cchar => p_neq0; split. case: IHq => // fq fq_eq. exists (fq * fu + Base (Subvs ck))%algT => /=. by rewrite rmorphD rmorphM/= map_polyX map_polyC !hornerE fq_eq. -move=> mkalg; apply/solvable_by_radical_polyP => //=; first exact: char_num. +move=> mkalg; apply/solvable_by_radical_polyP => //=. + by move=>L rs _; apply/char0_separable/char_ext. have [/= rsalg pE] := closed_field_poly_normal (p ^^ (ratr : _ -> algC)). have {}pE : p ^^ ratr %= \prod_(z <- rsalg) ('X - z%:P). rewrite pE (eqp_trans (eqp_scale _ _)) ?eqpxx//. From 08606fce0f4d836d00bcf169b4a9badfbc8229eb Mon Sep 17 00:00:00 2001 From: qvermande Date: Thu, 8 Jun 2023 19:32:46 +0200 Subject: [PATCH 08/14] cleanup --- theories/abel.v | 294 +++++++++++++----------- theories/xmathcomp/artin_scheier.v | 101 +++++---- theories/xmathcomp/temp.v | 350 ++++++++++++++++------------- theories/xmathcomp/various.v | 26 +-- 4 files changed, 428 insertions(+), 343 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 800fcc3..73efdc9 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -1,12 +1,13 @@ From mathcomp Require Import all_ssreflect all_fingroup all_algebra. From mathcomp Require Import all_solvable all_field polyrcf. From Abel Require Import various classic_ext map_gal algR. -From Abel Require Import char0 cyclotomic_ext real_closed_ext artin_scheier temp. +From Abel Require Import char0 cyclotomic_ext real_closed_ext artin_scheier. +From Abel Require Import temp. (*****************************************************************************) (* We work inside a enclosing splittingFieldType L over a base field F0 *) (* *) -(* radical U x n := x is a radical elemen,ct of degree n over U *) +(* radical U x n := x is a radical element of degree n over U *) (* pradical U x p := x is a radical element of prime degree p over U *) (* r.-tower U e pw := e is a chain of elements of L such that *) (* forall i, r <> e`_i pw`_i *) @@ -71,14 +72,14 @@ Lemma radicalP U x n : reflect [\/ [/\ n%:R != 0 :> F0 & x ^+ n \in U] | [/\ n \in [char L] & x ^+ n - x \in U]] (radical U x n). -Proof. by apply(iffP orP); (case=>/andP h; [ left | right ]). Qed. +Proof. by apply: (iffP orP); (case=> /andP h; [ left | right ]). Qed. Lemma pradicalP U x p : reflect [\/ [/\ prime p, p%:R != 0 :> F0 & x ^+ p \in U] | [/\ p \in [char L] & x ^+ p - x \in U]] (pradical U x p). Proof. -by apply(iffP orP); (case=> h; [ left; apply/and3P | right; apply/andP ]). +by apply: (iffP orP); (case=> h; [ left; apply/and3P | right; apply/andP ]). Qed. Implicit Types r : {vspace L} -> L -> nat -> bool. @@ -129,25 +130,26 @@ Lemma prim_root_natf_neq0 (w : L) (n : nat) : n.-primitive_root w -> n%:R != (0 : F0). Proof. case: n => // n /andP[_ /forallP w1]. -rewrite natf_neq0; apply/andP; split=>//. +rewrite natf_neq0; apply/andP; split=> //. rewrite -(negbK (all _ _)) -has_predC. apply/negP => /hasP[p]; rewrite mem_primes => /and3P[p_prime _ /dvdnP][]. -case=>// m nE. +case=> // m nE. rewrite /negn inE negbK => /andP [_ p0]. -have: p \in [char L] by rewrite (char_lalg L) inE; apply/andP; split=>//. +have: p \in [char L] by rewrite (char_lalg L) inE; apply/andP; split=> //. move=> {p0} p_char. -move:(w1 (Ordinal (ltnSn n))) => /= /eqP. +move: (w1 (Ordinal (ltnSn n))) => /= /eqP. rewrite eqxx /root_of_unity /root !hornerE ?hornerXn. (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) rewrite nE exprM -(@expr1n _ p). -rewrite -(Frobenius_autE p_char (w ^+ m.+1)) -(Frobenius_autE p_char 1) subr_eq0=>/eqP/fmorph_inj wm1. +rewrite -(Frobenius_autE p_char (w ^+ m.+1)) -(Frobenius_autE p_char 1). +rewrite subr_eq0 => /eqP/fmorph_inj wm1. have mn: (m.+1 < n.+1)%N. - by rewrite nE; apply ltn_Pmulr=>//; apply prime_gt1. + by rewrite nE; apply: ltn_Pmulr => //; apply: prime_gt1. have: ((Ordinal (ltn_trans (ltnSn m) mn)).+1).-unity_root w. by rewrite /root_of_unity /root/= !hornerE ?hornerXn wm1 subrr. (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) -move:(w1 (Ordinal (ltn_trans (ltnSn m) mn))) => /eqP -> /= /eqP mnE. -by move:mn; rewrite mnE ltnn. +move: (w1 (Ordinal (ltn_trans (ltnSn m) mn))) => /eqP -> /= /eqP mnE. +by move: mn; rewrite mnE ltnn. Qed. Lemma rext_refl r (E : {subfield L}) : r.-ext E E. @@ -221,15 +223,15 @@ Proof. by move=> nL xnE; apply/rext_r/(pradical_Fadjoin2 nL xnE). Qed. Lemma pradicalext_radical n (x : L) (E : {subfield L}) : radical E x n -> pradical.-ext E << E; x >>%VS. Proof. -move=> /radicalP; case=>[[n_gt0] | [nL]] xnE; last first. - by apply (pradical_ext_Fadjoin2 nL xnE). +move=> /radicalP; case=> [[n_gt0] | [nL]] xnE; last first. + by apply: (pradical_ext_Fadjoin2 nL xnE). have [k] := ubnP n. elim: k => // k IHk in n x E n_gt0 xnE *; rewrite ltnS => lenk. have [prime_n|primeN_n] := boolP (prime n). by apply: (@pradical_ext_Fadjoin1 n). case/boolP: (2 <= n)%N; last first. case: n {lenk primeN_n} => [|[]]// in xnE n_gt0 * => _. - by move:n_gt0; rewrite eqxx. + by move: n_gt0; rewrite eqxx. suff ->: <>%VS = E by apply: rext_refl. by rewrite (Fadjoin_idP _). move: primeN_n => /primePn[|[d /andP[d_gt1 d_ltn] dvd_dn n_gt1]]. @@ -256,13 +258,13 @@ Qed. Lemma tower_sub r1 r2 n E (e : n.-tuple L) (pw : n.-tuple nat) : (forall U x n, r1 U x n -> r2 U x n) -> r1.-tower E e pw -> r2.-tower E e pw. -Proof. by move=> sub_r /forallP /= h; apply/forallP=> /= i; apply/sub_r/h. Qed. +Proof. by move=> sub_r /forallP /= h; apply/forallP => /= i; apply/sub_r/h. Qed. Lemma radical_pradical U x p : pradical U x p -> radical U x p. Proof. -move=>/pradicalP x_rad; apply/radicalP. -case:x_rad=>x_rad; last by right. -by case:x_rad=> prime_p xpU; left; split. +move=> /pradicalP x_rad; apply/radicalP. +case: x_rad => x_rad; last by right. +by case: x_rad => prime_p xpU; left; split. Qed. Lemma radicalext_pradicalext (E F : {subfield L}) : @@ -282,7 +284,7 @@ apply: (@rext_trans _ << E; tnth e 0 >>). by move/forallP/(_ ord0): Ee; rewrite take0 Fadjoin_nil. apply: (ih [tuple of behead e] [tuple of behead pw]) => /=; last first. by rewrite -adjoin_cons -drop1 (tnth_nth 0) -drop_nth 1?(drop0, size_tuple). -apply/forallP=> /= i; move/forallP/(_ (rshift 1 i)): Ee => /=. +apply/forallP => /= i; move/forallP/(_ (rshift 1 i)): Ee => /=. rewrite !(tnth_nth 0, tnth_nth 0%N) !nth_behead [_ (rshift 1 i)]/=. by rewrite -adjoin_cons takeD drop1 (take_nth 0) 1?size_tuple // take0. Qed. @@ -343,11 +345,11 @@ Lemma radical_aimg (F0 : fieldType) (L L' : splittingFieldType F0) (x : Falgebra.vect_ringType L) (n : nat) : radical (iota @: U) (iota x) n = radical U x n. Proof. -rewrite/radical (fmorph_char (ahom_rmorphism iota))/=-rmorphX/= -rmorphB/=. +rewrite /radical (fmorph_char (ahom_rmorphism iota))/=-rmorphX/= -rmorphB/=. have inE: forall y, iota y \in (iota @: U)%VS = (y \in U). - move=>y; apply/idP/idP. - by move=>/memv_imgP [u uU] /fmorph_inj ->. - by move=>/(memv_img iota). + move=> y; apply/idP/idP. + by move=> /memv_imgP [u uU] /fmorph_inj ->. + by move=> /(memv_img iota). by rewrite 2!inE. Qed. @@ -358,7 +360,7 @@ Lemma radical_tower_aimg (F0 : fieldType) (L L' : splittingFieldType F0) radical.-tower (ext_size e) E (ext_ep e) (ext_pw e). Proof. apply/forallP/forallP => tower i /=. - move:(tower i). + move: (tower i). by rewrite -map_take -aimg_adjoin_seq tnth_map radical_aimg. by rewrite -map_take -aimg_adjoin_seq tnth_map radical_aimg. Qed. @@ -368,7 +370,7 @@ Lemma radical_ext_aimg (F0 : fieldType) (L L' : splittingFieldType F0) radical.-ext (iota @: E) (iota @: F) <-> radical.-ext E F. Proof. split => [[]|[]] e tower img; last first. - exists (ExtData [tuple of [seq iota x | x <- ext_ep e]] (ext_pw e))=>/=. + exists (ExtData [tuple of [seq iota x | x <- ext_ep e]] (ext_pw e))=> /=. by rewrite radical_tower_aimg. by rewrite -aimg_adjoin_seq img. have /subset_limgP [f fF ef]: {subset (ext_ep e) <= (iota @: F)%VS}. @@ -378,7 +380,7 @@ set e' := ExtData (Tuple sizef) (ext_pw e). exists e'. rewrite -(radical_tower_aimg iota)/=. suff <-: ext_ep e = [tuple of [seq iota x | x <- ext_ep e']] by []. - by apply val_inj. + by apply: val_inj. apply/eqP; rewrite -(@eq_limg_ker0 _ _ _ iota) ?AHom_lker0// aimg_adjoin_seq/=. by rewrite -ef img. Qed. @@ -387,98 +389,114 @@ Section Part1. Variables (F0 : fieldType) (L : splittingFieldType F0). Implicit Types (E F K : {subfield L}) (w : L) (n : nat). -Lemma cyclic_radical_ext w E F : - ((\dim_E F)`_[char L]^').-primitive_root w -> w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F. +Lemma cyclic_radical_ext w E F : ((\dim_E F)`_[char L]^').-primitive_root w -> + w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F. Proof. case /boolP: (E == F :> {vspace L}) => [/eqP -> _ _ _ _ | EneF]. - by apply rext_refl. + by apply: rext_refl. remember (\dim_E F) as n. move: w E F Heqn EneF. -refine (@ltn_ind (fun n => forall (w : L) (E F : {subfield L}), n = \dim_E F -> ((E : {vspace L}) != F)%VS -> (n`_[char L]^').-primitive_root w -> w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F) _ n). +refine (@ltn_ind + (fun n => forall (w : L) (E F : {subfield L}), + n = \dim_E F -> + ((E : {vspace L}) != F)%VS -> + (n`_[char L]^').-primitive_root w -> + w \in E -> + galois E F -> + cyclic 'Gal(F / E) -> + radical.-ext E F) + _ n). move: n => _ n IHn w E F dimEF EneF wroot wE galEF /[dup] cycEF /cyclicP[g GE]. have ggen : generator ('Gal(F / E))%g g by rewrite GE generator_cycle. have ggal : g \in ('Gal(F / E))%g by rewrite GE cycle_id. have EF := galois_subW galEF. have n_gt0: (0 < n)%N by rewrite dimEF divn_gt0 ?adim_gt0//; apply/dimvS. -have [k [a [k0 [aE [aF /rext_r arad]]]]]: exists (k : nat) (a : L), (0 < k)%N /\ a \notin E /\ a \in F /\ radical E a k. - case /boolP: (n%:R == (0 : L)) => [n0 | n_ne0]. - move:(natf0_char n_gt0 n0) => [p pchar]; exists p. - have /eqP: galTrace E F (-1) = 0. - rewrite/galTrace. - transitivity (\sum_(x in ('Gal(F / E))%g) (-1 : L)). - apply eq_bigr => x xgal. - by rewrite (fixed_gal EF) ?rpredN1. - move: n0 => /eqP n0. - by rewrite sumr_const -(galois_dim galEF) -dimEF -mulr_natl n0 mul0r. - have FN1: -1 \in F by rewrite rpredN1. - move=>/(Hilbert's_theorem_90_additive galEF ggen FN1) [a] aF /(congr1 (@GRing.opp L))/(congr1 (GRing.add a)). - rewrite opprK opprB addrCA subrr addr0 => /esym ga. - have apF: a ^+ p - a \in F by rewrite rpredB// rpredX. - have: a ^+ p - a \in fixedField ('Gal(F / E))%g. - apply/fixedFieldP => //. - move=> x; rewrite GE => /cycleP[+ ->]; elim => [|m IHm]. - by rewrite expg0 gal_id. - rewrite expgSr galM// IHm rmorphB/= rmorphX/= ga. - rewrite -(Frobenius_autE pchar (a+1)) rmorphD/= (Frobenius_autE pchar a). - by rewrite rmorph1 opprD addrACA subrr addr0. - move:(galEF) => /galois_fixedField -> apE. - case /boolP: (a \in E) => aE. - move: ga; rewrite (fixed_gal EF)//. - move=> /(congr1 (fun x => x-a))/esym/eqP. - by rewrite addrAC subrr add0r oner_eq0. - exists a; repeat split => //. - by move:pchar => /andP [/prime_gt0]. - by apply/orP; right; apply/andP. - move:(n_ne0) wroot => /negPf; rewrite natf0_partn//. - move=>/negbT; rewrite negbK => /eqP/(congr1 (fun x => (x * n`_[char L]^'))%N). - rewrite mul1n partnC => // <- wroot. - exists n. - have HT90g := Hilbert's_theorem_90 ggen (subvP EF _ wE). - have /eqP/HT90g[x [xF xN0]] : galNorm E F w = 1. - rewrite /galNorm; under eq_bigr => g' g'G. rewrite (fixed_gal EF g'G)//. over. - by rewrite prodr_const -galois_dim// -dimEF (prim_expr_order wroot). - have gxN0 : g x != 0 by rewrite fmorph_eq0. - have wN0 : w != 0. rewrite (primitive_root_eq0 wroot) -lt0n //. - move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. - have gXx i : (g ^+ i)%g x = w ^- i * x. - elim: i => [|i IHi]. - by rewrite expg0 expr0 invr1 mul1r gal_id. - rewrite expgSr exprSr invfM galM// IHi rmorphM/= gx mulrA. - by rewrite (fixed_gal EF ggal) ?rpredV ?rpredX. - exists x; repeat split=>//. - - apply/negP=>xE. - move:gx; rewrite (fixed_gal EF)// => /(congr1 (fun y => w * y / x)). - rewrite mulrA -2!mulrA mulfV// 2!mulr1 mulfV// => w1; subst w. - move:wroot; rewrite prim_root1 => /eqP n1; subst n. - move:n1 => /eqP; rewrite -eqn_mul ?adim_gt0 ?(field_dimS EF)// mul1n => /eqP dimEFe. - by move:EneF => /negP; apply => /=; rewrite eqEdim EF dimEFe leqnn. - - apply/orP; left; apply/andP; split. - apply/negP => /eqP n0. - by move: n_ne0; rewrite -scaler_nat n0 scale0r eqxx. - move:galEF => /galois_fixedField <-; apply/fixedFieldP. - by apply rpredX. - rewrite GE => + /cycleP [i ->] => _. - by rewrite rmorphX/= gXx exprMn exprVn exprAC (prim_expr_order wroot)// expr1n invr1 mul1r. -apply (rext_trans arad). +have [k [a [k0 [aE [aF /rext_r arad]]]]]: + exists (k : nat) (a : L), (0 < k)%N /\ a \notin E /\ a \in F /\ radical E a k. + case /boolP: (n%:R == (0 : L)) => [n0 | n_ne0]. + move: (natf0_char n_gt0 n0) => [p pchar]; exists p. + have /eqP: galTrace E F (-1) = 0. + rewrite /galTrace. + transitivity (\sum_(x in ('Gal(F / E))%g) (-1 : L)). + apply: eq_bigr => x xgal. + by rewrite (fixed_gal EF) ?rpredN1. + move: n0 => /eqP n0. + by rewrite sumr_const -(galois_dim galEF) -dimEF -mulr_natl n0 mul0r. + have FN1: -1 \in F by rewrite rpredN1. + move=> /(Hilbert's_theorem_90_additive galEF ggen FN1) [a] aF. + move=> /(congr1 (@GRing.opp L))/(congr1 (GRing.add a)). + rewrite opprK opprB addrCA subrr addr0 => /esym ga. + have apF: a ^+ p - a \in F by rewrite rpredB// rpredX. + have: a ^+ p - a \in fixedField ('Gal(F / E))%g. + apply/fixedFieldP => //. + move=> x; rewrite GE => /cycleP[+ ->]; elim => [|m IHm]. + by rewrite expg0 gal_id. + rewrite expgSr galM// IHm rmorphB/= rmorphX/= ga. + rewrite -(Frobenius_autE pchar (a+1)) rmorphD/= (Frobenius_autE pchar a). + by rewrite rmorph1 opprD addrACA subrr addr0. + move: (galEF) => /galois_fixedField -> apE. + case /boolP: (a \in E) => aE. + move: ga; rewrite (fixed_gal EF)//. + move=> /(congr1 (fun x => x-a))/esym/eqP. + by rewrite addrAC subrr add0r oner_eq0. + exists a; repeat split => //. + by move: pchar => /andP [/prime_gt0]. + by apply/orP; right; apply/andP. + move: (n_ne0) wroot => /negPf; rewrite natf0_partn//. + move=> /negbT; rewrite negbK. + move=> /eqP/(congr1 (fun x => (x * n`_[char L]^'))%N). + rewrite mul1n partnC => // <- wroot. + exists n. + have HT90g := Hilbert's_theorem_90 ggen (subvP EF _ wE). + have /eqP/HT90g[x [xF xN0]] : galNorm E F w = 1. + rewrite /galNorm; under eq_bigr => g' g'G; + first by rewrite (fixed_gal EF g'G)//; over. + by rewrite prodr_const -galois_dim// -dimEF (prim_expr_order wroot). + have gxN0 : g x != 0 by rewrite fmorph_eq0. + have wN0 : w != 0. rewrite (primitive_root_eq0 wroot) -lt0n //. + move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. + have gXx i : (g ^+ i)%g x = w ^- i * x. + elim: i => [|i IHi]. + by rewrite expg0 expr0 invr1 mul1r gal_id. + rewrite expgSr exprSr invfM galM// IHi rmorphM/= gx mulrA. + by rewrite (fixed_gal EF ggal) ?rpredV ?rpredX. + exists x; repeat split=> //. + - apply/negP=> xE. + move: gx; rewrite (fixed_gal EF)// => /(congr1 (fun y => w * y / x)). + rewrite mulrA -2!mulrA mulfV// 2!mulr1 mulfV// => w1; subst w. + move: wroot; rewrite prim_root1 => /eqP n1; subst n. + move: n1 => /eqP; rewrite -eqn_mul ?adim_gt0 ?(field_dimS EF)//. + rewrite mul1n => /eqP dimEFe. + by move: EneF => /negP; apply => /=; rewrite eqEdim EF dimEFe leqnn. + - apply/orP; left; apply/andP; split. + apply/negP => /eqP n0. + by move: n_ne0; rewrite -scaler_nat n0 scale0r eqxx. + move: galEF => /galois_fixedField <-; apply/fixedFieldP. + by apply: rpredX. + rewrite GE => + /cycleP [i ->] => _. + rewrite rmorphX/= gXx exprMn exprVn exprAC (prim_expr_order wroot)//. + by rewrite expr1n invr1 mul1r. +apply: (rext_trans arad). have gala: galois <> F. - refine (galoisS _ galEF); apply/andP; split; first by apply subv_adjoin. - by apply/FadjoinP; split=>//; apply/galois_subW. + refine (galoisS _ galEF); apply/andP; split; first by apply: subv_adjoin. + by apply/FadjoinP; split=> //; apply/galois_subW. have dimEaF: (\dim_(<>) F < n)%N. - rewrite dimEF ltn_divRL; last by apply/field_dimS/galois_subW. - rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. - rewrite ltn_divLR ?adim_gt0// mulnC ltn_mul2l adim_gt0/=. - rewrite ltnNge; apply/negP => dimE. - move:(eqEdim E <>); rewrite dimE subv_adjoin/= => /eqP EE. - by move: aE; rewrite EE memv_adjoin. + rewrite dimEF ltn_divRL; last by apply/field_dimS/galois_subW. + rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. + rewrite ltn_divLR ?adim_gt0// mulnC ltn_mul2l adim_gt0/=. + rewrite ltnNge; apply/negP => dimE. + move: (eqEdim E <>); rewrite dimE subv_adjoin/= => /eqP EE. + by move: aE; rewrite EE memv_adjoin. case /boolP: (<>%AS == F) => [FE | Fne]. - move:FE => /eqP ->; apply rext_refl. -apply (IHn _ dimEaF (w ^+ (n`_[char L]^' %/ (\dim_(<>) F)`_[char L]^')%N)) => //. + move: FE => /eqP ->; apply: rext_refl. +apply: (IHn _ dimEaF + (w ^+ (n`_[char L]^' %/ (\dim_(<>) F)`_[char L]^')%N)) => //. - rewrite dvdn_prim_root// partn_dvd//. - rewrite dimEF dvdn_divRL; last by apply/field_dimS/galois_subW. - rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. - rewrite dvdn_divLR ?adim_gt0//. - by rewrite mulnC dvdn_mul//; apply/field_dimS/subv_adjoin. - by apply dvdn_mull; apply/field_dimS/FadjoinP; rewrite EF aF. + rewrite dimEF dvdn_divRL; last by apply/field_dimS/galois_subW. + rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. + rewrite dvdn_divLR ?adim_gt0//. + by rewrite mulnC dvdn_mul//; apply/field_dimS/subv_adjoin. + by apply/dvdn_mull/field_dimS/FadjoinP; rewrite EF aF. - by apply/rpredX/subvP_adjoin. - exact (cyclicS (galS F (subv_adjoin E a)) cycEF). Qed. @@ -507,8 +525,10 @@ have n_eq : n = (p * d)%N by rewrite /p /d -dim_fixedField dim_fixed_galois; rewrite ?Lagrange ?normal_sub -?galois_dim. have Ewm : w ^+ (n`_[char L]^' %/ d`_[char L]^')%N \in E by rewrite rpredX. move=> /prime_cyclic/cyclic_radical_ext-/(_ _ _ Ewm galEH)/=. -rewrite -/d dvdn_prim_root// => [/(_ isT)|]; last by rewrite partn_dvd// n_eq dvdn_mull. -move=> /rext_trans; apply; apply: (IHk (w ^+ (n`_[char L]^' %/ p`_[char L]^'))) => /=. +rewrite -/d dvdn_prim_root// => [/(_ isT)|]; + last by rewrite partn_dvd// n_eq dvdn_mull. +move=> /rext_trans; apply. +apply: (IHk (w ^+ (n`_[char L]^' %/ p`_[char L]^'))) => /=. - exact: fixedField_galois. - rewrite (leq_trans _ le_nk)// -dim_fixedField /n galois_dim// proper_card//. by rewrite properEneq H_neq normal_sub. @@ -526,19 +546,24 @@ move=> w_root galEF solEF; have [EF Ew] := (galois_subW galEF, subv_adjoin E w). exists (F * <>)%AS; last by rewrite field_subvMr. apply: rext_trans (radicalext_Fadjoin_cyclotomic _ w_root) _. have galEwFEw: galois <> (F * <>) by apply: galois_prodvr galEF. -pose m := \dim_<> (F * <>); pose w' := w ^+ (n`_[char L]^' %/ m`_[char L]^')%N. +pose m := \dim_<> (F * <>). +pose w' := w ^+ (n`_[char L]^' %/ m`_[char L]^')%N. have w'Ew : w' \in <>%VS by rewrite rpredX ?memv_adjoin. have w'prim : (m`_[char L]^')%N.-primitive_root w'. rewrite dvdn_prim_root // /m /n !galois_dim//. - by rewrite (card_isog (galois_isog galEF _))// partn_dvd// cardSg ?galS ?subv_cap ?EF//. -apply: (@solvableWradical_ext w'); rewrite // (isog_sol (galois_isog galEF _))//. + rewrite (card_isog (galois_isog galEF _))// partn_dvd//. + by rewrite cardSg ?galS ?subv_cap ?EF//. +apply: (@solvableWradical_ext w') => //. +rewrite (isog_sol (galois_isog galEF _))//. by rewrite (solvableS _ solEF) ?galS// subv_cap EF. Qed. (* Main lemma of part 1 *) (* TODO : remove wprim *) Lemma ext_solvable_by_radical w E F (n := \dim_E (normalClosure E F)) : - (n`_[char L]^')%N.-primitive_root w -> solvable_ext E F -> solvable_by radical E F. + (n`_[char L]^')%N.-primitive_root w -> + solvable_ext E F -> + solvable_by radical E F. Proof. move=> wprim /andP[sepEF]; have galEF := normalClosure_galois sepEF. move=> /(galois_solvable_by_radical wprim galEF) [M EM EFM]; exists M => //. @@ -706,10 +731,9 @@ rewrite (@pradical_solvable p _ _ w)// ?memv_adjoin//. by rewrite (isog_sol (normalField_isog _ _ _)) ?galois_normalW ?subv_adjoin. Qed. -Lemma ArtinSchreier_solvable_ext (p : nat) (F0 : fieldType) (L : splittingFieldType F0) - (E : {subfield L}) (x : L) : - p \in [char L] -> - x ^+ p - x \in E -> x \notin E -> solvable_ext E <>. +Lemma ArtinSchreier_solvable_ext (p : nat) (F0 : fieldType) + (L : splittingFieldType F0) (E : {subfield L}) (x : L) : p \in [char L] -> + x ^+ p - x \in E -> x \notin E -> solvable_ext E <>. Proof. move=> pchar xpE xE. apply/solvable_extP; exists <>%AS; rewrite subvv/=. @@ -719,7 +743,7 @@ rewrite -(galois_dim (ArtinSchreier_galois pchar xpE)) -adjoin_degreeE. rewrite (pred_Sn (adjoin_degree E x)) -size_minPoly (minPoly_ArtinSchreier pchar)//. move: pchar => /andP[pprim _]. rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. -by apply prime_gt1. +by apply: prime_gt1. Qed. Lemma radical_ext_solvable_ext (F0 : fieldType) (L : splittingFieldType F0) @@ -737,11 +761,11 @@ rewrite (take_nth 0) ?size_tuple// adjoin_rcons. apply: solvable_ext_trans IHsol _. by rewrite /= subv_adjoin_seq subv_adjoin. have := epwP (Ordinal kn); rewrite (tnth_nth 0) (tnth_nth 0%N)/=. -move=> /pradicalP; case=>[[pwk_prime] | [pwkL]] epwEk. +move=> /pradicalP; case=> [[pwk_prime] | [pwkL]] epwEk. by apply: (pradical_solvable_ext pwk_prime). case /boolP: (e`_k \in <>%VS). move=> /Fadjoin_idP ->; exact: solvable_ext_refl. -by apply (ArtinSchreier_solvable_ext pwkL). +by apply: (ArtinSchreier_solvable_ext pwkL). Qed. (******************************************************************************) @@ -773,6 +797,10 @@ Definition solvable_ext_poly (F : fieldType) (p : {poly F}) := p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> solvable 'Gal(<<1 & rs>> / 1). +Definition separable_splittingField (F : fieldType) (p : {poly F}) := + forall (L : splittingFieldType F) (rs : seq L), + p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> separable 1 <<1 & rs>>. + Lemma galois_solvable (F0 : fieldType) (L : splittingFieldType F0) (E F : {subfield L}) : galois E F -> solvable_ext E F = solvable 'Gal(F / E). @@ -791,22 +819,23 @@ Qed. (* TODO: check if there is another way to write the first hypothesis. *) Lemma AbelGaloisPoly (F : fieldType) (p : {poly F}) : - (forall (L : splittingFieldType F) (rs : seq L), - p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> separable 1 <<1 & rs>>) -> + separable_splittingField p -> solvable_ext_poly p <-> solvable_by_radical_poly p. Proof. -move=>psep. +move=> psep. split=> + L rs pE => [/(_ L rs pE) + w w_prim|solrs]/=. have normal_rs : normalField 1 <<1 & rs>>. apply/splitting_normalField; rewrite ?sub1v//. by exists (p ^^ in_alg _); [apply/polyOver1P; exists p | exists rs]. - move=> solrs; apply/(@AbelGalois _ _ w); rewrite ?normalClosure_id ?sub1v ?dimv1 ?divn1//. - by rewrite/solvable_ext normalClosure_id ?sub1v// solrs andbT psep. + move=> solrs; apply/(@AbelGalois _ _ w); + rewrite ?normalClosure_id ?sub1v ?dimv1 ?divn1//. + by rewrite /solvable_ext normalClosure_id ?sub1v// solrs andbT psep. have normal_rs : normalField 1 <<1 & rs>>. apply/splitting_normalField; rewrite ?sub1v//. by exists (p ^^ in_alg _); [apply/polyOver1P; exists p | exists rs]. pose n := \dim <<1 & rs>>. -apply: (@classic_cycloSplitting _ L _ (natf_partn_ne0 F n)) => - [L' [w [iota wL' w_prim]]]. +apply: (@classic_cycloSplitting _ L _ (natf_partn_ne0 F n)). +move=> - [L' [w [iota wL' w_prim]]]. suff: solvable_ext 1 <<1 & rs>>. by rewrite /solvable_ext psep// normalClosure_id ?sub1v. rewrite -(solvable_ext_aimg iota). @@ -875,8 +904,7 @@ by rewrite -imgg -(aimg1 g)/= -img_map_gal injm_sol ?map_gal_inj ?subsetT//. Qed. Lemma solvable_by_radical_polyP (F : fieldType) (p : {poly F}) : p != 0 -> - (forall (L : splittingFieldType F) (rs : seq L), - p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> separable 1 <<1 & rs>>) -> + separable_splittingField p -> solvable_by_radical_poly p <-> classically (exists (L : splittingFieldType F) (rs : seq L), p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) /\ @@ -889,7 +917,7 @@ split => sol_p; last first. exists L, rs; split => //; rewrite -galois_solvable. apply: radical_ext_solvable_ext; rewrite ?sub1v// => v. move: (psep L rs prs) => /normalClosure_galois; congr galois. - apply normalClosure_id; first by rewrite sub1v. + apply: normalClosure_id; first by rewrite sub1v. apply/splitting_normalField; first by rewrite sub1v. exists (p ^^ in_alg L); first by apply/polyOver1P; exists p. by exists rs. @@ -904,7 +932,7 @@ have splitL : SplittingField.axiom L. by move=> /memv_imgP[u _ ->]; rewrite fF/= rpredZ// rpred1. pose S := SplittingFieldType F L splitL. pose d := ((\dim <<1 & (rs : seq S)>>)`_[char F]^')%N. -have /classic_cycloSplitting-/(_ S) : d%:R != 0 :> F by apply natf_partn_ne0. +have /classic_cycloSplitting-/(_ S) : d%:R != 0 :> F by apply: natf_partn_ne0. apply/classic_bind => -[C [w [g wg w_prim]]]; apply/classicW. have gf : g \o f =1 in_alg C by move=> v /=; rewrite fF rmorph_alg. have pgrs : p ^^ in_alg C %= \prod_(x <- [seq g i | i <- rs]) ('X - x%:P). @@ -957,7 +985,7 @@ have splitS' : splittingFieldFor 1 (p ^^ in_alg S') <<1 & rs'>> by exists rs'. have [f /= imgf] := splitting_ahom splitS splitS'. exists S', iota', rs'; split => //. apply: (p_sol S' rs' prs' w); rewrite -imgf dim_aimg/= -rsf. -move:w_prim; congr (_.-primitive_root w). +move: w_prim; congr (_.-primitive_root w). rewrite -(partnC [char L'] d_gt0) (eq_partn _ (char_ext L')) -/d {1}/partn. by rewrite -big_filter filter_pred0 big_nil mul1n. Qed. @@ -992,7 +1020,7 @@ move=> p_neq0; split. by exists L, <<1 & rs>>%AS; first by exists rs. have charrat : [char rat] =i pred0 by exact: char_num. move=> [L [K [rs prs <-] solK]]; apply/solvable_by_radical_polyP => //. - by move=>L' rs' _; apply/char0_separable/char_ext. + by move=> L' rs' _; apply/char0_separable/char_ext. by apply/classicW; exists L, rs. Qed. @@ -1042,7 +1070,7 @@ have [rs prs <-] := numfieldP p_neq0. split; last by move=> /(_ (numfield p) rs prs). move=> solp; apply/solvable_ext_polyP => //. by apply/classicW; exists (numfield p); exists rs; split. -by move=>L rs _; apply/char0_separable/char_ext. +by move=> L rs _; apply/char0_separable/char_ext. Qed. Definition numfield_roots (p : {poly rat}) := @@ -1713,7 +1741,7 @@ have Cchar := Cchar => p_neq0; split. exists (fq * fu + Base (Subvs ck))%algT => /=. by rewrite rmorphD rmorphM/= map_polyX map_polyC !hornerE fq_eq. move=> mkalg; apply/solvable_by_radical_polyP => //=. - by move=>L rs _; apply/char0_separable/char_ext. + by move=> L rs _; apply/char0_separable/char_ext. have [/= rsalg pE] := closed_field_poly_normal (p ^^ (ratr : _ -> algC)). have {}pE : p ^^ ratr %= \prod_(z <- rsalg) ('X - z%:P). rewrite pE (eqp_trans (eqp_scale _ _)) ?eqpxx//. diff --git a/theories/xmathcomp/artin_scheier.v b/theories/xmathcomp/artin_scheier.v index 91e7fd5..021011a 100644 --- a/theories/xmathcomp/artin_scheier.v +++ b/theories/xmathcomp/artin_scheier.v @@ -17,20 +17,20 @@ Variable (E : {subfield L}) (x : L). Hypothesis (pchar : p \in [char L]) (xpE : x ^+ p - x \in E). Let pprim : prime p. -Proof. by move: pchar=>/andP[]. Qed. +Proof. by move: pchar => /andP[]. Qed. Let p0 : p%:R == 0 :> L. -Proof. by move: pchar=>/andP[_]. Qed. +Proof. by move: pchar => /andP[_]. Qed. Let p1 : (1 < p)%N. -Proof. by apply prime_gt1. Qed. +Proof. by apply: prime_gt1. Qed. Lemma ArtinScheier_factorize : 'X^p - 'X - (x ^+ p - x)%:P = \prod_(i < p) ('X - (x + i%:R)%:P). Proof. case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. apply/eqP; rewrite -eqp_monic; first last. -- by apply monic_prod_XsubC. +- by apply: monic_prod_XsubC. - apply/monicP; rewrite -addrA -opprD lead_coefDl ?lead_coefXn//. by rewrite size_opp size_XaddC size_polyXn ltnS. - rewrite eqp_sym -dvdp_size_eqp. @@ -40,58 +40,61 @@ apply/eqP; rewrite -eqp_monic; first last. by rewrite size_XsubC size_polyC eqxx. have ->: \big[addn/0%N]_(i < n.+1) size ('X - (x + (val i)%:R)%:P)%R = \big[addn/0%N]_(i < n.+1) 2%N. - by apply eq_bigr=> i _; rewrite size_XsubC. + by apply: eq_bigr => i _; rewrite size_XsubC. rewrite big_const_ord iter_addn_0. rewrite -add1n mul2n -addnn addnA card_ord -addnBA// subnn addn0 add1n. rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. by move: pchar => /andP [ /prime_gt1 ]. - have: all (root ('X^n.+1 - 'X - (x ^+ n.+1 - x)%:P)) [seq (x + (val i)%:R) | i <- index_enum (ordinal_finType n.+1)]. + have: all (root ('X^n.+1 - 'X - (x ^+ n.+1 - x)%:P)) + [seq (x + (val i)%:R) | i : 'I_n.+1]. apply/allP => + /mapP [i _ ->] => _. - rewrite/root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). + rewrite /root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). rewrite opprB opprD addrACA -addrA 2![x+_]addrA subrr add0r. by rewrite addrAC addrCA subrr addr0 addrC subrr. - move=>/uniq_roots_dvdp; rewrite big_map; apply. + move=> /uniq_roots_dvdp; rewrite big_map big_enum/=; apply. rewrite uniq_rootsE; apply/(uniqP 0) => i j. rewrite 2!inE size_map => ilt jlt. - rewrite (nth_map ord0)// (nth_map ord0)// => /addrI/esym/eqP. - set ip := nth ord0 (index_enum (ordinal_finType n.+1)) i. - set jp := nth ord0 (index_enum (ordinal_finType n.+1)) j. - move=>ijE. + do 2 rewrite (nth_map ord0 _ (fun i : 'I_n.+1 => x + i%:R))//. + move=> /addrI/esym/eqP. + set ip := nth ord0 (enum 'I_n.+1) i. + set jp := nth ord0 (enum 'I_n.+1) j. + move=> ijE. suff: jp = ip. - rewrite/ip/jp => /esym ijE0. - by move: (index_enum_uniq (ordinal_finType n.+1))=>/uniqP + rewrite /ip /jp => /esym ijE0. + by move: (enum_uniq ('I_n.+1)) => /uniqP /(_ i j ilt jlt ijE0). - move:ijE. + move: ijE. wlog ij : {i} {j} {ilt} {jlt} ip jp / (val ip <= val jp)%N. move=> h. move: (Order.TotalTheory.le_total (val ip) (val jp)) => /orP; case => ij. - by apply h. - by rewrite eq_sym=> ijE; apply /esym/h. + by apply: h. + by rewrite eq_sym => ijE; apply/esym/h. rewrite -subr_eq0 -natrB// -(dvdn_charf nchar). case /posnP: (val jp - val ip)%N. - move=>/eqP; rewrite subn_eq0 => ji _; apply/val_inj/eqP. + move=> /eqP; rewrite subn_eq0 => ji _; apply/val_inj/eqP. by rewrite Order.POrderTheory.eq_le; apply/andP; split. - move=>ij0 /(dvdn_leq ij0); rewrite ltn_subRL -addnS. - move=>/(leq_trans (leq_addl _ _)). - have: (val jp < n.+1)%N by destruct jp. + move=> ij0 /(dvdn_leq ij0); rewrite ltn_subRL -addnS. + move=> /(leq_trans (leq_addl _ _)). + have: (val jp < n.+1)%N by case: jp ij ij0. by rewrite ltnS => jle; move => /(leq_ltn_trans jle); rewrite ltnn. Qed. Lemma ArtinSchreier_splitting : splittingFieldFor E ('X^p - 'X - (x ^+ p - x)%:P) <>%AS. Proof. -exists ([seq x + (val i)%:R | i <- (index_enum (ordinal_finType p))]). - by rewrite ArtinScheier_factorize big_map eqpxx. +exists ([seq x + (val i)%:R | i :'I_p]). + by rewrite ArtinScheier_factorize big_map big_enum/= eqpxx. apply/eqP; rewrite eqEsubv; apply/andP; split. - apply/Fadjoin_seqP; split; first by apply subv_adjoin. - move=>+ /mapP [i _ ->] => _. - apply (@rpredD _ _ (memv_addrPred <>%AS)); first by apply memv_adjoin. - by apply rpred_nat. -apply/FadjoinP; split; first by apply subv_adjoin_seq. + apply/Fadjoin_seqP; split; first by apply: subv_adjoin. + move=> + /mapP [i _ ->] => _. + apply: (@rpredD _ _ (memv_addrPred <>%AS)); + first by apply: memv_adjoin. + by apply: rpred_nat. +apply/FadjoinP; split; first by apply: subv_adjoin_seq. case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. -apply/seqv_sub_adjoin/mapP; exists ord0; first by apply mem_index_enum. +apply/seqv_sub_adjoin/mapP; exists ord0; first by apply: mem_enum. by rewrite addr0. Qed. @@ -104,27 +107,28 @@ Lemma ArtinSchreier_galois : Proof. apply/splitting_galoisField; exists ('X^p - 'X - (x ^+ p - x)%:P); split. - exact ArtinSchreier_polyOver. -- rewrite/separable_poly derivB derivC subr0 derivB derivXn derivX -scaler_nat. +- rewrite /separable_poly derivB derivC subr0 derivB derivXn derivX -scaler_nat. move: pchar; rewrite inE => /andP[_ /eqP ->]. rewrite scale0r add0r. apply/Bezout_eq1_coprimepP; exists (0, (-1)) => /=. by rewrite mul0r add0r mulN1r opprK. -- by apply ArtinSchreier_splitting. +- by apply: ArtinSchreier_splitting. Qed. Lemma minPoly_ArtinSchreier : (x \notin E) -> minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. Proof. move=> xE. -have pE: ('X^p - 'X - (x ^+ p - x)%:P) = \prod_(i <- [seq x + (val i)%:R | i : 'I_p]) ('X - i%:P). - by rewrite ArtinScheier_factorize big_map; apply congr_big => //; rewrite enumT. -have /(minPoly_dvdp ArtinSchreier_polyOver): root ('X^p - 'X - (x ^+ p - x)%:P) x. +have pE: ('X^p - 'X - (x ^+ p - x)%:P) = + \prod_(i <- [seq x + (val i)%:R | i : 'I_p]) ('X - i%:P). + by rewrite ArtinScheier_factorize big_map; apply: congr_big; rewrite // enumT. +have /(minPoly_dvdp ArtinSchreier_polyOver): + root ('X^p - 'X - (x ^+ p - x)%:P) x. rewrite pE root_prod_XsubC. case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. - apply/mapP; exists ord0; first by rewrite enumT mem_index_enum. - by rewrite addr0. -rewrite pE => /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last first. - by rewrite monic_prod// => i _; rewrite monic_XsubC. + by apply/mapP; exists ord0; rewrite ?mem_enum ?addr0. +rewrite pE => /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; + last by rewrite monic_prod// => i _; rewrite monic_XsubC. rewrite -map_mask. have [{}m sm ->] := resize_mask m (enum 'I_p). set s := mask _ _ => /eqP mEx. @@ -132,22 +136,25 @@ have [|smp_gt0] := posnP (size s). case: s mEx => // /(congr1 (horner^~x))/esym/eqP. by rewrite minPolyxx big_nil hornerC oner_eq0. suff leq_pm : (p <= size s)%N. - move: mEx; suff /eqP->: s == enum 'I_p by []. - rewrite -(geq_leqif (size_subseq_leqif _)) ?mask_subseq//. - by rewrite/index_enum; case: index_enum_key=>/=; rewrite size_enum_ord. + move: mEx; suff /eqP -> : s == enum 'I_p by []. + by rewrite -(geq_leqif (size_subseq_leqif _)) ?mask_subseq// size_enum_ord. have /polyOverP/(_ (size s).-1%N) := minPolyOver E x; rewrite {}mEx. -rewrite -(size_map (fun i => x + (val i)%:R)) coefPn_prod_XsubC size_map -?lt0n// big_map. +rewrite -(size_map (fun i => x + (val i)%:R)). +rewrite coefPn_prod_XsubC size_map -?lt0n// big_map. rewrite memvN big_split/= big_const_seq count_predT iter_addr_0 => DE. -have sE: \sum_(i <- s) i%:R \in E by apply rpred_sum => i _; apply rpred_nat. -move:(rpredB DE sE) => {DE} {sE}. +have sE: \sum_(i <- s) i%:R \in E by apply: rpred_sum => i _; apply: rpred_nat. +move: (rpredB DE sE) => {DE} {sE}. rewrite -addrA subrr addr0 => xsE. apply/negP => sltp. have /coprimeP: coprime (size s) p. - by rewrite coprime_sym (prime_coprime _ pprim); apply/negP => /(dvdn_leq smp_gt0). + rewrite coprime_sym (prime_coprime _ pprim). + by apply/negP => /(dvdn_leq smp_gt0). move=> /(_ smp_gt0) [[u v]]/= uv1. have /ltnW vltu: (v * p < u * size s)%N by rewrite ltnNge -subn_eq0 uv1. -move:uv1 => /eqP; rewrite -(eqn_add2l (v * p)) addnBA// addnC -addnBA// subnn addn0 => /eqP sE. -move: xsE => /(rpredMn u); rewrite -mulrnA mulnC sE addn1 mulrS mulrnA -mulr_natr. +move: uv1 => /eqP; rewrite -(eqn_add2l (v * p)) addnBA// addnC -addnBA//. +rewrite subnn addn0 => /eqP sE. +move: xsE => /(rpredMn u). +rewrite -mulrnA mulnC sE addn1 mulrS mulrnA -mulr_natr. move: p0 => /eqP ->; rewrite mulr0 addr0. by move: xE => /negP. Qed. diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v index 19fe799..38c2810 100644 --- a/theories/xmathcomp/temp.v +++ b/theories/xmathcomp/temp.v @@ -13,88 +13,111 @@ Local Open Scope ring_scope. Section Temp. -(* NB : rpredM and mulrPred uses that 1 is in the subset, which is useless. Predicates should be defined for {aspace aT}. *) +(* NB : rpredM and mulrPred uses that 1 is in the subset, which is useless. + Predicates should be defined for {aspace aT}. *) -Lemma memv_mulr_2closed [K : fieldType] [aT : FalgType K] (U : {aspace aT}) : GRing.mulr_2closed U. +Lemma memv_mulr_2closed [K : fieldType] [aT : FalgType K] (U : {aspace aT}) : + GRing.mulr_2closed U. Proof. move: U => [U]/[dup]/andP[_ /subvP UU] Ualg. -move=> u v uU vU; apply/UU/memv_mulP; exists 1%N, (@Tuple _ _ [:: u] (eqxx _)), (@Tuple _ _ [:: v] (eqxx _)); split => /=. +move=> u v uU vU; apply/UU/memv_mulP. +exists 1%N, (@Tuple _ _ [:: u] (eqxx _)), (@Tuple _ _ [:: v] (eqxx _)). +split => /=. - by rewrite uU. - by rewrite vU. - by rewrite big_ord1 2!(tnth_nth 1)/=. Qed. -Lemma polyOver_mulr_2closed [R : ringType] [S : {pred R}] [addS : addrPred S] (kS : keyed_pred addS) : GRing.mulr_2closed kS -> GRing.mulr_2closed (polyOver kS). +Lemma polyOver_mulr_2closed [R : ringType] [S : {pred R}] + [addS : addrPred S] (kS : keyed_pred addS) : + GRing.mulr_2closed kS -> GRing.mulr_2closed (polyOver kS). Proof. -move=>SM u vz /polyOverP uS /polyOverP vS; apply/polyOverP => i. -by rewrite coefM rpred_sum // => j _; apply SM. +move=> SM u vz /polyOverP uS /polyOverP vS; apply/polyOverP => i. +by rewrite coefM rpred_sum // => j _; apply/SM. Qed. -Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] (f g : 'AHom(K, rT)) - (U : {subfield K}) (x : K) : +Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] + (f g : 'AHom(K, rT)) (U : {subfield K}) (x : K) : {in U, f =1 g} -> f x = g x -> {in <>%VS, f =1 g}. Proof. move=> fgU fgx y /Fadjoin_poly_eq <-. move: (Fadjoin_poly U x y) (Fadjoin_polyOver U x y) => p /polyOverP pU. -rewrite -(coefK p) horner_poly 2!rmorph_sum/=; apply eq_bigr => i _. +rewrite -(coefK p) horner_poly 2!rmorph_sum/=; apply/eq_bigr => i _. by rewrite 2!rmorphM /= fgU// 2!rmorphX/= fgx. Qed. -Lemma ahom_eq_adjoin_seq [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] (f g : 'AHom(K, rT)) - (U : {aspace K}) (xs : seq K) : +Lemma ahom_eq_adjoin_seq [F0 : fieldType] [K : fieldExtType F0] + [rT : FalgType F0] (f g : 'AHom(K, rT)) (U : {aspace K}) (xs : seq K) : {in U, f =1 g} -> {in xs, forall x, f x = g x} -> {in <>%VS, f =1 g}. Proof. elim: xs U => [|x xs IHxs] U fgU fgxs. by rewrite adjoin_nil subfield_closed. rewrite adjoin_cons. -have ->: <>%VS = ASpace (agenv_is_aspace <>%VS) by rewrite /= agenv_id. +have ->: <>%VS = ASpace (agenv_is_aspace <>%VS) + by rewrite /= agenv_id. move: fgxs (IHxs (ASpace (agenv_is_aspace <>))) => fgxs /=. -rewrite agenv_id; apply; first by apply/ahom_eq_adjoin/fgxs=>//; apply mem_head. -by move=>a axs; apply fgxs; rewrite in_cons axs orbT. +rewrite agenv_id; apply. + by apply/ahom_eq_adjoin/fgxs => //; apply/mem_head. +by move=> a axs; apply/fgxs; rewrite in_cons axs orbT. Qed. -Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. +Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) + (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. Proof. -move=>->. +move=> ->. suff ->: (1+U)%VS = U by rewrite subfield_closed. rewrite -{2}(subfield_closed U) (agenvEr U) subfield_closed. by congr (1 + _)%VS; apply/esym/field_module_eq; rewrite sup_field_module. Qed. -Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f g : gal_of E) : f = g \/ exists x, x \in E /\ f x != g x. +Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) + (f g : gal_of E) : f = g \/ exists x, x \in E /\ f x != g x. Proof. -move:(vbasisP E)=>/span_basis/agenv_span LE. -case/boolP: (all (fun x => f x == g x) (vbasis E)) => [/allP fgE | /allPn[x] xE fgx]; [ left | right ]. - 2: by exists x; split=>//; apply vbasis_mem. +move: (vbasisP E) => /span_basis/agenv_span LE. +case /boolP: (all (fun x => f x == g x) (vbasis E)) + => [/allP fgE | /allPn[x] xE fgx]; [ left | right ]. + 2: by exists x; split => //; apply/vbasis_mem. apply/eqP/gal_eqP. -rewrite -{1}LE; apply ahom_eq_adjoin_seq=>//; last by move=>x /fgE/eqP. -move:(gal1 f)(gal1 g). -rewrite gal_kHom ?sub1v// gal_kHom ?sub1v// => /andP [_ /subvP f1] /andP [_ /subvP g1]. -by move=>x /[dup] /f1/fixedSpaceP -> /g1/fixedSpaceP ->. +rewrite -{1}LE; apply/ahom_eq_adjoin_seq => //; last by move=> x /fgE/eqP. +move: (gal1 f)(gal1 g). +rewrite gal_kHom ?sub1v// gal_kHom ?sub1v//. +move=> /andP [_ /subvP f1] /andP [_ /subvP g1]. +by move=> x /[dup] /f1/fixedSpaceP -> /g1/fixedSpaceP ->. Qed. -Lemma tnth_cons (T : Type) (x : T) (l : seq T) (i : 'I_(size l)): tnth (in_tuple (x :: l)) (lift ord0 i) = tnth (in_tuple l) i. -Proof. by rewrite/tnth/=; apply set_nth_default. Qed. +Lemma tnth_cons (T : Type) (x : T) (l : seq T) (i : 'I_(size l)) : + tnth (in_tuple (x :: l)) (lift ord0 i) = tnth (in_tuple l) i. +Proof. by rewrite /tnth/=; apply/set_nth_default. Qed. -Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (f : seq (gal_of E)) (k : 'I_(size f) -> L) : uniq f -> (forall i, k i = 0) \/ (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). +(* TODO : generalize to independance of characters *) + +Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) + (E : {subfield L}) (f : seq (gal_of E)) (k : 'I_(size f) -> L) : + uniq f -> + (forall i, k i = 0) \/ + (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). Proof. -move:(Logic.eq_refl (size f)); generalize (size f) at 1 => n. +move: {1}(size f) (Logic.eq_refl (size f)) => n. elim: n f k => [|n IHn] f k fsize funiq. by left; case; move: k; rewrite -fsize. -destruct f as [| s f] => //. -destruct n; destruct f as [| s0 f] => //. - case/boolP: (k 0 == 0). - move=>/eqP k0; left => i. - by move: k0; congr (k _ = 0); apply val_inj; case i; case. - move=>/negPf k0; right; exists 1; rewrite big_ord1 /= rmorph1; split. - by apply mem1v. +case: f => [|s f] in k fsize funiq * => //. +case: f => [|s0 f] in k fsize funiq * => //. + case /boolP: (k 0 == 0). + move=> /eqP k0; left => i. + by move: k0; congr (k _ = 0); apply/val_inj; case i; case. + move=> /negPf k0; right; exists 1; rewrite big_ord1 /= rmorph1; split. + by apply/mem1v. by apply/negP; rewrite mulr1 k0. -move: funiq => /=; rewrite negb_or => /andP [/andP[ss0 sf]] /[dup] s0f /andP[_ funiq]. +move: funiq; rewrite /= negb_or. +move=> /andP [/andP[ss0 sf]] /[dup] s0f /andP[_ funiq]. case: (gal_ne s s0) => [/eqP ss0E | [x [xE /negPf ss0x]]]. by move: ss0; rewrite ss0E. -move:fsize=>/eqP; rewrite eqSS=>/eqP fsize. -case: (IHn [:: s0 & f] (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) i x - s x))) fsize s0f). - move=>/(_ ord0)/=/eqP; rewrite mulf_eq0 subr_eq0 [s0 x == _]eq_sym ss0x orbF => k10. +move: fsize => /eqP; rewrite eqSS => /eqP fsize. +case: (IHn [:: s0 & f] + (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) i x - s x))) + fsize s0f). + move=> /(_ ord0)/=/eqP. + rewrite mulf_eq0 subr_eq0 [s0 x == _]eq_sym ss0x orbF => k10. set k' := fun i : 'I_(size f).+1 => k (match splitP (i : 'I_(1 + size f)%N) with | SplitLo _ _ => ord0 @@ -104,43 +127,58 @@ case: (IHn [:: s0 & f] (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) have /[swap]/[apply]: uniq (s :: f) by apply/andP; split. case => [k0 | [a [aE fne0]]]; [left => i | right; exists a]. case: i; case. - move: (k0 ord0); rewrite/k'. - by case: splitP => // + _ + ilt => _; congr (k _ = 0); apply val_inj. + move: (k0 ord0); rewrite /k'. + by case: splitP => // + _ + ilt => _; congr (k _ = 0); apply/val_inj. case => [|i] ilt. - by move: k10 => /eqP; congr (k _ = 0); apply val_inj. + by move: k10 => /eqP; congr (k _ = 0); apply/val_inj. have ile: (i.+1 < (size f).+1)%N by rewrite -ltnS. - move:(k0 (Ordinal ile)); rewrite/k'. + move: (k0 (Ordinal ile)); rewrite /k'. case: splitP => [[j]/=/[swap]<-// | /= _ _]. - by congr (k _ = 0); apply val_inj. - split=>//. - move:k10 fne0 => /eqP k10. + by congr (k _ = 0); apply/val_inj. + split => //. + move: k10 fne0 => /eqP k10. rewrite 3!big_ord_recl/= k10 mul0r add0r. congr (_ * _ + _ != 0). - by rewrite/k'; case: splitP => // [[i]] /=/(congr1 val). - apply eq_bigr => i _; rewrite tnth_cons (@tnth_cons _ s (s0 :: f) (lift ord0 i)) tnth_cons; congr (_ * _). - by rewrite/k'; case: splitP => // [[j]]/=/[swap]<-. -move=>[y [yE fne0]]; right. -case /boolP: (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) => [| yne0]. - 2: by exists y. + by rewrite /k'; case: splitP => // [[i]] /=/(congr1 val). + apply/eq_bigr => i _. + rewrite tnth_cons (@tnth_cons _ s (s0 :: f) (lift ord0 i)) tnth_cons. + congr (_ * _). + by rewrite /k'; case: splitP => // [[j]]/=/[swap]<-. +move=> [y [yE fne0]]; right. +case /boolP: + (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) + => [| yne0]; last by exists y. rewrite big_ord_recl/= addrC addr_eq0 {2}/tnth/= => /eqP. under eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)); move=> y0. -exists (x*y); split; first by apply rpredM. +exists (x*y); split; first by apply/rpredM. move: fne0; congr (_ != 0). -under [\sum_(_ < (size f).+1) _]eq_bigr do rewrite mulrBr mulrBl [X in _ - X * _]mulrC -mulrA -rmorphM/= -[X in _ - X]mulrA. -rewrite sumrB -mulr_sumr y0 mulrN mulrA opprK [s x * _]mulrC -mulrA -rmorphM/= addrC [in RHS]big_ord_recl {2}/tnth/=. +under [\sum_(_ < (size f).+1) _]eq_bigr do rewrite mulrBr mulrBl + [X in _ - X * _]mulrC -mulrA -rmorphM/= -[X in _ - X]mulrA. +rewrite sumrB -mulr_sumr y0 mulrN mulrA opprK [s x * _]mulrC -mulrA -rmorphM/=. +rewrite addrC [in RHS]big_ord_recl {2}/tnth/=. by under [in RHS]eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)). Qed. -Lemma galTrace_ne_0 (F : fieldType) (L : splittingFieldType F) (K E : {subfield L}) : exists a, a \in E /\ galTrace K E a != 0. +Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) + [I : finType] (F : I -> R) : + \big[op/idx]_(i in [set: I]) F i = \big[op/idx]_i F i. +Proof. by apply/congr_big => // i; rewrite in_setT. Qed. + +Lemma galTrace_ne_0 (F : fieldType) (L : splittingFieldType F) + (K E : {subfield L}) : exists a, a \in E /\ galTrace K E a != 0. Proof. -set l := index_enum (FinGroup.finType (gal_finGroupType E)). -case: (gal_free (fun i : 'I_(size l) => (1 *+ ((tnth (in_tuple l) i) \in (galoisG E K) : nat))%:A) (index_enum_uniq _)). - have /[dup] l1: 1%g \in l by apply mem_index_enum. - rewrite -index_mem => lt1. - by move=>/(_ (Ordinal lt1))/=/eqP; rewrite /tnth (nth_index _ l1) group1/= scaler_eq0 2!oner_eq0. -move=>[x [xE s0]]; exists x; split=>//; move:s0; congr (_ != 0). -rewrite/galTrace -(big_tuple _ _ _ xpredT (fun f => (f \in galoisG E K)%:R%:A * f x))/=/l. -rewrite [in RHS]big_mkcond/=; apply eq_bigr => i _. +set l := enum [set: gal_of E]. +case: (gal_free + (fun i : 'I_(size l) => + (1 *+ ((tnth (in_tuple l) i) \in (galoisG E K) : nat))%:A) + (enum_uniq _)). + have /[dup] l1: 1%g \in l by rewrite mem_enum. + rewrite -index_mem => lt1 /(_ (Ordinal lt1))/=/eqP. + by rewrite /tnth (nth_index _ l1) group1/= scaler_eq0 2!oner_eq0. +move=> [x [xE s0]]; exists x; split => //. +move: s0; congr (_ != 0); rewrite /galTrace. +rewrite -(big_tuple _ _ _ xpredT (fun f => (f \in galoisG E K)%:R%:A * f x))/=. +rewrite /l [in RHS]big_mkcond/= big_enum /= big_setT; apply/eq_bigr => i _. case: (i \in galoisG E K) => /=; first by rewrite mulr1n scale1r mul1r. by rewrite mulr0n scale0r mul0r. Qed. @@ -154,6 +192,7 @@ move=> a f IHf. by rewrite 2!big_cons ffunE IHf. Qed. + Definition Zp_succ n (i : 'I_n) := match i with | @Ordinal _ k klt => Ordinal ( @@ -163,31 +202,33 @@ Definition Zp_succ n (i : 'I_n) := end klt) end. -Lemma cycle_imset [gT : finGroupType] (g : gT) : <[g]>%g = @Imset.imset (ordinal_finType #[g]%g) (FinGroup.finType gT) (fun i => (g ^+ (val i))%g) (mem setT). +(* TODO: généraliser sur toutes les définitions par imset. *) +(* Ah non, je change le domaine d'indexation, ce lemme est spécifique aux + * éléments d'ordre fini d'un groupe. *) +Lemma cycle_imset [gT : finGroupType] (g : gT) : + <[g]>%g = ([set g ^+ (val i) | i : 'I_#[g]])%g. Proof. apply/eqP; rewrite eqEsubset; apply/andP; split; apply/subsetP => x. - move=>/cycleP [i ->]; apply/imsetP. + move=> /cycleP [i ->]; apply/imsetP. exists (Ordinal (ltn_pmod i (order_gt0 g))); rewrite ?in_setT//. by rewrite expg_mod_order. -by move=>/imsetP [i] _ ->; apply/cycleP; exists i. +by move=> /imsetP [i] _ ->; apply/cycleP; exists i. Qed. -Lemma cycle_imset_inj [gT : finGroupType] (g : gT) : {in setT &, injective (fun i : 'I_(#[g]%g) => (g ^+ i)%g)}. +Lemma cycle_imset_inj [gT : finGroupType] (g : gT) : + injective (fun i : 'I_(#[g]) => (g ^+ i))%g. Proof. -move=>[i ilt] [j jlt]/= _ _ /eqP; rewrite eq_expg_mod_order. +move=> [i ilt] [j jlt] /eqP; rewrite eq_expg_mod_order. rewrite modn_small// modn_small// => /eqP ijE. -by apply val_inj. +by apply/val_inj. Qed. Lemma big_condT [R : Type] [idx : R] (op : Monoid.com_law idx) [I : finType] (A : {pred I}) (F : I -> R) : \big[op/idx]_(i in A | true) F i = \big[op/idx]_(i in A) F i. -Proof. by apply congr_big => // i; rewrite andbT. Qed. - -Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) - [I : finType] (F : I -> R) : - \big[op/idx]_(i in [set: I]) F i = \big[op/idx]_i F i. -Proof. by apply congr_big => // i; rewrite in_setT. Qed. +Proof. +rewrite big_mkcondr. +by apply/congr_big => // i; rewrite andbT. Qed. Lemma Hilbert's_theorem_90_additive [F : fieldType] [L : splittingFieldType F] @@ -199,58 +240,62 @@ Lemma Hilbert's_theorem_90_additive reflect (exists2 b : L, b \in E & a = b - x b) (galTrace K E a == 0). Proof. -move=>Egal /(_ =P <[x]>%g) DgalE Ea. +move=> Egal /(_ =P <[x]>%g) DgalE Ea. have galEx: x \in 'Gal(E / K)%g by rewrite DgalE cycle_id. apply: (iffP eqP) => [normEa1 | [b Eb ->]]; last first. - by rewrite galTrace_is_additive galTrace_gal// subrr. -move:(galTrace_ne_0 K E) => [b [bE tb]]. + by rewrite raddfB/= galTrace_gal// subrr. +move: (galTrace_ne_0 K E) => [b [bE tb]]. remember (\dim_K E) as n. have ordx: #[x]%g = n by rewrite orderE -DgalE -(galois_dim Egal). -move:(expg_order x); rewrite ordx => xord. -move:(Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). +move: (expg_order x); rewrite ordx => xord. +move: (Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). rewrite mul0n adim_gt0 => dimgt0 /(_ 1%N); rewrite mul1n => dimgt1. -destruct n; first by move:dimgt0; rewrite -Heqn. -destruct n. - move:dimgt1; rewrite -Heqn ltnn => /esym/negbT; rewrite -leqNgt => dimEK. - move:(eqEdim K E); rewrite dimEK (galois_subW Egal) => /=/eqP KE. - move:normEa1; rewrite/galTrace. +case: n => [|n] in Heqn ordx xord *; first by move: dimgt0; rewrite -Heqn. +case: n => [|n] in Heqn ordx xord *. + move: dimgt1; rewrite -Heqn ltnn => /esym/negbT; rewrite -leqNgt => dimEK. + move: (eqEdim K E); rewrite dimEK (galois_subW Egal) => /=/eqP KE. + move: normEa1; rewrite /galTrace. have ->: \sum_(x0 in ('Gal(E / K))%g) x0 a = \sum_(x0 in ('Gal(E / K))%g) a. - apply eq_bigr => f fgal. - move:Egal=>/galois_fixedField Kfix. - by move:(Ea); rewrite -{1}KE -Kfix => /fixedFieldP => /(_ Ea f fgal). + apply/eq_bigr => f fgal. + move: Egal => /galois_fixedField Kfix. + by move: (Ea); rewrite -{1}KE -Kfix => /fixedFieldP => /(_ Ea f fgal). rewrite sumr_const; rewrite -(galois_dim Egal) -Heqn mulr1n => a0. by exists a => //; rewrite a0 rmorph0 subr0. -set c := (galTrace K E b)^-1 * \sum_(i < n.+1) (\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. -have tbE: galTrace K E b \in E by rewrite /galTrace rpred_sum// => f _; apply memv_gal. +set c := (galTrace K E b)^-1 + * \sum_(i < n.+1) (\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. +have tbE: galTrace K E b \in E. + by rewrite /galTrace rpred_sum// => f _; apply/memv_gal. exists c. - apply rpredM; first by rewrite rpredV. + apply/rpredM; first by rewrite rpredV. rewrite rpred_sum// => i _. - apply rpredM; last by apply memv_gal. - by rewrite rpred_sum// => j _; apply memv_gal. -rewrite/c rmorphM/= rmorphV/= ?unitfE//. -move:(galTrace_fixedField K bE) => /fixedFieldP => /(_ tbE x galEx) ->. + apply/rpredM; last by apply/memv_gal. + by rewrite rpred_sum// => j _; apply/memv_gal. +rewrite /c rmorphM/= rmorphV/= ?unitfE//. +move: (galTrace_fixedField K bE) => /fixedFieldP => /(_ tbE x galEx) ->. rewrite -mulrBr rmorph_sum/=. rewrite big_ord_recl big_ord1 expg0 gal_id expg1 big_ord_recr/=. rewrite opprD addrAC [_ - x _]addrC addrA -addrA [- _ + _]addrC -sumrB. -have ->: \sum_(i < n) ((\sum_(j < (bump 0 i).+1) (x ^+ j)%g a) * (x ^+ (bump 0 i).+1)%g b - +have ->: \sum_(i < n) + ((\sum_(j < (bump 0 i).+1) (x ^+ j)%g a) * (x ^+ (bump 0 i).+1)%g b - x ((\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b)) = - \sum_(i < n) a * (x ^+ i.+2)%g b. - apply eq_bigr; case => i ilt _ /=. - rewrite/bump/= add1n rmorphM/= rmorph_sum/= expgSr galM// -mulrBl; congr (_ * _). - rewrite big_ord_recl/= -addrA -sumrB expg0 gal_id -[in RHS](addr0 a); congr (a + _). + \sum_(i < n) a * (x ^+ i.+2)%g b. + apply/eq_bigr; case => i ilt _ /=. + rewrite /bump/= add1n rmorphM/= rmorph_sum/= expgSr galM// -mulrBl. + congr *%R. + rewrite big_ord_recl/= -addrA -sumrB expg0 gal_id -[in RHS](addr0 a). + congr (a + _). transitivity (\sum_(j < i.+1) (0 : L)); last by rewrite sumr_const mul0rn. - by apply eq_bigr => j _; rewrite/bump/= add1n expgSr galM// subrr. + by apply/eq_bigr => j _; rewrite /bump/= add1n expgSr galM// subrr. rewrite -mulr_sumr rmorphM/= rmorph_sum/=. have tE: forall d, d \in E -> galTrace K E d = \sum_(i < n.+2) (x ^+ i)%g d. - move=>d dE. - rewrite/galTrace DgalE cycle_imset => /=. - rewrite -big_condT/=. - rewrite (big_imset_cond _ _ _ (@cycle_imset_inj _ x)). - by rewrite big_condT /= ordx big_setT/= big_ord_recl expg0 gal_id. -move:normEa1; rewrite tE// big_ord_recl expg0 gal_id => /eqP. -under [in X in X -> _]eq_bigr do rewrite /=/bump/=add1n expgSr galM//. + move=> d dE. + rewrite /galTrace DgalE cycle_imset => /=. + by rewrite (big_imset _ (in2W (@cycle_imset_inj _ x))) /= ordx. +move: normEa1; rewrite tE// big_ord_recl expg0 gal_id => /eqP. +under [in X in X -> _]eq_bigr do rewrite /= /bump/= add1n expgSr galM//. rewrite addrC addr_eq0 => /eqP ->. -rewrite mulNr opprK -2!mulrDr mulrCA -(galM _ x bE) -expgSr xord gal_id [x b + b]addrC. +rewrite mulNr opprK -2!mulrDr mulrCA -(galM _ x bE). +rewrite -expgSr xord gal_id [x b + b]addrC. have <-: galTrace K E b = b + x b + \sum_(i < n) (x ^+ i.+2)%g b. rewrite (tE b bE) big_ord_recl/= expg0 gal_id big_ord_recl/= expg1 addrA. by under eq_bigr do rewrite /bump/= 2!add1n. @@ -261,19 +306,20 @@ Lemma natf_partn_ne0 (R : idomainType) n : (n`_[char R]^')%:R != 0 :> R. Proof. have n_gt0 := (part_gt0 [char R]^' n). -apply/negP; rewrite/partn natr_prod prodf_seq_eq0 => /hasP [i] i0n. +apply/negP; rewrite /partn natr_prod prodf_seq_eq0 => /hasP [i] i0n. rewrite unfold_in/= natrX expf_eq0 logn_gt0 mem_primes => /andP[/negP ichar]. -move=>/andP[/andP[iprim _] i0]; apply ichar; rewrite unfold_in/=. +move=> /andP[/andP[iprim _] i0]; apply/ichar; rewrite unfold_in/=. by apply/andP. Qed. -Lemma natf0_partn (R : idomainType) n : (0 < n)%N -> (n%:R == 0 :> R) = (n`_[char R] != 1)%N. +Lemma natf0_partn (R : idomainType) n : (0 < n)%N -> + (n%:R == 0 :> R) = (n`_[char R] != 1)%N. Proof. -move=>n_gt0. +move=> n_gt0. apply/idP/idP => [n0 |]. apply/negP => /eqP nchar1. - move:n0; rewrite -(partnC [char R] n_gt0) nchar1 mul1n => n0. - by move:(natf_partn_ne0 R n); rewrite n0. + move: n0; rewrite -(partnC [char R] n_gt0) nchar1 mul1n => n0. + by move: (natf_partn_ne0 R n); rewrite n0. rewrite partn_eq1// /pnat n_gt0/= => /allPn [p]. rewrite mem_primes => /andP [pprim /andP [_ pn]]. rewrite /negn/mem/= 2!unfold_in negbK /= => pchar. @@ -283,36 +329,39 @@ Qed. Lemma primes_dvdn (m n : nat) : (0 < n)%N -> (m %| n)%N -> primes m = [seq p <- primes n | p \in primes m]. Proof. -move=>n0 mn. -apply Order.POrderTheory.lt_sorted_eq. -- apply sorted_primes. -- apply sorted_filter. - apply Order.POrderTheory.lt_trans. -apply sorted_primes. -- move=>p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. +move=> n0 mn. +apply/Order.POrderTheory.lt_sorted_eq. +- apply/sorted_primes. +- apply/sorted_filter. + apply/Order.POrderTheory.lt_trans. +apply/sorted_primes. +- move=> p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. rewrite 2!mem_primes => /andP[->/=]/andP[m0 pm]. -by rewrite n0/=; apply (dvdn_trans pm). +by rewrite n0/=; apply/(dvdn_trans pm). Qed. Lemma dvdn_leq_logP (m n : nat) : - (0 < n)%N -> (0 < m)%N -> reflect (forall p, prime p -> logn p m <= logn p n)%N (m %| n)%N. + (0 < n)%N -> (0 < m)%N -> + reflect (forall p, prime p -> logn p m <= logn p n)%N (m %| n)%N. Proof. -move=>n0 m0; apply (iffP idP) => [mn p prim | vp_leq]. - by apply dvdn_leq_log. +move=> n0 m0; apply/(iffP idP) => [mn p prim | vp_leq]. + by apply/dvdn_leq_log. apply/dvdnP; exists (\prod_(p <- primes n) p ^ (logn p n - logn p m))%N. -rewrite {1}(prod_prime_decomp n0) {2}(prod_prime_decomp m0) 2!prime_decompE 2!big_map/=. +rewrite {1}(prod_prime_decomp n0) {2}(prod_prime_decomp m0). +rewrite 2!prime_decompE 2!big_map/=. have ->: primes m = [seq i <- primes n | i \in primes m]. - apply Order.POrderTheory.lt_sorted_eq. - - apply sorted_primes. - - apply sorted_filter. - apply Order.POrderTheory.lt_trans. - apply sorted_primes. - - move=>p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. - move=>/[dup]; rewrite {1}mem_primes => /andP[pprim _]. + apply/Order.POrderTheory.lt_sorted_eq. + - apply/sorted_primes. + - apply/sorted_filter. + apply/Order.POrderTheory.lt_trans. + apply/sorted_primes. + - move=> p; rewrite mem_filter. + apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. + move=> /[dup]; rewrite {1}mem_primes => /andP[pprim _]. rewrite -2!logn_gt0 => pm. - apply (leq_trans pm (vp_leq p pprim)). + apply/(leq_trans pm (vp_leq p pprim)). rewrite big_filter [in X in (_ * X)%N]big_mkcond/= -big_split/= 2!big_seq. -apply eq_bigr => p; rewrite mem_primes => /andP[pprim _]. +apply/eq_bigr => p; rewrite mem_primes => /andP[pprim _]. have ->: ((if p \in primes m then p ^ logn p m else 1) = p ^ logn p m)%N. case/boolP: (p \in primes m) => //. by rewrite -logn_gt0 lt0n negbK => /eqP ->; rewrite expn0. @@ -325,9 +374,9 @@ Lemma logn_prod [I : eqType] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : Proof. elim: r => [|n r IHn Fnr0]; first by rewrite 2!big_nil logn1. have Fr0: {in r, forall n : I, P n -> (0 < F n)%N}. - by move=> i ir; apply Fnr0; rewrite in_cons ir orbT. -rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply IHn. -move:(Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. + by move=> i ir; apply/Fnr0; rewrite in_cons ir orbT. +rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply/IHn. +move: (Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. rewrite lognM// ?IHn//. rewrite big_seq_cond big_mkcond prodn_gt0// => i. by case /boolP: ((i \in r) && P i) => // /andP[/Fr0]. @@ -336,31 +385,32 @@ Qed. Lemma logn_partn (p n : nat) (pi : nat_pred) : logn p (n`_pi)%N = ((p \in pi) * logn p n)%N. Proof. -rewrite/partn logn_prod; last by move=> i _; rewrite pfactor_gt0. +rewrite /partn logn_prod; last by move=> i _; rewrite pfactor_gt0. under eq_bigr do rewrite lognX. have logp (i : nat): (i == p) || (logn i n * logn p i == 0)%N. case /boolP: (i == p) => //= /negPf ip. case /boolP: (prime i) => [|/negPf] iprim; last first. - by rewrite/logn iprim mul0n. + by rewrite /logn iprim mul0n. by rewrite (logn_prime _ iprim) [p == i]eq_sym ip muln0. case /boolP: (p < n.+1)%N => [plt |]; last first. rewrite -leqNgt => np. - suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i = \sum_(0 <= i < n.+1 | i \in pi) 0)%N. + suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i + = \sum_(0 <= i < n.+1 | i \in pi) 0)%N. by rewrite big_const_seq iter_addn_0 mul0n ltn_log0// muln0. - apply eq_bigr => i _. + apply/eq_bigr => i _. move: (logp i) => /orP [|]/eqP ->//. by rewrite ltn_log0// mul0n. -suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i = \sum_(i < n.+1 | pred1 (Ordinal plt) i) (p \in pi) * logn i n)%N. +suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i + = \sum_(i < n.+1 | pred1 (Ordinal plt) i) (p \in pi) * logn i n)%N. by rewrite (big_pred1 (Ordinal plt)). rewrite big_mkord big_mkcond/= [in RHS]big_mkcond/=. -apply eq_bigr => i _. +apply/eq_bigr => i _. have ->: (i == Ordinal plt = (val i == p)). - by apply/eqP/eqP => [/(congr1 val)// | ] ip; apply val_inj. + by apply/eqP/eqP => [/(congr1 val)// | ] ip; apply/val_inj. move: (logp i); case /boolP: (val i == p)%N => /= [|_] /eqP ->. 2: by case: (val i \in pi). -move=>_; case: (p \in pi); last by rewrite mul0n. -rewrite mul1n. -case /boolP: (prime p) => [| /negPf] pprim; last by rewrite/logn pprim. +move=> _; case: (p \in pi); rewrite ?mul0n// mul1n. +case /boolP: (prime p) => [| /negPf] pprim; last by rewrite /logn pprim. by rewrite -{3}(expn1 p) pfactorK// muln1. Qed. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index ccec87b..5c0857a 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -1195,16 +1195,16 @@ Lemma bigA_distr_bigA2 (R : Type) (zero one : R) (times : Monoid.mul_law zero) \big[times/one]_i plus (F i) (G i) = \big[plus/zero]_(J in {set I}) \big[times/one]_i (if i \in J then F i else G i). Proof. -transitivity (\big[times/one]_i \big[plus/zero]_(b : bool) if b then F i else G i); first by apply eq_bigr => i _; rewrite big_bool. +transitivity (\big[times/one]_i \big[plus/zero]_(b : bool) if b then F i else G i); first by apply: eq_bigr => i _; rewrite big_bool. rewrite bigA_distr_bigA. set f := fun J : {set I} => val J. transitivity (\big[plus/zero]_(f0 in (imset f (mem setT))) \big[times/one]_i (if f0 i then F i else G i)). - suff <-: setT = imset f (mem setT) by apply congr_big=>// i; rewrite in_setT. + suff <-: setT = imset f (mem setT) by apply: congr_big=>// i; rewrite in_setT. apply/esym/eqP; rewrite -subTset; apply/subsetP => b _. by apply/imsetP; exists (FinSet b). rewrite big_imset; last by case => g; case => h _ _; rewrite /f/= => ->. -apply congr_big=>//; case => g; first by rewrite in_setT. -move=>_; apply eq_bigr => i _; congr (if _ then _ else _). +apply: congr_big=>//; case => g; first by rewrite in_setT. +move=>_; apply: eq_bigr => i _; congr (if _ then _ else _). by rewrite SetDef.pred_of_setE. Qed. @@ -1218,18 +1218,18 @@ Proof. move=> nle. have psE: ps = tval (Tuple (eqxx (size ps))) by []. transitivity (\prod_(p <- ps) ((- p)%:P + 'X))`_n. - by congr ((polyseq _)`_n); apply eq_bigr => i _; rewrite addrC polyCN. + by congr ((polyseq _)`_n); apply: eq_bigr => i _; rewrite addrC polyCN. rewrite {1}psE -(map_tnth_enum (Tuple _)) big_map enumT bigA_distr_bigA2 /=. rewrite coef_sum. transitivity (\sum_(I in {set 'I_(size ps)}) if #|I| == (size ps - n)%N then \prod_(i < size ps | i \in I) - (tnth (Tuple (eqxx (size ps))) i) else 0). - apply eq_bigr => I _. + apply: eq_bigr => I _. rewrite big_if/= big_const iter_mulr_1. rewrite -(rmorph_prod (@polyC_rmorphism R))/= coefCM coefXn. rewrite -[#|I| == _](eqn_add2l n) addnBA// [(_ + (size ps))%N]addnC -addnBA// subnn addn0 [(n + _)%N]addnC. rewrite -[in X in _ = if _ == X then _ else _](card_ord (size ps)) -(cardC I) eqn_add2l. by case: (n == #|[predC I]|); rewrite ?mulr1 ?mulr0. -rewrite -big_mkcond mulr_sumr/=; apply eq_bigr => I /eqP cardI. -rewrite prodrN cardI; congr GRing.mul; apply eq_bigr => i _. +rewrite -big_mkcond mulr_sumr/=; apply: eq_bigr => I /eqP cardI. +rewrite prodrN cardI; congr GRing.mul; apply: eq_bigr => i _. by rewrite (tnth_nth (GRing.zero R)) -psE. Qed. @@ -1240,18 +1240,18 @@ Lemma coefPn_prod_XsubC {R : comRingType} (ps : seq R) : Proof. rewrite coefn_prod_XsubC ?leq_pred// => ps0. have ->: (size ps - (size ps).-1 = 1)%N. - by move: ps0; case: (size ps)=>// n _; apply subSnn. + by move: ps0; case: (size ps)=>// n _; apply: subSnn. rewrite expr1 mulN1r; congr GRing.opp. set f : 'I_(size ps) -> {set 'I_(size ps)} := fun a => [set a]. transitivity (\sum_(I in imset f (mem setT)) \prod_(i in I) ps`_i). - apply congr_big=>// I /=. + apply: congr_big=>// I /=. apply/cards1P/imsetP. by move=>[a ->]; exists a. by move=>[a _ ->]; exists a. rewrite big_imset/=; last by move=> i j _ _; rewrite/f => ij; apply/set1P; rewrite -ij set11. have psE: ps = tval (Tuple (eqxx (size ps))) by []. rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. -apply congr_big => // i; first by rewrite in_setT. +apply: congr_big => // i; first by rewrite in_setT. by move=>_; rewrite big_set1 (tnth_nth (GRing.zero R)) -psE. Qed. @@ -1261,14 +1261,14 @@ Lemma coefP0_prod_XsubC {R : comRingType} (ps : seq R) : Proof. rewrite coefn_prod_XsubC// subn0; congr GRing.mul. transitivity (\sum_(I in [set setT : {set 'I_(size ps)}]) \prod_(i in I) ps`_i). - apply congr_big=>// i/=. + apply: congr_big=>// i/=. apply/idP/set1P. by move=>/eqP cardE; apply/eqP; rewrite eqEcard subsetT cardsT card_ord cardE leqnn. by move=>->; rewrite cardsT card_ord. rewrite big_set1. have psE: ps = tval (Tuple (eqxx (size ps))) by []. rewrite [in RHS]psE -(map_tnth_enum (Tuple _)) big_map enumT. -apply congr_big => // i; first by rewrite in_setT. +apply: congr_big => // i; first by rewrite in_setT. by move=>_; rewrite (tnth_nth (GRing.zero R)) -psE. Qed. From 9a91e8af55beb40655d5e5891bada95803d6a7dc Mon Sep 17 00:00:00 2001 From: Cyril Cohen Date: Thu, 27 Apr 2023 14:37:56 +0200 Subject: [PATCH 09/14] Simplifications --- .nix/coq-overlays/mathcomp-abel/default.nix | 27 +++ theories/xmathcomp/artin_scheier.v | 131 ++++-------- theories/xmathcomp/temp.v | 216 +++++++------------- theories/xmathcomp/various.v | 15 ++ 4 files changed, 155 insertions(+), 234 deletions(-) create mode 100644 .nix/coq-overlays/mathcomp-abel/default.nix diff --git a/.nix/coq-overlays/mathcomp-abel/default.nix b/.nix/coq-overlays/mathcomp-abel/default.nix new file mode 100644 index 0000000..3e30d6e --- /dev/null +++ b/.nix/coq-overlays/mathcomp-abel/default.nix @@ -0,0 +1,27 @@ +{ coq, mkCoqDerivation, mathcomp, mathcomp-real-closed, lib, version ? null }: + +mkCoqDerivation { + + namePrefix = [ "coq" "mathcomp" ]; + pname = "abel"; + owner = "math-comp"; + + inherit version; + defaultVersion = with lib; with versions; switch [ coq.version mathcomp.version ] [ + { cases = [ (range "8.10" "8.15") (isGe "1.12.0") ]; out = "1.2.0"; } + { cases = [ (range "8.10" "8.14") (range "1.11.0" "1.12.0") ]; out = "1.1.2"; } + ] null; + + release."1.2.0".sha256 = "1picd4m85ipj22j3b84cv8ab3330radzrhd6kp0gpxq14dhv02c2"; + release."1.1.2".sha256 = "0565w713z1cwxvvdlqws2z5lgdys8lddf0vpwfdj7bpd7pq9hwxg"; + release."1.0.0".sha256 = "190jd8hb8anqsvr9ysr514pm5sh8qhw4030ddykvwxx9d9q6rbp3"; + + + propagatedBuildInputs = [ mathcomp.character mathcomp-real-closed ]; + + meta = with lib; { + description = "Abel - Galois and Abel - Ruffini Theorems"; + license = licenses.cecill-b; + maintainers = [ maintainers.cohencyril ]; + }; +} diff --git a/theories/xmathcomp/artin_scheier.v b/theories/xmathcomp/artin_scheier.v index 021011a..733faf0 100644 --- a/theories/xmathcomp/artin_scheier.v +++ b/theories/xmathcomp/artin_scheier.v @@ -22,112 +22,69 @@ Proof. by move: pchar => /andP[]. Qed. Let p0 : p%:R == 0 :> L. Proof. by move: pchar => /andP[_]. Qed. +Let p_gt0 : (0 < p)%N. +Proof. by apply: prime_gt0. Qed. + Let p1 : (1 < p)%N. Proof. by apply: prime_gt1. Qed. -Lemma ArtinScheier_factorize : - 'X^p - 'X - (x ^+ p - x)%:P = \prod_(i < p) ('X - (x + i%:R)%:P). +Let rs := [tuple x + i%:R | i < p]. + +Let AS := 'X^p - 'X - (x ^+ p - x)%:P. + +Let x_rs : x \in rs. Proof. -case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. -apply/eqP; rewrite -eqp_monic; first last. -- by apply: monic_prod_XsubC. -- apply/monicP; rewrite -addrA -opprD lead_coefDl ?lead_coefXn//. - by rewrite size_opp size_XaddC size_polyXn ltnS. -- rewrite eqp_sym -dvdp_size_eqp. - rewrite size_prod; last first. - move=> [i]/= _ _; apply/negP => /eqP - /(congr1 (fun p : {poly L} => size p)). - by rewrite size_XsubC size_polyC eqxx. - have ->: \big[addn/0%N]_(i < n.+1) size ('X - (x + (val i)%:R)%:P)%R = - \big[addn/0%N]_(i < n.+1) 2%N. - by apply: eq_bigr => i _; rewrite size_XsubC. - rewrite big_const_ord iter_addn_0. - rewrite -add1n mul2n -addnn addnA card_ord -addnBA// subnn addn0 add1n. - rewrite -addrA -opprD size_addl size_polyXn// size_opp size_XaddC ltnS. - by move: pchar => /andP [ /prime_gt1 ]. - have: all (root ('X^n.+1 - 'X - (x ^+ n.+1 - x)%:P)) - [seq (x + (val i)%:R) | i : 'I_n.+1]. - apply/allP => + /mapP [i _ ->] => _. - rewrite /root !hornerE ?hornerXn -(Frobenius_autE nchar (x + (val i)%:R)). - (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) - rewrite rmorphD/= rmorph_nat (Frobenius_autE nchar x). - rewrite opprB opprD addrACA -addrA 2![x+_]addrA subrr add0r. - by rewrite addrAC addrCA subrr addr0 addrC subrr. - move=> /uniq_roots_dvdp; rewrite big_map big_enum/=; apply. - rewrite uniq_rootsE; apply/(uniqP 0) => i j. - rewrite 2!inE size_map => ilt jlt. - do 2 rewrite (nth_map ord0 _ (fun i : 'I_n.+1 => x + i%:R))//. - move=> /addrI/esym/eqP. - set ip := nth ord0 (enum 'I_n.+1) i. - set jp := nth ord0 (enum 'I_n.+1) j. - move=> ijE. - suff: jp = ip. - rewrite /ip /jp => /esym ijE0. - by move: (enum_uniq ('I_n.+1)) => /uniqP - /(_ i j ilt jlt ijE0). - move: ijE. - wlog ij : {i} {j} {ilt} {jlt} ip jp / (val ip <= val jp)%N. - move=> h. - move: (Order.TotalTheory.le_total (val ip) (val jp)) => /orP; case => ij. - by apply: h. - by rewrite eq_sym => ijE; apply/esym/h. - rewrite -subr_eq0 -natrB// -(dvdn_charf nchar). - case /posnP: (val jp - val ip)%N. - move=> /eqP; rewrite subn_eq0 => ji _; apply/val_inj/eqP. - by rewrite Order.POrderTheory.eq_le; apply/andP; split. - move=> ij0 /(dvdn_leq ij0); rewrite ltn_subRL -addnS. - move=> /(leq_trans (leq_addl _ _)). - have: (val jp < n.+1)%N by case: jp ij ij0. - by rewrite ltnS => jle; move => /(leq_ltn_trans jle); rewrite ltnn. +apply/tnthP; exists (Ordinal p_gt0). +by rewrite tnth_map/= tnth_ord_tuple/= addr0. Qed. -Lemma ArtinSchreier_splitting : - splittingFieldFor E ('X^p - 'X - (x ^+ p - x)%:P) <>%AS. +Lemma ArtinSchreier_factorize : AS = \prod_(i < p) ('X - (x + i%:R)%:P). +Proof. +have sNXXp : (size ('X : {poly L}) < size ('X^p : {poly L}))%N. + by rewrite size_polyXn size_polyX. +have sCXp (c : L) : (size c%:P < size ('X^p : {poly L}))%N. + by rewrite size_polyXn ltnS (leq_trans (size_polyC_leq1 _)) ?prime_gt0. +have lcLHS : lead_coef ('X^p - 'X - (x ^+ p - x)%:P) = 1. + by rewrite !lead_coefDl ?lead_coefXn ?scale1r// ?size_addl ?size_opp. +rewrite [LHS](@all_roots_prod_XsubC _ _ rs). +- by rewrite lcLHS scale1r big_map big_enum. +- by rewrite size_tuple ?size_addl ?size_opp// size_polyXn. +- apply/allP => y /mapP[/= i _ ->]; rewrite rootE !hornerE hornerXn. + rewrite -!Frobenius_autE rmorphD rmorph_nat. + by rewrite opprD addrACA subrr addr0 subrr. +- by rewrite uniq_rootsE/= map_inj_uniq ?enum_uniq// => i j /addrI/ZprI; apply. +Qed. + +Let ASE : AS = \prod_(i <- rs) ('X - i%:P). +Proof. by rewrite ArtinSchreier_factorize big_image/=. Qed. + +Lemma ArtinSchreier_splitting : splittingFieldFor E AS <>%AS. Proof. -exists ([seq x + (val i)%:R | i :'I_p]). - by rewrite ArtinScheier_factorize big_map big_enum/= eqpxx. -apply/eqP; rewrite eqEsubv; apply/andP; split. - apply/Fadjoin_seqP; split; first by apply: subv_adjoin. - move=> + /mapP [i _ ->] => _. - apply: (@rpredD _ _ (memv_addrPred <>%AS)); - first by apply: memv_adjoin. - by apply: rpred_nat. -apply/FadjoinP; split; first by apply: subv_adjoin_seq. -case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. -apply/seqv_sub_adjoin/mapP; exists ord0; first by apply: mem_enum. -by rewrite addr0. +exists rs; first by rewrite ASE eqpxx. +have /eq_adjoin-> : rs =i x :: rem x rs by apply/perm_mem/perm_to_rem. +rewrite adjoin_cons (Fadjoin_seq_idP _)//=. +apply/allP => y /mem_rem /mapP[i _ ->]/=. +by rewrite rpredD ?memv_adjoin// subvP_adjoin// rpredMn// rpred1. Qed. -Lemma ArtinSchreier_polyOver : - 'X^p - 'X - (x ^+ p - x)%:P \is a polyOver E. +Lemma ArtinSchreier_polyOver : AS \is a polyOver E. Proof. by rewrite rpredB ?polyOverC// rpredB ?rpredX// polyOverX. Qed. -Lemma ArtinSchreier_galois : - galois E <>. +Lemma ArtinSchreier_galois : galois E <>. Proof. apply/splitting_galoisField; exists ('X^p - 'X - (x ^+ p - x)%:P); split. - exact ArtinSchreier_polyOver. - rewrite /separable_poly derivB derivC subr0 derivB derivXn derivX -scaler_nat. - move: pchar; rewrite inE => /andP[_ /eqP ->]. - rewrite scale0r add0r. - apply/Bezout_eq1_coprimepP; exists (0, (-1)) => /=. - by rewrite mul0r add0r mulN1r opprK. + rewrite charf0// scale0r add0r -(@coprimepZr _ (-1)) ?oppr_eq0 ?oner_eq0//. + by rewrite scaleNr scale1r opprK coprimep1. - by apply: ArtinSchreier_splitting. Qed. -Lemma minPoly_ArtinSchreier : (x \notin E) -> - minPoly E x = 'X^p - 'X - (x ^+ p - x)%:P. +Lemma minPoly_ArtinSchreier : x \notin E -> minPoly E x = AS. Proof. -move=> xE. -have pE: ('X^p - 'X - (x ^+ p - x)%:P) = - \prod_(i <- [seq x + (val i)%:R | i : 'I_p]) ('X - i%:P). - by rewrite ArtinScheier_factorize big_map; apply: congr_big; rewrite // enumT. -have /(minPoly_dvdp ArtinSchreier_polyOver): - root ('X^p - 'X - (x ^+ p - x)%:P) x. - rewrite pE root_prod_XsubC. - case: p pchar pprim p0 p1 => // n nchar nprim n0 n1. - by apply/mapP; exists ord0; rewrite ?mem_enum ?addr0. -rewrite pE => /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; +move=> xE; have /(minPoly_dvdp ArtinSchreier_polyOver) : root AS x. + by rewrite ASE root_prod_XsubC. +rewrite ASE => /dvdp_prod_XsubC[m]; rewrite eqp_monic ?monic_minPoly//; last by rewrite monic_prod// => i _; rewrite monic_XsubC. rewrite -map_mask. have [{}m sm ->] := resize_mask m (enum 'I_p). diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v index 38c2810..9fc136b 100644 --- a/theories/xmathcomp/temp.v +++ b/theories/xmathcomp/temp.v @@ -29,7 +29,7 @@ split => /=. Qed. Lemma polyOver_mulr_2closed [R : ringType] [S : {pred R}] - [addS : addrPred S] (kS : keyed_pred addS) : + [addS : addrPred S] (kS : keyed_pred addS) : GRing.mulr_2closed kS -> GRing.mulr_2closed (polyOver kS). Proof. move=> SM u vz /polyOverP uS /polyOverP vS; apply/polyOverP => i. @@ -64,7 +64,7 @@ Qed. Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. Proof. -move=> ->. +move=> ->. suff ->: (1+U)%VS = U by rewrite subfield_closed. rewrite -{2}(subfield_closed U) (agenvEr U) subfield_closed. by congr (1 + _)%VS; apply/esym/field_module_eq; rewrite sup_field_module. @@ -146,7 +146,7 @@ case: (IHn [:: s0 & f] by rewrite /k'; case: splitP => // [[j]]/=/[swap]<-. move=> [y [yE fne0]]; right. case /boolP: - (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) + (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) => [| yne0]; last by exists y. rewrite big_ord_recl/= addrC addr_eq0 {2}/tnth/= => /eqP. under eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)); move=> y0. @@ -159,20 +159,24 @@ rewrite addrC [in RHS]big_ord_recl {2}/tnth/=. by under [in RHS]eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)). Qed. -Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) +Lemma big_condT [R : Type] [idx : R] (op : Monoid.com_law idx) + [I : finType] (A : {pred I}) (F : I -> R) : + \big[op/idx]_(i in A | true) F i = \big[op/idx]_(i in A) F i. +Proof. by rewrite big_mkcondr. Qed. + +Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) [I : finType] (F : I -> R) : \big[op/idx]_(i in [set: I]) F i = \big[op/idx]_i F i. -Proof. by apply/congr_big => // i; rewrite in_setT. Qed. +Proof. by under eq_bigl do rewrite inE. Qed. -Lemma galTrace_ne_0 (F : fieldType) (L : splittingFieldType F) +Lemma galTrace_neq0 (F : fieldType) (L : splittingFieldType F) (K E : {subfield L}) : exists a, a \in E /\ galTrace K E a != 0. Proof. set l := enum [set: gal_of E]. -case: (gal_free - (fun i : 'I_(size l) => - (1 *+ ((tnth (in_tuple l) i) \in (galoisG E K) : nat))%:A) - (enum_uniq _)). - have /[dup] l1: 1%g \in l by rewrite mem_enum. +have [] := gal_free + (fun i : 'I_(size l) => (tnth (in_tuple l) i \in 'Gal(E / K)%G)%:R%:A) + (enum_uniq _). + have /[dup] l1 : 1%g \in l by rewrite mem_enum. rewrite -index_mem => lt1 /(_ (Ordinal lt1))/=/eqP. by rewrite /tnth (nth_index _ l1) group1/= scaler_eq0 2!oner_eq0. move=> [x [xE s0]]; exists x; split => //. @@ -192,6 +196,8 @@ move=> a f IHf. by rewrite 2!big_cons ffunE IHf. Qed. +(** Alternative: *) +(* Definition Zp_succ n : 'I_n -> 'I_n := if n is n.+1 then +%R ord_max else id. *) Definition Zp_succ n (i : 'I_n) := match i with @@ -206,7 +212,7 @@ Definition Zp_succ n (i : 'I_n) := (* Ah non, je change le domaine d'indexation, ce lemme est spécifique aux * éléments d'ordre fini d'un groupe. *) Lemma cycle_imset [gT : finGroupType] (g : gT) : - <[g]>%g = ([set g ^+ (val i) | i : 'I_#[g]])%g. + (<[g]> = [set g ^+ i | i : 'I_#[g]])%g. Proof. apply/eqP; rewrite eqEsubset; apply/andP; split; apply/subsetP => x. move=> /cycleP [i ->]; apply/imsetP. @@ -216,23 +222,16 @@ by move=> /imsetP [i] _ ->; apply/cycleP; exists i. Qed. Lemma cycle_imset_inj [gT : finGroupType] (g : gT) : - injective (fun i : 'I_(#[g]) => (g ^+ i))%g. + injective (fun i : 'I_#[g] => g ^+ i)%g. Proof. move=> [i ilt] [j jlt] /eqP; rewrite eq_expg_mod_order. rewrite modn_small// modn_small// => /eqP ijE. by apply/val_inj. Qed. -Lemma big_condT [R : Type] [idx : R] (op : Monoid.com_law idx) - [I : finType] (A : {pred I}) (F : I -> R) : - \big[op/idx]_(i in A | true) F i = \big[op/idx]_(i in A) F i. -Proof. -rewrite big_mkcondr. -by apply/congr_big => // i; rewrite andbT. Qed. - Lemma Hilbert's_theorem_90_additive - [F : fieldType] [L : splittingFieldType F] - [K E : {subfield L}] [x : gal_of E] + [F : fieldType] [L : splittingFieldType F] + [K E : {subfield L}] [x : gal_of E] [a : L] : galois K E -> generator 'Gal(E / K) x -> @@ -240,66 +239,40 @@ Lemma Hilbert's_theorem_90_additive reflect (exists2 b : L, b \in E & a = b - x b) (galTrace K E a == 0). Proof. -move=> Egal /(_ =P <[x]>%g) DgalE Ea. +move=> Egal /eqP DgalE Ea. have galEx: x \in 'Gal(E / K)%g by rewrite DgalE cycle_id. -apply: (iffP eqP) => [normEa1 | [b Eb ->]]; last first. +apply: (iffP eqP) => [normEa0 | [b Eb ->]]; last first. by rewrite raddfB/= galTrace_gal// subrr. -move: (galTrace_ne_0 K E) => [b [bE tb]]. -remember (\dim_K E) as n. +have [b [bE tb]] := galTrace_neq0 K E. +move Heqn : (\dim_K E) => n. have ordx: #[x]%g = n by rewrite orderE -DgalE -(galois_dim Egal). -move: (expg_order x); rewrite ordx => xord. -move: (Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). +have xXn : (x ^+ n = 1)%g by rewrite -ordx orderE expg_order. +move: (Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). rewrite mul0n adim_gt0 => dimgt0 /(_ 1%N); rewrite mul1n => dimgt1. -case: n => [|n] in Heqn ordx xord *; first by move: dimgt0; rewrite -Heqn. -case: n => [|n] in Heqn ordx xord *. - move: dimgt1; rewrite -Heqn ltnn => /esym/negbT; rewrite -leqNgt => dimEK. - move: (eqEdim K E); rewrite dimEK (galois_subW Egal) => /=/eqP KE. - move: normEa1; rewrite /galTrace. - have ->: \sum_(x0 in ('Gal(E / K))%g) x0 a = \sum_(x0 in ('Gal(E / K))%g) a. - apply/eq_bigr => f fgal. - move: Egal => /galois_fixedField Kfix. - by move: (Ea); rewrite -{1}KE -Kfix => /fixedFieldP => /(_ Ea f fgal). - rewrite sumr_const; rewrite -(galois_dim Egal) -Heqn mulr1n => a0. - by exists a => //; rewrite a0 rmorph0 subr0. -set c := (galTrace K E b)^-1 - * \sum_(i < n.+1) (\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. -have tbE: galTrace K E b \in E. - by rewrite /galTrace rpred_sum// => f _; apply/memv_gal. +case: n => [|n] in Heqn ordx xXn *; first by move: dimgt0; rewrite Heqn. +have trE d : d \in E -> galTrace K E d = \sum_(0 <= i < n.+1) (x ^+ i)%g d. + move=> dE; rewrite /galTrace DgalE cycle_imset => /=. + by rewrite (big_imset _ (in2W (@cycle_imset_inj _ x))) /= ordx big_mkord. +have trI d : d \in E -> \sum_(0 <= i < n) (x ^+ i.+1)%g d = galTrace K E d - d. + by move=> dE; rewrite trE// [in RHS]big_nat_recl//= expg0 gal_id addrC addKr. +set c : L := (galTrace K E b)^-1 + * \sum_(0 <= i < n) (\sum_(0 <= j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. +have tr_b_E : galTrace K E b \in E by rewrite rpred_sum// => * /[!memv_gal]. exists c. - apply/rpredM; first by rewrite rpredV. - rewrite rpred_sum// => i _. - apply/rpredM; last by apply/memv_gal. - by rewrite rpred_sum// => j _; apply/memv_gal. -rewrite /c rmorphM/= rmorphV/= ?unitfE//. -move: (galTrace_fixedField K bE) => /fixedFieldP => /(_ tbE x galEx) ->. -rewrite -mulrBr rmorph_sum/=. -rewrite big_ord_recl big_ord1 expg0 gal_id expg1 big_ord_recr/=. -rewrite opprD addrAC [_ - x _]addrC addrA -addrA [- _ + _]addrC -sumrB. -have ->: \sum_(i < n) - ((\sum_(j < (bump 0 i).+1) (x ^+ j)%g a) * (x ^+ (bump 0 i).+1)%g b - - x ((\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b)) = - \sum_(i < n) a * (x ^+ i.+2)%g b. - apply/eq_bigr; case => i ilt _ /=. - rewrite /bump/= add1n rmorphM/= rmorph_sum/= expgSr galM// -mulrBl. - congr *%R. - rewrite big_ord_recl/= -addrA -sumrB expg0 gal_id -[in RHS](addr0 a). - congr (a + _). - transitivity (\sum_(j < i.+1) (0 : L)); last by rewrite sumr_const mul0rn. - by apply/eq_bigr => j _; rewrite /bump/= add1n expgSr galM// subrr. -rewrite -mulr_sumr rmorphM/= rmorph_sum/=. -have tE: forall d, d \in E -> galTrace K E d = \sum_(i < n.+2) (x ^+ i)%g d. - move=> d dE. - rewrite /galTrace DgalE cycle_imset => /=. - by rewrite (big_imset _ (in2W (@cycle_imset_inj _ x))) /= ordx. -move: normEa1; rewrite tE// big_ord_recl expg0 gal_id => /eqP. -under [in X in X -> _]eq_bigr do rewrite /= /bump/= add1n expgSr galM//. -rewrite addrC addr_eq0 => /eqP ->. -rewrite mulNr opprK -2!mulrDr mulrCA -(galM _ x bE). -rewrite -expgSr xord gal_id [x b + b]addrC. -have <-: galTrace K E b = b + x b + \sum_(i < n) (x ^+ i.+2)%g b. - rewrite (tE b bE) big_ord_recl/= expg0 gal_id big_ord_recl/= expg1 addrA. - by under eq_bigr do rewrite /bump/= 2!add1n. -by rewrite mulVf// mulr1. + rewrite rpredM// ?rpredV// ?rpred_sum// => i _. + by rewrite rpredM//= ?memv_gal// rpred_sum// => j _; rewrite memv_gal. +rewrite rmorphM/= rmorphV/= ?unitfE//. +rewrite (fixedFieldP _ (galTrace_fixedField K bE))// -mulrBr rmorph_sum/=. +pose f i := (\sum_(1 <= j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. +have := @telescope_sumr _ 0 n f isT. +rewrite /f (@big_geq _ _ _ 1 1)// mul0r subr0 sumrB => /(canRL (addrK _)). +rewrite big_add1/= trI// normEa0 sub0r opprK addrC. +under eq_bigr => i. + rewrite big_add1; under eq_bigr => j do rewrite expgSr galM//. + by rewrite expgSr galM// -rmorph_sum/= -rmorphM /=; over. +move->; rewrite opprD addrA -sumrB xXn gal_id mulNr opprK. +under eq_bigr do rewrite big_nat_recl// expg0 gal_id big_add1/= mulrDl addrK. +by rewrite -mulr_sumr trI// mulrBr addrNK mulrCA mulVf ?mulr1. Qed. Lemma natf_partn_ne0 (R : idomainType) n : @@ -329,89 +302,38 @@ Qed. Lemma primes_dvdn (m n : nat) : (0 < n)%N -> (m %| n)%N -> primes m = [seq p <- primes n | p \in primes m]. Proof. -move=> n0 mn. -apply/Order.POrderTheory.lt_sorted_eq. -- apply/sorted_primes. -- apply/sorted_filter. - apply/Order.POrderTheory.lt_trans. -apply/sorted_primes. -- move=> p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. -rewrite 2!mem_primes => /andP[->/=]/andP[m0 pm]. -by rewrite n0/=; apply/(dvdn_trans pm). +move=> n0 mn; apply/(irr_sorted_eq ltn_trans ltnn (sorted_primes _)). + by rewrite sorted_filter ?sorted_primes//; apply: ltn_trans. +move=> p; rewrite mem_filter; case: (boolP (_ \in _)) => //. +rewrite !mem_primes => /and3P[p_prime m_gt0 dvd_pm]/=. +by rewrite p_prime n0//= (dvdn_trans dvd_pm). Qed. -Lemma dvdn_leq_logP (m n : nat) : - (0 < n)%N -> (0 < m)%N -> +Lemma dvdn_leq_logP (m n : nat) : (0 < m)%N -> (0 < n)%N -> reflect (forall p, prime p -> logn p m <= logn p n)%N (m %| n)%N. Proof. -move=> n0 m0; apply/(iffP idP) => [mn p prim | vp_leq]. - by apply/dvdn_leq_log. -apply/dvdnP; exists (\prod_(p <- primes n) p ^ (logn p n - logn p m))%N. -rewrite {1}(prod_prime_decomp n0) {2}(prod_prime_decomp m0). -rewrite 2!prime_decompE 2!big_map/=. -have ->: primes m = [seq i <- primes n | i \in primes m]. - apply/Order.POrderTheory.lt_sorted_eq. - - apply/sorted_primes. - - apply/sorted_filter. - apply/Order.POrderTheory.lt_trans. - apply/sorted_primes. - - move=> p; rewrite mem_filter. - apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. - move=> /[dup]; rewrite {1}mem_primes => /andP[pprim _]. - rewrite -2!logn_gt0 => pm. - apply/(leq_trans pm (vp_leq p pprim)). -rewrite big_filter [in X in (_ * X)%N]big_mkcond/= -big_split/= 2!big_seq. -apply/eq_bigr => p; rewrite mem_primes => /andP[pprim _]. -have ->: ((if p \in primes m then p ^ logn p m else 1) = p ^ logn p m)%N. - case/boolP: (p \in primes m) => //. - by rewrite -logn_gt0 lt0n negbK => /eqP ->; rewrite expn0. -by rewrite -expnD subnK// vp_leq. +move=> m0 n0; apply/(iffP idP) => [mn p prim | vp_le]; first exact/dvdn_leq_log. +apply/dvdn_partP => // p /[!(inE, mem_primes)]/and3P[p_prime _ pm]. +by rewrite p_part pfactor_dvdn// vp_le. Qed. -Lemma logn_prod [I : eqType] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : - {in r, forall n, P n -> (0 < F n)%N} -> +Lemma logn_prod [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : + (forall n, P n -> (0 < F n)%N) -> (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. Proof. -elim: r => [|n r IHn Fnr0]; first by rewrite 2!big_nil logn1. -have Fr0: {in r, forall n : I, P n -> (0 < F n)%N}. - by move=> i ir; apply/Fnr0; rewrite in_cons ir orbT. -rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply/IHn. -move: (Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. -rewrite lognM// ?IHn//. -rewrite big_seq_cond big_mkcond prodn_gt0// => i. -by case /boolP: ((i \in r) && P i) => // /andP[/Fr0]. +move=> F_gt0; elim/(big_load (fun n => (n > 0)%N)): _. +elim/big_rec2: _; first by rewrite logn1. +by move=> i m n Pi [n_gt0 <-]; rewrite muln_gt0 lognM ?F_gt0. Qed. Lemma logn_partn (p n : nat) (pi : nat_pred) : logn p (n`_pi)%N = ((p \in pi) * logn p n)%N. Proof. -rewrite /partn logn_prod; last by move=> i _; rewrite pfactor_gt0. -under eq_bigr do rewrite lognX. -have logp (i : nat): (i == p) || (logn i n * logn p i == 0)%N. - case /boolP: (i == p) => //= /negPf ip. - case /boolP: (prime i) => [|/negPf] iprim; last first. - by rewrite /logn iprim mul0n. - by rewrite (logn_prime _ iprim) [p == i]eq_sym ip muln0. -case /boolP: (p < n.+1)%N => [plt |]; last first. - rewrite -leqNgt => np. - suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i - = \sum_(0 <= i < n.+1 | i \in pi) 0)%N. - by rewrite big_const_seq iter_addn_0 mul0n ltn_log0// muln0. - apply/eq_bigr => i _. - move: (logp i) => /orP [|]/eqP ->//. - by rewrite ltn_log0// mul0n. -suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i - = \sum_(i < n.+1 | pred1 (Ordinal plt) i) (p \in pi) * logn i n)%N. - by rewrite (big_pred1 (Ordinal plt)). -rewrite big_mkord big_mkcond/= [in RHS]big_mkcond/=. -apply/eq_bigr => i _. -have ->: (i == Ordinal plt = (val i == p)). - by apply/eqP/eqP => [/(congr1 val)// | ] ip; apply/val_inj. -move: (logp i); case /boolP: (val i == p)%N => /= [|_] /eqP ->. - 2: by case: (val i \in pi). -move=> _; case: (p \in pi); rewrite ?mul0n// mul1n. -case /boolP: (prime p) => [| /negPf] pprim; last by rewrite /logn pprim. -by rewrite -{3}(expn1 p) pfactorK// muln1. +have [p_prime|pNprime] := boolP (prime p); last first. + by rewrite /logn !ifN// muln0. +have [ppi|pNpi] := boolP (p \in pi); last first. + by rewrite mul0n logn_coprime// (@p'nat_coprime pi) ?part_pnat// pnatE. +by rewrite mul1n -logn_part partn_part ?logn_part// => i /eqP->. Qed. End Temp. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index 5c0857a..e1614e0 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -296,6 +296,21 @@ by move=> x xreal; rewrite conj_Creal. Qed. End ssrnum. +(*********) +(* zmodp *) +(*********) + +Lemma ZprI p (F : fieldType) : p \in [char F] -> + injective (GRing.natmul 1 : 'I_p -> F). +Proof. +move=> pchar i j; wlog leij : i j / (j <= i)%N => [hwlog|]. + by have [/hwlog/[apply]//|/ltnW/hwlog+/esym] := leqP j i => /[apply]. +move=> /eqP; rewrite -subr_eq0 -mulrnBr// -(dvdn_charf pchar) => /eqP ijMp0. +apply/eqP; rewrite -val_eqE eqn_leq/= leij andbT -subn_eq0. +rewrite (divn_eq (i - j) p) ijMp0 addn0 divn_small// ltn_subLR//. +by rewrite (@leq_trans p)// leq_addl. +Qed. + (**********) (* ssrint *) (**********) From d46aeddfc2dafea815de883f64eb432385761fb0 Mon Sep 17 00:00:00 2001 From: Cyril Cohen Date: Fri, 21 Jul 2023 12:49:08 +0200 Subject: [PATCH 10/14] set -> pose --- theories/xmathcomp/temp.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v index 9fc136b..3b74671 100644 --- a/theories/xmathcomp/temp.v +++ b/theories/xmathcomp/temp.v @@ -255,7 +255,7 @@ have trE d : d \in E -> galTrace K E d = \sum_(0 <= i < n.+1) (x ^+ i)%g d. by rewrite (big_imset _ (in2W (@cycle_imset_inj _ x))) /= ordx big_mkord. have trI d : d \in E -> \sum_(0 <= i < n) (x ^+ i.+1)%g d = galTrace K E d - d. by move=> dE; rewrite trE// [in RHS]big_nat_recl//= expg0 gal_id addrC addKr. -set c : L := (galTrace K E b)^-1 +pose c : L := (galTrace K E b)^-1 * \sum_(0 <= i < n) (\sum_(0 <= j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. have tr_b_E : galTrace K E b \in E by rewrite rpred_sum// => * /[!memv_gal]. exists c. From 77a6cf704e7ad06e44020e7f9d0282541c6ee8d7 Mon Sep 17 00:00:00 2001 From: qvermande Date: Fri, 21 Jul 2023 16:32:48 +0200 Subject: [PATCH 11/14] started cleaning temp --- theories/abel.v | 35 +--- theories/xmathcomp/temp.v | 384 +---------------------------------- theories/xmathcomp/various.v | 383 ++++++++++++++++++++++++++++++++++ 3 files changed, 387 insertions(+), 415 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 73efdc9..5450c2c 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -125,33 +125,6 @@ Section Properties. Implicit Types r : {vspace L} -> L -> nat -> bool. Implicit Types (U V : {subfield L}). -(* TODO: rename and move to the proper place *) -Lemma prim_root_natf_neq0 (w : L) (n : nat) : - n.-primitive_root w -> n%:R != (0 : F0). -Proof. -case: n => // n /andP[_ /forallP w1]. -rewrite natf_neq0; apply/andP; split=> //. -rewrite -(negbK (all _ _)) -has_predC. -apply/negP => /hasP[p]; rewrite mem_primes => /and3P[p_prime _ /dvdnP][]. -case=> // m nE. -rewrite /negn inE negbK => /andP [_ p0]. -have: p \in [char L] by rewrite (char_lalg L) inE; apply/andP; split=> //. -move=> {p0} p_char. -move: (w1 (Ordinal (ltnSn n))) => /= /eqP. -rewrite eqxx /root_of_unity /root !hornerE ?hornerXn. - (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) -rewrite nE exprM -(@expr1n _ p). -rewrite -(Frobenius_autE p_char (w ^+ m.+1)) -(Frobenius_autE p_char 1). -rewrite subr_eq0 => /eqP/fmorph_inj wm1. -have mn: (m.+1 < n.+1)%N. - by rewrite nE; apply: ltn_Pmulr => //; apply: prime_gt1. - have: ((Ordinal (ltn_trans (ltnSn m) mn)).+1).-unity_root w. - by rewrite /root_of_unity /root/= !hornerE ?hornerXn wm1 subrr. - (* FIXME: remove ?hornerXn when requiring MC >= 1.16.0 *) -move: (w1 (Ordinal (ltn_trans (ltnSn m) mn))) => /eqP -> /= /eqP mnE. -by move: mn; rewrite mnE ltnn. -Qed. - Lemma rext_refl r (E : {subfield L}) : r.-ext E E. Proof. by exists trivExt; rewrite ?Fadjoin_nil//=; apply/towerP => -[]. Qed. @@ -301,7 +274,9 @@ Lemma radicalext_Fadjoin_cyclotomic (E : {subfield L}) (w : L) (n : nat) : n.-primitive_root w -> radical.-ext E <>%AS. Proof. move=> wprim; apply: (@radical_ext_Fadjoin1 n w E). - exact: (prim_root_natf_neq0 wprim). + apply/negP => /eqP n0. + move: (prim_root_natf_neq0 wprim). + by rewrite -scaler_nat n0 scale0r eqxx. by rewrite (prim_expr_order wprim) mem1v. Qed. @@ -537,7 +512,6 @@ apply: (IHk (w ^+ (n`_[char L]^' %/ p`_[char L]^'))) => /=. - by rewrite gal_fixedField (solvableS (normal_sub Hnormal)). Qed. -(* TODO : remove wprim *) Lemma galois_solvable_by_radical w E F (n := \dim_E F) : (n`_[char L]^')%N.-primitive_root w -> galois E F -> solvable 'Gal(F / E) -> solvable_by radical E F. @@ -559,7 +533,6 @@ by rewrite (solvableS _ solEF) ?galS// subv_cap EF. Qed. (* Main lemma of part 1 *) -(* TODO : remove wprim *) Lemma ext_solvable_by_radical w E F (n := \dim_E (normalClosure E F)) : (n`_[char L]^')%N.-primitive_root w -> solvable_ext E F -> @@ -816,8 +789,6 @@ move=> /normalClosure_galois /[swap] EF /[swap] /(normalClosure_id EF) ->. by apply: galois_solvable. Qed. -(* TODO: check if there is another way to write the first hypothesis. *) - Lemma AbelGaloisPoly (F : fieldType) (p : {poly F}) : separable_splittingField p -> solvable_ext_poly p <-> solvable_by_radical_poly p. diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v index 38c2810..b9efc4c 100644 --- a/theories/xmathcomp/temp.v +++ b/theories/xmathcomp/temp.v @@ -1,7 +1,4 @@ -From mathcomp Require Import all_ssreflect all_fingroup all_algebra. -From mathcomp Require Import all_solvable all_field polyrcf. -From Abel Require Import various classic_ext map_gal algR. -From Abel Require Import char0 cyclotomic_ext real_closed_ext artin_scheier. +From mathcomp Require Import all_ssreflect. Set Implicit Arguments. Unset Strict Implicit. @@ -16,181 +13,10 @@ Section Temp. (* NB : rpredM and mulrPred uses that 1 is in the subset, which is useless. Predicates should be defined for {aspace aT}. *) -Lemma memv_mulr_2closed [K : fieldType] [aT : FalgType K] (U : {aspace aT}) : - GRing.mulr_2closed U. -Proof. -move: U => [U]/[dup]/andP[_ /subvP UU] Ualg. -move=> u v uU vU; apply/UU/memv_mulP. -exists 1%N, (@Tuple _ _ [:: u] (eqxx _)), (@Tuple _ _ [:: v] (eqxx _)). -split => /=. -- by rewrite uU. -- by rewrite vU. -- by rewrite big_ord1 2!(tnth_nth 1)/=. -Qed. -Lemma polyOver_mulr_2closed [R : ringType] [S : {pred R}] - [addS : addrPred S] (kS : keyed_pred addS) : - GRing.mulr_2closed kS -> GRing.mulr_2closed (polyOver kS). -Proof. -move=> SM u vz /polyOverP uS /polyOverP vS; apply/polyOverP => i. -by rewrite coefM rpred_sum // => j _; apply/SM. -Qed. -Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] - (f g : 'AHom(K, rT)) (U : {subfield K}) (x : K) : - {in U, f =1 g} -> f x = g x -> {in <>%VS, f =1 g}. -Proof. -move=> fgU fgx y /Fadjoin_poly_eq <-. -move: (Fadjoin_poly U x y) (Fadjoin_polyOver U x y) => p /polyOverP pU. -rewrite -(coefK p) horner_poly 2!rmorph_sum/=; apply/eq_bigr => i _. -by rewrite 2!rmorphM /= fgU// 2!rmorphX/= fgx. -Qed. -Lemma ahom_eq_adjoin_seq [F0 : fieldType] [K : fieldExtType F0] - [rT : FalgType F0] (f g : 'AHom(K, rT)) (U : {aspace K}) (xs : seq K) : - {in U, f =1 g} -> {in xs, forall x, f x = g x} -> {in <>%VS, f =1 g}. -Proof. -elim: xs U => [|x xs IHxs] U fgU fgxs. - by rewrite adjoin_nil subfield_closed. -rewrite adjoin_cons. -have ->: <>%VS = ASpace (agenv_is_aspace <>%VS) - by rewrite /= agenv_id. -move: fgxs (IHxs (ASpace (agenv_is_aspace <>))) => fgxs /=. -rewrite agenv_id; apply. - by apply/ahom_eq_adjoin/fgxs => //; apply/mem_head. -by move=> a axs; apply/fgxs; rewrite in_cons axs orbT. -Qed. -Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) - (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. -Proof. -move=> ->. -suff ->: (1+U)%VS = U by rewrite subfield_closed. -rewrite -{2}(subfield_closed U) (agenvEr U) subfield_closed. -by congr (1 + _)%VS; apply/esym/field_module_eq; rewrite sup_field_module. -Qed. - -Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) - (f g : gal_of E) : f = g \/ exists x, x \in E /\ f x != g x. -Proof. -move: (vbasisP E) => /span_basis/agenv_span LE. -case /boolP: (all (fun x => f x == g x) (vbasis E)) - => [/allP fgE | /allPn[x] xE fgx]; [ left | right ]. - 2: by exists x; split => //; apply/vbasis_mem. -apply/eqP/gal_eqP. -rewrite -{1}LE; apply/ahom_eq_adjoin_seq => //; last by move=> x /fgE/eqP. -move: (gal1 f)(gal1 g). -rewrite gal_kHom ?sub1v// gal_kHom ?sub1v//. -move=> /andP [_ /subvP f1] /andP [_ /subvP g1]. -by move=> x /[dup] /f1/fixedSpaceP -> /g1/fixedSpaceP ->. -Qed. - -Lemma tnth_cons (T : Type) (x : T) (l : seq T) (i : 'I_(size l)) : - tnth (in_tuple (x :: l)) (lift ord0 i) = tnth (in_tuple l) i. -Proof. by rewrite /tnth/=; apply/set_nth_default. Qed. - -(* TODO : generalize to independance of characters *) - -Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) - (E : {subfield L}) (f : seq (gal_of E)) (k : 'I_(size f) -> L) : - uniq f -> - (forall i, k i = 0) \/ - (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). -Proof. -move: {1}(size f) (Logic.eq_refl (size f)) => n. -elim: n f k => [|n IHn] f k fsize funiq. - by left; case; move: k; rewrite -fsize. -case: f => [|s f] in k fsize funiq * => //. -case: f => [|s0 f] in k fsize funiq * => //. - case /boolP: (k 0 == 0). - move=> /eqP k0; left => i. - by move: k0; congr (k _ = 0); apply/val_inj; case i; case. - move=> /negPf k0; right; exists 1; rewrite big_ord1 /= rmorph1; split. - by apply/mem1v. - by apply/negP; rewrite mulr1 k0. -move: funiq; rewrite /= negb_or. -move=> /andP [/andP[ss0 sf]] /[dup] s0f /andP[_ funiq]. -case: (gal_ne s s0) => [/eqP ss0E | [x [xE /negPf ss0x]]]. - by move: ss0; rewrite ss0E. -move: fsize => /eqP; rewrite eqSS => /eqP fsize. -case: (IHn [:: s0 & f] - (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) i x - s x))) - fsize s0f). - move=> /(_ ord0)/=/eqP. - rewrite mulf_eq0 subr_eq0 [s0 x == _]eq_sym ss0x orbF => k10. - set k' := fun i : 'I_(size f).+1 => k - (match splitP (i : 'I_(1 + size f)%N) with - | SplitLo _ _ => ord0 - | SplitHi _ _ => lift ord0 i - end). - move: (IHn [:: s & f] k' fsize). - have /[swap]/[apply]: uniq (s :: f) by apply/andP; split. - case => [k0 | [a [aE fne0]]]; [left => i | right; exists a]. - case: i; case. - move: (k0 ord0); rewrite /k'. - by case: splitP => // + _ + ilt => _; congr (k _ = 0); apply/val_inj. - case => [|i] ilt. - by move: k10 => /eqP; congr (k _ = 0); apply/val_inj. - have ile: (i.+1 < (size f).+1)%N by rewrite -ltnS. - move: (k0 (Ordinal ile)); rewrite /k'. - case: splitP => [[j]/=/[swap]<-// | /= _ _]. - by congr (k _ = 0); apply/val_inj. - split => //. - move: k10 fne0 => /eqP k10. - rewrite 3!big_ord_recl/= k10 mul0r add0r. - congr (_ * _ + _ != 0). - by rewrite /k'; case: splitP => // [[i]] /=/(congr1 val). - apply/eq_bigr => i _. - rewrite tnth_cons (@tnth_cons _ s (s0 :: f) (lift ord0 i)) tnth_cons. - congr (_ * _). - by rewrite /k'; case: splitP => // [[j]]/=/[swap]<-. -move=> [y [yE fne0]]; right. -case /boolP: - (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) - => [| yne0]; last by exists y. -rewrite big_ord_recl/= addrC addr_eq0 {2}/tnth/= => /eqP. -under eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)); move=> y0. -exists (x*y); split; first by apply/rpredM. -move: fne0; congr (_ != 0). -under [\sum_(_ < (size f).+1) _]eq_bigr do rewrite mulrBr mulrBl - [X in _ - X * _]mulrC -mulrA -rmorphM/= -[X in _ - X]mulrA. -rewrite sumrB -mulr_sumr y0 mulrN mulrA opprK [s x * _]mulrC -mulrA -rmorphM/=. -rewrite addrC [in RHS]big_ord_recl {2}/tnth/=. -by under [in RHS]eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)). -Qed. - -Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) - [I : finType] (F : I -> R) : - \big[op/idx]_(i in [set: I]) F i = \big[op/idx]_i F i. -Proof. by apply/congr_big => // i; rewrite in_setT. Qed. - -Lemma galTrace_ne_0 (F : fieldType) (L : splittingFieldType F) - (K E : {subfield L}) : exists a, a \in E /\ galTrace K E a != 0. -Proof. -set l := enum [set: gal_of E]. -case: (gal_free - (fun i : 'I_(size l) => - (1 *+ ((tnth (in_tuple l) i) \in (galoisG E K) : nat))%:A) - (enum_uniq _)). - have /[dup] l1: 1%g \in l by rewrite mem_enum. - rewrite -index_mem => lt1 /(_ (Ordinal lt1))/=/eqP. - by rewrite /tnth (nth_index _ l1) group1/= scaler_eq0 2!oner_eq0. -move=> [x [xE s0]]; exists x; split => //. -move: s0; congr (_ != 0); rewrite /galTrace. -rewrite -(big_tuple _ _ _ xpredT (fun f => (f \in galoisG E K)%:R%:A * f x))/=. -rewrite /l [in RHS]big_mkcond/= big_enum /= big_setT; apply/eq_bigr => i _. -case: (i \in galoisG E K) => /=; first by rewrite mulr1n scale1r mul1r. -by rewrite mulr0n scale0r mul0r. -Qed. - -Lemma ffun_sum [T : finType] [R : ringType] [E : vectType R] - (f : seq (ffun_vectType T E)) (x : T) : - (\sum_(i <- f) i) x = \sum_(i <- f) i x. -Proof. -elim: f; first by rewrite 2!big_nil ffunE. -move=> a f IHf. -by rewrite 2!big_cons ffunE IHf. -Qed. Definition Zp_succ n (i : 'I_n) := @@ -202,216 +28,8 @@ Definition Zp_succ n (i : 'I_n) := end klt) end. -(* TODO: généraliser sur toutes les définitions par imset. *) -(* Ah non, je change le domaine d'indexation, ce lemme est spécifique aux - * éléments d'ordre fini d'un groupe. *) -Lemma cycle_imset [gT : finGroupType] (g : gT) : - <[g]>%g = ([set g ^+ (val i) | i : 'I_#[g]])%g. -Proof. -apply/eqP; rewrite eqEsubset; apply/andP; split; apply/subsetP => x. - move=> /cycleP [i ->]; apply/imsetP. - exists (Ordinal (ltn_pmod i (order_gt0 g))); rewrite ?in_setT//. - by rewrite expg_mod_order. -by move=> /imsetP [i] _ ->; apply/cycleP; exists i. -Qed. - -Lemma cycle_imset_inj [gT : finGroupType] (g : gT) : - injective (fun i : 'I_(#[g]) => (g ^+ i))%g. -Proof. -move=> [i ilt] [j jlt] /eqP; rewrite eq_expg_mod_order. -rewrite modn_small// modn_small// => /eqP ijE. -by apply/val_inj. -Qed. - -Lemma big_condT [R : Type] [idx : R] (op : Monoid.com_law idx) - [I : finType] (A : {pred I}) (F : I -> R) : - \big[op/idx]_(i in A | true) F i = \big[op/idx]_(i in A) F i. -Proof. -rewrite big_mkcondr. -by apply/congr_big => // i; rewrite andbT. Qed. - -Lemma Hilbert's_theorem_90_additive - [F : fieldType] [L : splittingFieldType F] - [K E : {subfield L}] [x : gal_of E] - [a : L] : - galois K E -> - generator 'Gal(E / K) x -> - a \in E -> - reflect (exists2 b : L, b \in E & a = b - x b) - (galTrace K E a == 0). -Proof. -move=> Egal /(_ =P <[x]>%g) DgalE Ea. -have galEx: x \in 'Gal(E / K)%g by rewrite DgalE cycle_id. -apply: (iffP eqP) => [normEa1 | [b Eb ->]]; last first. - by rewrite raddfB/= galTrace_gal// subrr. -move: (galTrace_ne_0 K E) => [b [bE tb]]. -remember (\dim_K E) as n. -have ordx: #[x]%g = n by rewrite orderE -DgalE -(galois_dim Egal). -move: (expg_order x); rewrite ordx => xord. -move: (Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). -rewrite mul0n adim_gt0 => dimgt0 /(_ 1%N); rewrite mul1n => dimgt1. -case: n => [|n] in Heqn ordx xord *; first by move: dimgt0; rewrite -Heqn. -case: n => [|n] in Heqn ordx xord *. - move: dimgt1; rewrite -Heqn ltnn => /esym/negbT; rewrite -leqNgt => dimEK. - move: (eqEdim K E); rewrite dimEK (galois_subW Egal) => /=/eqP KE. - move: normEa1; rewrite /galTrace. - have ->: \sum_(x0 in ('Gal(E / K))%g) x0 a = \sum_(x0 in ('Gal(E / K))%g) a. - apply/eq_bigr => f fgal. - move: Egal => /galois_fixedField Kfix. - by move: (Ea); rewrite -{1}KE -Kfix => /fixedFieldP => /(_ Ea f fgal). - rewrite sumr_const; rewrite -(galois_dim Egal) -Heqn mulr1n => a0. - by exists a => //; rewrite a0 rmorph0 subr0. -set c := (galTrace K E b)^-1 - * \sum_(i < n.+1) (\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. -have tbE: galTrace K E b \in E. - by rewrite /galTrace rpred_sum// => f _; apply/memv_gal. -exists c. - apply/rpredM; first by rewrite rpredV. - rewrite rpred_sum// => i _. - apply/rpredM; last by apply/memv_gal. - by rewrite rpred_sum// => j _; apply/memv_gal. -rewrite /c rmorphM/= rmorphV/= ?unitfE//. -move: (galTrace_fixedField K bE) => /fixedFieldP => /(_ tbE x galEx) ->. -rewrite -mulrBr rmorph_sum/=. -rewrite big_ord_recl big_ord1 expg0 gal_id expg1 big_ord_recr/=. -rewrite opprD addrAC [_ - x _]addrC addrA -addrA [- _ + _]addrC -sumrB. -have ->: \sum_(i < n) - ((\sum_(j < (bump 0 i).+1) (x ^+ j)%g a) * (x ^+ (bump 0 i).+1)%g b - - x ((\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b)) = - \sum_(i < n) a * (x ^+ i.+2)%g b. - apply/eq_bigr; case => i ilt _ /=. - rewrite /bump/= add1n rmorphM/= rmorph_sum/= expgSr galM// -mulrBl. - congr *%R. - rewrite big_ord_recl/= -addrA -sumrB expg0 gal_id -[in RHS](addr0 a). - congr (a + _). - transitivity (\sum_(j < i.+1) (0 : L)); last by rewrite sumr_const mul0rn. - by apply/eq_bigr => j _; rewrite /bump/= add1n expgSr galM// subrr. -rewrite -mulr_sumr rmorphM/= rmorph_sum/=. -have tE: forall d, d \in E -> galTrace K E d = \sum_(i < n.+2) (x ^+ i)%g d. - move=> d dE. - rewrite /galTrace DgalE cycle_imset => /=. - by rewrite (big_imset _ (in2W (@cycle_imset_inj _ x))) /= ordx. -move: normEa1; rewrite tE// big_ord_recl expg0 gal_id => /eqP. -under [in X in X -> _]eq_bigr do rewrite /= /bump/= add1n expgSr galM//. -rewrite addrC addr_eq0 => /eqP ->. -rewrite mulNr opprK -2!mulrDr mulrCA -(galM _ x bE). -rewrite -expgSr xord gal_id [x b + b]addrC. -have <-: galTrace K E b = b + x b + \sum_(i < n) (x ^+ i.+2)%g b. - rewrite (tE b bE) big_ord_recl/= expg0 gal_id big_ord_recl/= expg1 addrA. - by under eq_bigr do rewrite /bump/= 2!add1n. -by rewrite mulVf// mulr1. -Qed. - -Lemma natf_partn_ne0 (R : idomainType) n : - (n`_[char R]^')%:R != 0 :> R. -Proof. -have n_gt0 := (part_gt0 [char R]^' n). -apply/negP; rewrite /partn natr_prod prodf_seq_eq0 => /hasP [i] i0n. -rewrite unfold_in/= natrX expf_eq0 logn_gt0 mem_primes => /andP[/negP ichar]. -move=> /andP[/andP[iprim _] i0]; apply/ichar; rewrite unfold_in/=. -by apply/andP. -Qed. - -Lemma natf0_partn (R : idomainType) n : (0 < n)%N -> - (n%:R == 0 :> R) = (n`_[char R] != 1)%N. -Proof. -move=> n_gt0. -apply/idP/idP => [n0 |]. - apply/negP => /eqP nchar1. - move: n0; rewrite -(partnC [char R] n_gt0) nchar1 mul1n => n0. - by move: (natf_partn_ne0 R n); rewrite n0. -rewrite partn_eq1// /pnat n_gt0/= => /allPn [p]. -rewrite mem_primes => /andP [pprim /andP [_ pn]]. -rewrite /negn/mem/= 2!unfold_in negbK /= => pchar. -by rewrite -(dvdn_charf pchar). -Qed. - -Lemma primes_dvdn (m n : nat) : - (0 < n)%N -> (m %| n)%N -> primes m = [seq p <- primes n | p \in primes m]. -Proof. -move=> n0 mn. -apply/Order.POrderTheory.lt_sorted_eq. -- apply/sorted_primes. -- apply/sorted_filter. - apply/Order.POrderTheory.lt_trans. -apply/sorted_primes. -- move=> p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. -rewrite 2!mem_primes => /andP[->/=]/andP[m0 pm]. -by rewrite n0/=; apply/(dvdn_trans pm). -Qed. -Lemma dvdn_leq_logP (m n : nat) : - (0 < n)%N -> (0 < m)%N -> - reflect (forall p, prime p -> logn p m <= logn p n)%N (m %| n)%N. -Proof. -move=> n0 m0; apply/(iffP idP) => [mn p prim | vp_leq]. - by apply/dvdn_leq_log. -apply/dvdnP; exists (\prod_(p <- primes n) p ^ (logn p n - logn p m))%N. -rewrite {1}(prod_prime_decomp n0) {2}(prod_prime_decomp m0). -rewrite 2!prime_decompE 2!big_map/=. -have ->: primes m = [seq i <- primes n | i \in primes m]. - apply/Order.POrderTheory.lt_sorted_eq. - - apply/sorted_primes. - - apply/sorted_filter. - apply/Order.POrderTheory.lt_trans. - apply/sorted_primes. - - move=> p; rewrite mem_filter. - apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. - move=> /[dup]; rewrite {1}mem_primes => /andP[pprim _]. - rewrite -2!logn_gt0 => pm. - apply/(leq_trans pm (vp_leq p pprim)). -rewrite big_filter [in X in (_ * X)%N]big_mkcond/= -big_split/= 2!big_seq. -apply/eq_bigr => p; rewrite mem_primes => /andP[pprim _]. -have ->: ((if p \in primes m then p ^ logn p m else 1) = p ^ logn p m)%N. - case/boolP: (p \in primes m) => //. - by rewrite -logn_gt0 lt0n negbK => /eqP ->; rewrite expn0. -by rewrite -expnD subnK// vp_leq. -Qed. -Lemma logn_prod [I : eqType] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : - {in r, forall n, P n -> (0 < F n)%N} -> - (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. -Proof. -elim: r => [|n r IHn Fnr0]; first by rewrite 2!big_nil logn1. -have Fr0: {in r, forall n : I, P n -> (0 < F n)%N}. - by move=> i ir; apply/Fnr0; rewrite in_cons ir orbT. -rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply/IHn. -move: (Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. -rewrite lognM// ?IHn//. -rewrite big_seq_cond big_mkcond prodn_gt0// => i. -by case /boolP: ((i \in r) && P i) => // /andP[/Fr0]. -Qed. -Lemma logn_partn (p n : nat) (pi : nat_pred) : - logn p (n`_pi)%N = ((p \in pi) * logn p n)%N. -Proof. -rewrite /partn logn_prod; last by move=> i _; rewrite pfactor_gt0. -under eq_bigr do rewrite lognX. -have logp (i : nat): (i == p) || (logn i n * logn p i == 0)%N. - case /boolP: (i == p) => //= /negPf ip. - case /boolP: (prime i) => [|/negPf] iprim; last first. - by rewrite /logn iprim mul0n. - by rewrite (logn_prime _ iprim) [p == i]eq_sym ip muln0. -case /boolP: (p < n.+1)%N => [plt |]; last first. - rewrite -leqNgt => np. - suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i - = \sum_(0 <= i < n.+1 | i \in pi) 0)%N. - by rewrite big_const_seq iter_addn_0 mul0n ltn_log0// muln0. - apply/eq_bigr => i _. - move: (logp i) => /orP [|]/eqP ->//. - by rewrite ltn_log0// mul0n. -suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i - = \sum_(i < n.+1 | pred1 (Ordinal plt) i) (p \in pi) * logn i n)%N. - by rewrite (big_pred1 (Ordinal plt)). -rewrite big_mkord big_mkcond/= [in RHS]big_mkcond/=. -apply/eq_bigr => i _. -have ->: (i == Ordinal plt = (val i == p)). - by apply/eqP/eqP => [/(congr1 val)// | ] ip; apply/val_inj. -move: (logp i); case /boolP: (val i == p)%N => /= [|_] /eqP ->. - 2: by case: (val i \in pi). -move=> _; case: (p \in pi); rewrite ?mul0n// mul1n. -case /boolP: (prime p) => [| /negPf] pprim; last by rewrite /logn pprim. -by rewrite -{3}(expn1 p) pfactorK// muln1. -Qed. End Temp. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index 5c0857a..6470235 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -68,6 +68,11 @@ Lemma big_rcons (R : Type) (idx : R) (op : Monoid.law idx) (I : Type) op (\big[op/idx]_(j <- r | P j) F j) (if P i then F i else idx). Proof. by rewrite big_rcons_idx -big_change_idx Monoid.mulm1. Qed. +Lemma big_setT [R : Type] [idx : R] (op : Monoid.com_law idx) + [I : finType] (F : I -> R) : + \big[op/idx]_(i in [set: I]) F i = \big[op/idx]_i F i. +Proof. by apply/congr_big => // i; rewrite in_setT. Qed. + (********) (* path *) (********) @@ -87,6 +92,10 @@ Qed. Section tnth_shift. Context {T : Type} {n1 n2} (t1 : n1.-tuple T) (t2 : n2.-tuple T). +Lemma tnth_cons (x : T) (l : seq T) (i : 'I_(size l)) : + tnth (in_tuple (x :: l)) (lift ord0 i) = tnth (in_tuple l) i. +Proof. by rewrite /tnth/=; apply/set_nth_default. Qed. + Lemma tnth_lshift i : tnth [tuple of t1 ++ t2] (lshift n2 i) = tnth t1 i. Proof. have x0 := tnth_default t1 i; rewrite !(tnth_nth x0). @@ -100,6 +109,19 @@ by rewrite nth_cat size_tuple ltnNge leq_addr /= addKn. Qed. End tnth_shift. +(**********) +(* finfun *) +(**********) + +Lemma ffun_sum [T : finType] [R : ringType] [E : vectType R] + (f : seq (ffun_vectType T E)) (x : T) : + ((\sum_(i <- f) i) x = \sum_(i <- f) i x)%R. +Proof. +elim: f; first by rewrite 2!big_nil ffunE. +move=> a f IHf. +by rewrite 2!big_cons ffunE IHf. +Qed. + (*********) (* prime *) (*********) @@ -135,10 +157,120 @@ case: (logn 2 n) => [|[|k]]// ->. by rewrite totient_pfactor//= expnS mul1n leq_pmulr ?expn_gt0. Qed. +Lemma primes_dvdn (m n : nat) : + (0 < n)%N -> (m %| n)%N -> primes m = [seq p <- primes n | p \in primes m]. +Proof. +move=> n0 mn. +apply/Order.POrderTheory.lt_sorted_eq. +- apply/sorted_primes. +- apply/sorted_filter. + apply/Order.POrderTheory.lt_trans. +apply/sorted_primes. +- move=> p; rewrite mem_filter; apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. +rewrite 2!mem_primes => /andP[->/=]/andP[m0 pm]. +by rewrite n0/=; apply/(dvdn_trans pm). +Qed. + +Lemma dvdn_leq_logP (m n : nat) : + (0 < n)%N -> (0 < m)%N -> + reflect (forall p, prime p -> logn p m <= logn p n)%N (m %| n)%N. +Proof. +move=> n0 m0; apply/(iffP idP) => [mn p prim | vp_leq]. + by apply/dvdn_leq_log. +apply/dvdnP; exists (\prod_(p <- primes n) p ^ (logn p n - logn p m))%N. +rewrite {1}(prod_prime_decomp n0) {2}(prod_prime_decomp m0). +rewrite 2!prime_decompE 2!big_map/=. +have ->: primes m = [seq i <- primes n | i \in primes m]. + apply/Order.POrderTheory.lt_sorted_eq. + - apply/sorted_primes. + - apply/sorted_filter. + apply/Order.POrderTheory.lt_trans. + apply/sorted_primes. + - move=> p; rewrite mem_filter. + apply/idP/idP => [/[dup] + -> /= | /andP[->//]]. + move=> /[dup]; rewrite {1}mem_primes => /andP[pprim _]. + rewrite -2!logn_gt0 => pm. + apply/(leq_trans pm (vp_leq p pprim)). +rewrite big_filter [in X in (_ * X)%N]big_mkcond/= -big_split/= 2!big_seq. +apply/eq_bigr => p; rewrite mem_primes => /andP[pprim _]. +have ->: ((if p \in primes m then p ^ logn p m else 1) = p ^ logn p m)%N. + case/boolP: (p \in primes m) => //. + by rewrite -logn_gt0 lt0n negbK => /eqP ->; rewrite expn0. +by rewrite -expnD subnK// vp_leq. +Qed. + +Lemma logn_prod [I : eqType] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : + {in r, forall n, P n -> (0 < F n)%N} -> + (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. +Proof. +elim: r => [|n r IHn Fnr0]; first by rewrite 2!big_nil logn1. +have Fr0: {in r, forall n : I, P n -> (0 < F n)%N}. + by move=> i ir; apply/Fnr0; rewrite in_cons ir orbT. +rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply/IHn. +move: (Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. +rewrite lognM// ?IHn//. +rewrite big_seq_cond big_mkcond prodn_gt0// => i. +by case /boolP: ((i \in r) && P i) => // /andP[/Fr0]. +Qed. + +Lemma logn_partn (p n : nat) (pi : nat_pred) : + logn p (n`_pi)%N = ((p \in pi) * logn p n)%N. +Proof. +rewrite /partn logn_prod; last by move=> i _; rewrite pfactor_gt0. +under eq_bigr do rewrite lognX. +have logp (i : nat): (i == p) || (logn i n * logn p i == 0)%N. + case /boolP: (i == p) => //= /negPf ip. + case /boolP: (prime i) => [|/negPf] iprim; last first. + by rewrite /logn iprim mul0n. + by rewrite (logn_prime _ iprim) [p == i]eq_sym ip muln0. +case /boolP: (p < n.+1)%N => [plt |]; last first. + rewrite -leqNgt => np. + suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i + = \sum_(0 <= i < n.+1 | i \in pi) 0)%N. + by rewrite big_const_seq iter_addn_0 mul0n ltn_log0// muln0. + apply/eq_bigr => i _. + move: (logp i) => /orP [|]/eqP ->//. + by rewrite ltn_log0// mul0n. +suff ->: (\sum_(0 <= i < n.+1 | i \in pi) logn i n * logn p i + = \sum_(i < n.+1 | pred1 (Ordinal plt) i) (p \in pi) * logn i n)%N. + by rewrite (big_pred1 (Ordinal plt)). +rewrite big_mkord big_mkcond/= [in RHS]big_mkcond/=. +apply/eq_bigr => i _. +have ->: (i == Ordinal plt = (val i == p)). + by apply/eqP/eqP => [/(congr1 val)// | ] ip; apply/val_inj. +move: (logp i); case /boolP: (val i == p)%N => /= [|_] /eqP ->. + 2: by case: (val i \in pi). +move=> _; case: (p \in pi); rewrite ?mul0n// mul1n. +case /boolP: (prime p) => [| /negPf] pprim; last by rewrite /logn pprim. +by rewrite -{3}(expn1 p) pfactorK// muln1. +Qed. + (********************) (* package fingroup *) (********************) +(************) +(* fingroup *) +(************) + +Lemma cycle_imset [gT : finGroupType] (g : gT) : + <[g]>%g = ([set g ^+ (val i) | i : 'I_#[g]])%g. +Proof. +apply/eqP; rewrite eqEsubset; apply/andP; split; apply/subsetP => x. + move=> /cycleP [i ->]; apply/imsetP. + exists (Ordinal (ltn_pmod i (order_gt0 g))); rewrite ?in_setT//. + by rewrite expg_mod_order. +by move=> /imsetP [i] _ ->; apply/cycleP; exists i. +Qed. + +Lemma cycle_imset_inj [gT : finGroupType] (g : gT) : + injective (fun i : 'I_(#[g]) => (g ^+ i))%g. +Proof. +move=> [i ilt] [j jlt] /eqP; rewrite eq_expg_mod_order. +rewrite modn_small// modn_small// => /eqP ijE. +by apply/val_inj. +Qed. + (*************) (* gproduct? *) (*************) @@ -280,6 +412,37 @@ rewrite pfactor_dvdn// ltn_geF// -[k]muln1 logn_Gauss ?logn1//. by rewrite logn_gt0 mem_primes p_prime dvdpn n_gt0. Qed. +Lemma memv_mulr_2closed [K : fieldType] [aT : FalgType K] (U : {aspace aT}) : + GRing.mulr_2closed U. +Proof. +move: U => [U]/[dup]/andP[_ /subvP UU] Ualg. +by move=> u v uU vU; apply/UU/memv_mul. +Qed. + +Lemma natf_partn_ne0 (R : idomainType) n : + (n`_[char R]^')%:R != 0 :> R. +Proof. +have n_gt0 := (part_gt0 [char R]^' n). +apply/negP; rewrite /partn natr_prod prodf_seq_eq0 => /hasP [i] i0n. +rewrite unfold_in/= natrX expf_eq0 logn_gt0 mem_primes => /andP[/negP ichar]. +move=> /andP[/andP[iprim _] i0]; apply/ichar; rewrite unfold_in/=. +by apply/andP. +Qed. + +Lemma natf0_partn (R : idomainType) n : (0 < n)%N -> + (n%:R == 0 :> R) = (n`_[char R] != 1)%N. +Proof. +move=> n_gt0. +apply/idP/idP => [n0 |]. + apply/negP => /eqP nchar1. + move: n0; rewrite -(partnC [char R] n_gt0) nchar1 mul1n => n0. + by move: (natf_partn_ne0 R n); rewrite n0. +rewrite partn_eq1// /pnat n_gt0/= => /allPn [p]. +rewrite mem_primes => /andP [pprim /andP [_ pn]]. +rewrite /negn/mem/= 2!unfold_in negbK /= => pchar. +by rewrite -(dvdn_charf pchar). +Qed. + (**********) (* ssrnum *) (**********) @@ -352,6 +515,14 @@ Lemma poly_XnsubC_over {R : ringType} n c (S : {pred R}) (addS : subringPred S) (kS : keyed_pred addS): c \in kS -> 'X^n - c%:P \is a polyOver kS. Proof. by move=> cS; rewrite rpredB ?rpredX ?polyOverX ?polyOverC. Qed. +Lemma polyOver_mulr_2closed [R : ringType] [S : {pred R}] + [addS : addrPred S] (kS : keyed_pred addS) : + GRing.mulr_2closed kS -> GRing.mulr_2closed (polyOver kS). +Proof. +move=> SM u vz /polyOverP uS /polyOverP vS; apply/polyOverP => i. +by rewrite coefM rpred_sum // => j _; apply/SM. +Qed. + Lemma lead_coef_prod {R : idomainType} (ps : seq {poly R}) : lead_coef (\prod_(p <- ps) p) = \prod_(p <- ps) lead_coef p. Proof. by apply/big_morph/lead_coef1; apply: lead_coefM. Qed. @@ -655,6 +826,40 @@ Qed. (* fieldext *) (************) +Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] + (f g : 'AHom(K, rT)) (U : {subfield K}) (x : K) : + {in U, f =1 g} -> f x = g x -> {in <>%VS, f =1 g}. +Proof. +move=> fgU fgx y /Fadjoin_poly_eq <-. +move: (Fadjoin_poly U x y) (Fadjoin_polyOver U x y) => p /polyOverP pU. +rewrite -(coefK p) horner_poly 2!rmorph_sum/=; apply/eq_bigr => i _. +by rewrite 2!rmorphM /= fgU// 2!rmorphX/= fgx. +Qed. + +Lemma ahom_eq_adjoin_seq [F0 : fieldType] [K : fieldExtType F0] + [rT : FalgType F0] (f g : 'AHom(K, rT)) (U : {aspace K}) (xs : seq K) : + {in U, f =1 g} -> {in xs, forall x, f x = g x} -> {in <>%VS, f =1 g}. +Proof. +elim: xs U => [|x xs IHxs] U fgU fgxs. + by rewrite adjoin_nil subfield_closed. +rewrite adjoin_cons. +have ->: <>%VS = ASpace (agenv_is_aspace <>%VS) + by rewrite /= agenv_id. +move: fgxs (IHxs (ASpace (agenv_is_aspace <>))) => fgxs /=. +rewrite agenv_id; apply. + by apply/ahom_eq_adjoin/fgxs => //; apply/mem_head. +by move=> a axs; apply/fgxs; rewrite in_cons axs orbT. +Qed. + +Lemma agenv_span (K : fieldType) (L : fieldExtType K) (U : {subfield L}) + (X : seq L) : <>%VS = U -> <<1%VS & X>>%VS = U. +Proof. +move=> ->. +suff ->: (1+U)%VS = U by rewrite subfield_closed. +rewrite -{2}(subfield_closed U) (agenvEr U) subfield_closed. +by congr (1 + _)%VS; apply/esym/field_module_eq; rewrite sup_field_module. +Qed. + Lemma dim_aimg (F : fieldType) (L L' : fieldExtType F) (iota : 'AHom(L, L')) (E : {subfield L}) : \dim (iota @: E) = \dim E. Proof. @@ -985,6 +1190,184 @@ have := EF; rewrite rs'E -aimg_adjoin_seq => /eqP. by rewrite eq_limg_ker0 ?AHom_lker0// => /eqP. Qed. +(**********) +(* galois *) +(**********) + +Lemma gal_ne (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) + (f g : gal_of E) : f = g \/ exists x, x \in E /\ f x != g x. +Proof. +move: (vbasisP E) => /span_basis/agenv_span LE. +case /boolP: (all (fun x => f x == g x) (vbasis E)) + => [/allP fgE | /allPn[x] xE fgx]; [ left | right ]. + 2: by exists x; split => //; apply/vbasis_mem. +apply/eqP/gal_eqP. +rewrite -{1}LE; apply/ahom_eq_adjoin_seq => //; last by move=> x /fgE/eqP. +move: (gal1 f)(gal1 g). +rewrite gal_kHom ?sub1v// gal_kHom ?sub1v//. +move=> /andP [_ /subvP f1] /andP [_ /subvP g1]. +by move=> x /[dup] /f1/fixedSpaceP -> /g1/fixedSpaceP ->. +Qed. + +Lemma gal_free (F0 : fieldType) (L : splittingFieldType F0) + (E : {subfield L}) (f : seq (gal_of E)) (k : 'I_(size f) -> L) : + uniq f -> + (forall i, k i = 0) \/ + (exists a, a \in E /\ \sum_(i < size f) k i * tnth (in_tuple f) i a != 0). +Proof. +move: {1}(size f) (Logic.eq_refl (size f)) => n. +elim: n f k => [|n IHn] f k fsize funiq. + by left; case; move: k; rewrite -fsize. +case: f => [|s f] in k fsize funiq * => //. +case: f => [|s0 f] in k fsize funiq * => //. + case /boolP: (k 0 == 0). + move=> /eqP k0; left => i. + by move: k0; congr (k _ = 0); apply/val_inj; case i; case. + move=> /negPf k0; right; exists 1; rewrite big_ord1 /= rmorph1; split. + by apply/mem1v. + by apply/negP; rewrite mulr1 k0. +move: funiq; rewrite /= negb_or. +move=> /andP [/andP[ss0 sf]] /[dup] s0f /andP[_ funiq]. +case: (gal_ne s s0) => [/eqP ss0E | [x [xE /negPf ss0x]]]. + by move: ss0; rewrite ss0E. +move: fsize => /eqP; rewrite eqSS => /eqP fsize. +case: (IHn [:: s0 & f] + (fun i => (k (lift ord0 i) * (tnth (in_tuple [:: s0 & f]) i x - s x))) + fsize s0f). + move=> /(_ ord0)/=/eqP. + rewrite mulf_eq0 subr_eq0 [s0 x == _]eq_sym ss0x orbF => k10. + set k' := fun i : 'I_(size f).+1 => k + (match splitP (i : 'I_(1 + size f)%N) with + | SplitLo _ _ => ord0 + | SplitHi _ _ => lift ord0 i + end). + move: (IHn [:: s & f] k' fsize). + have /[swap]/[apply]: uniq (s :: f) by apply/andP; split. + case => [k0 | [a [aE fne0]]]; [left => i | right; exists a]. + case: i; case. + move: (k0 ord0); rewrite /k'. + by case: splitP => // + _ + ilt => _; congr (k _ = 0); apply/val_inj. + case => [|i] ilt. + by move: k10 => /eqP; congr (k _ = 0); apply/val_inj. + have ile: (i.+1 < (size f).+1)%N by rewrite -ltnS. + move: (k0 (Ordinal ile)); rewrite /k'. + case: splitP => [[j]/=/[swap]<-// | /= _ _]. + by congr (k _ = 0); apply/val_inj. + split => //. + move: k10 fne0 => /eqP k10. + rewrite 3!big_ord_recl/= k10 mul0r add0r. + congr (_ * _ + _ != 0). + by rewrite /k'; case: splitP => // [[i]] /=/(congr1 val). + apply/eq_bigr => i _. + rewrite tnth_cons (@tnth_cons _ s (s0 :: f) (lift ord0 i)) tnth_cons. + congr (_ * _). + by rewrite /k'; case: splitP => // [[j]]/=/[swap]<-. +move=> [y [yE fne0]]; right. +case /boolP: + (\sum_(i < (size f).+2) k i * tnth (in_tuple [:: s, s0 & f]) i y == 0) + => [| yne0]; last by exists y. +rewrite big_ord_recl/= addrC addr_eq0 {2}/tnth/= => /eqP. +under eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)); move=> y0. +exists (x*y); split; first by apply/rpredM. +move: fne0; congr (_ != 0). +under [\sum_(_ < (size f).+1) _]eq_bigr do rewrite mulrBr mulrBl + [X in _ - X * _]mulrC -mulrA -rmorphM/= -[X in _ - X]mulrA. +rewrite sumrB -mulr_sumr y0 mulrN mulrA opprK [s x * _]mulrC -mulrA -rmorphM/=. +rewrite addrC [in RHS]big_ord_recl {2}/tnth/=. +by under [in RHS]eq_bigr do rewrite (@tnth_cons _ s (s0 :: f)). +Qed. + +Lemma galTrace_ne_0 (F : fieldType) (L : splittingFieldType F) + (K E : {subfield L}) : exists a, a \in E /\ galTrace K E a != 0. +Proof. +set l := enum [set: gal_of E]. +case: (gal_free + (fun i : 'I_(size l) => + (1 *+ ((tnth (in_tuple l) i) \in (galoisG E K) : nat))%:A) + (enum_uniq _)). + have /[dup] l1: 1%g \in l by rewrite mem_enum. + rewrite -index_mem => lt1 /(_ (Ordinal lt1))/=/eqP. + by rewrite /tnth (nth_index _ l1) group1/= scaler_eq0 2!oner_eq0. +move=> [x [xE s0]]; exists x; split => //. +move: s0; congr (_ != 0); rewrite /galTrace. +rewrite -(big_tuple _ _ _ xpredT (fun f => (f \in galoisG E K)%:R%:A * f x))/=. +rewrite /l [in RHS]big_mkcond/= big_enum /= big_setT; apply/eq_bigr => i _. +case: (i \in galoisG E K) => /=; first by rewrite mulr1n scale1r mul1r. +by rewrite mulr0n scale0r mul0r. +Qed. + +Lemma Hilbert's_theorem_90_additive + [F : fieldType] [L : splittingFieldType F] + [K E : {subfield L}] [x : gal_of E] + [a : L] : + galois K E -> + generator 'Gal(E / K) x -> + a \in E -> + reflect (exists2 b : L, b \in E & a = b - x b) + (galTrace K E a == 0). +Proof. +move=> Egal /(_ =P <[x]>%g) DgalE Ea. +have galEx: x \in 'Gal(E / K)%g by rewrite DgalE cycle_id. +apply: (iffP eqP) => [normEa1 | [b Eb ->]]; last first. + by rewrite raddfB/= galTrace_gal// subrr. +move: (galTrace_ne_0 K E) => [b [bE tb]]. +remember (\dim_K E) as n. +have ordx: #[x]%g = n by rewrite orderE -DgalE -(galois_dim Egal). +move: (expg_order x); rewrite ordx => xord. +move: (Egal) => /galois_subW/field_dimS/ltn_divRL/[dup]/(_ 0%N). +rewrite mul0n adim_gt0 => dimgt0 /(_ 1%N); rewrite mul1n => dimgt1. +case: n => [|n] in Heqn ordx xord *; first by move: dimgt0; rewrite -Heqn. +case: n => [|n] in Heqn ordx xord *. + move: dimgt1; rewrite -Heqn ltnn => /esym/negbT; rewrite -leqNgt => dimEK. + move: (eqEdim K E); rewrite dimEK (galois_subW Egal) => /=/eqP KE. + move: normEa1; rewrite /galTrace. + have ->: \sum_(x0 in ('Gal(E / K))%g) x0 a = \sum_(x0 in ('Gal(E / K))%g) a. + apply/eq_bigr => f fgal. + move: Egal => /galois_fixedField Kfix. + by move: (Ea); rewrite -{1}KE -Kfix => /fixedFieldP => /(_ Ea f fgal). + rewrite sumr_const; rewrite -(galois_dim Egal) -Heqn mulr1n => a0. + by exists a => //; rewrite a0 rmorph0 subr0. +set c := (galTrace K E b)^-1 + * \sum_(i < n.+1) (\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b. +have tbE: galTrace K E b \in E. + by rewrite /galTrace rpred_sum// => f _; apply/memv_gal. +exists c. + apply/rpredM; first by rewrite rpredV. + rewrite rpred_sum// => i _. + apply/rpredM; last by apply/memv_gal. + by rewrite rpred_sum// => j _; apply/memv_gal. +rewrite /c rmorphM/= rmorphV/= ?unitfE//. +move: (galTrace_fixedField K bE) => /fixedFieldP => /(_ tbE x galEx) ->. +rewrite -mulrBr rmorph_sum/=. +rewrite big_ord_recl big_ord1 expg0 gal_id expg1 big_ord_recr/=. +rewrite opprD addrAC [_ - x _]addrC addrA -addrA [- _ + _]addrC -sumrB. +have ->: \sum_(i < n) + ((\sum_(j < (bump 0 i).+1) (x ^+ j)%g a) * (x ^+ (bump 0 i).+1)%g b - + x ((\sum_(j < i.+1) (x ^+ j)%g a) * (x ^+ i.+1)%g b)) = + \sum_(i < n) a * (x ^+ i.+2)%g b. + apply/eq_bigr; case => i ilt _ /=. + rewrite /bump/= add1n rmorphM/= rmorph_sum/= expgSr galM// -mulrBl. + congr *%R. + rewrite big_ord_recl/= -addrA -sumrB expg0 gal_id -[in RHS](addr0 a). + congr (a + _). + transitivity (\sum_(j < i.+1) (0 : L)); last by rewrite sumr_const mul0rn. + by apply/eq_bigr => j _; rewrite /bump/= add1n expgSr galM// subrr. +rewrite -mulr_sumr rmorphM/= rmorph_sum/=. +have tE: forall d, d \in E -> galTrace K E d = \sum_(i < n.+2) (x ^+ i)%g d. + move=> d dE. + rewrite /galTrace DgalE cycle_imset => /=. + by rewrite (big_imset _ (in2W (@cycle_imset_inj _ x))) /= ordx. +move: normEa1; rewrite tE// big_ord_recl expg0 gal_id => /eqP. +under [in X in X -> _]eq_bigr do rewrite /= /bump/= add1n expgSr galM//. +rewrite addrC addr_eq0 => /eqP ->. +rewrite mulNr opprK -2!mulrDr mulrCA -(galM _ x bE). +rewrite -expgSr xord gal_id [x b + b]addrC. +have <-: galTrace K E b = b + x b + \sum_(i < n) (x ^+ i.+2)%g b. + rewrite (tE b bE) big_ord_recl/= expg0 gal_id big_ord_recl/= expg1 addrA. + by under eq_bigr do rewrite /bump/= 2!add1n. +by rewrite mulVf// mulr1. +Qed. + (********************) (* package solvable *) (********************) From 7dff68d18f2c9d0d173df8189e43cdfc20155f65 Mon Sep 17 00:00:00 2001 From: qvermande Date: Tue, 25 Jul 2023 13:13:23 +0200 Subject: [PATCH 12/14] remove duplicate in map_gal; remove temp --- _CoqProject | 1 - theories/xmathcomp/map_gal.v | 2 -- theories/xmathcomp/temp.v | 38 ------------------------------------ theories/xmathcomp/various.v | 15 +++++--------- 4 files changed, 5 insertions(+), 51 deletions(-) delete mode 100644 theories/xmathcomp/temp.v diff --git a/_CoqProject b/_CoqProject index 57140ef..0289931 100644 --- a/_CoqProject +++ b/_CoqProject @@ -7,7 +7,6 @@ theories/xmathcomp/char0.v theories/xmathcomp/cyclotomic_ext.v theories/xmathcomp/real_closed_ext.v theories/xmathcomp/artin_scheier.v -theories/xmathcomp/temp.v -R theories Abel -arg -w -arg -projection-no-head-constant diff --git a/theories/xmathcomp/map_gal.v b/theories/xmathcomp/map_gal.v index d67ac6d..9febe38 100644 --- a/theories/xmathcomp/map_gal.v +++ b/theories/xmathcomp/map_gal.v @@ -19,8 +19,6 @@ Import AEnd_FinGroup. Variables (F0 : fieldType) (L : splittingFieldType F0). Implicit Types (K E F : {subfield L}). -Lemma galois_subW E F : galois E F -> (E <= F)%VS. Proof. by case/andP. Qed. - Lemma galois_normalW E F : galois E F -> (normalField E F)%VS. Proof. by case/and3P. Qed. diff --git a/theories/xmathcomp/temp.v b/theories/xmathcomp/temp.v deleted file mode 100644 index 341f5dd..0000000 --- a/theories/xmathcomp/temp.v +++ /dev/null @@ -1,38 +0,0 @@ -From mathcomp Require Import all_ssreflect. - -Set Implicit Arguments. -Unset Strict Implicit. -Unset Printing Implicit Defensive. - -Section Temp. - -(* This is actually quite useless, I am not convinced anymore that we should keep it. *) -Lemma big_condT [R : Type] [idx : R] (op : Monoid.com_law idx) - [I : finType] (A : {pred I}) (F : I -> R) : - \big[op/idx]_(i in A | true) F i = \big[op/idx]_(i in A) F i. -Proof. by rewrite big_mkcondr. Qed. - -(** Alternative: *) -(* Definition Zp_succ n : 'I_n -> 'I_n := if n is n.+1 then +%R ord_max else id. *) -(* The computational content would not be visible without the case distinction on n. Besides, this is not used anywhere anymore, so we can get rid of it. *) - -Definition Zp_succ n (i : 'I_n) := - match i with - | @Ordinal _ k klt => Ordinal ( - match n as n0 return (k < n0)%N -> (k.+1 %% n0 < n0)%N with - | 0 => id - | n0.+1 => fun=> ltn_pmod k.+1 (is_true_true : 0 < n0.+1)%N - end klt) - end. - -(* J'ai l'impression que je veux garder la quantification sur $r$ dans la première hypothèse. Je laisse ma version dans various.v le temps qu'on en discute. *) -Lemma logn_prod [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : - (forall n, P n -> (0 < F n)%N) -> - (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. -Proof. -move=> F_gt0; elim/(big_load (fun n => (n > 0)%N)): _. -elim/big_rec2: _; first by rewrite logn1. -by move=> i m n Pi [n_gt0 <-]; rewrite muln_gt0 lognM ?F_gt0. -Qed. - -End Temp. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index f899309..6a88026 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -175,18 +175,13 @@ apply/dvdn_partP => // p /[!(inE, mem_primes)]/and3P[p_prime _ pm]. by rewrite p_part pfactor_dvdn// vp_le. Qed. -Lemma logn_prod [I : eqType] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : - {in r, forall n, P n -> (0 < F n)%N} -> +Lemma logn_prod [I : Type] (r : seq I) (P : pred I) (F : I -> nat) (p : nat) : + (forall n, P n -> (0 < F n)%N) -> (logn p (\prod_(n <- r | P n) F n) = \sum_(n <- r | P n) logn p (F n))%N. Proof. -elim: r => [|n r IHn Fnr0]; first by rewrite 2!big_nil logn1. -have Fr0: {in r, forall n : I, P n -> (0 < F n)%N}. - by move=> i ir; apply/Fnr0; rewrite in_cons ir orbT. -rewrite 2!big_cons; case /boolP: (P n) => Pn; last by apply/IHn. -move: (Fnr0 n); rewrite mem_head Pn => /= /(_ is_true_true is_true_true) Fn0. -rewrite lognM// ?IHn//. -rewrite big_seq_cond big_mkcond prodn_gt0// => i. -by case /boolP: ((i \in r) && P i) => // /andP[/Fr0]. +move=> F_gt0; elim/(big_load (fun n => (n > 0)%N)): _. +elim/big_rec2: _; first by rewrite logn1. +by move=> i m n Pi [n_gt0 <-]; rewrite muln_gt0 lognM ?F_gt0. Qed. Lemma logn_partn (p n : nat) (pi : nat_pred) : From e632d24fdf326af63c5f05943262e6ebc6a39470 Mon Sep 17 00:00:00 2001 From: Cyril Cohen Date: Tue, 25 Jul 2023 19:08:52 +0200 Subject: [PATCH 13/14] refactoring --- theories/abel.v | 188 ++++++++++++++--------------------- theories/xmathcomp/various.v | 8 +- 2 files changed, 79 insertions(+), 117 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 5450c2c..58ac0dc 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -205,7 +205,7 @@ have [prime_n|primeN_n] := boolP (prime n). case/boolP: (2 <= n)%N; last first. case: n {lenk primeN_n} => [|[]]// in xnE n_gt0 * => _. by move: n_gt0; rewrite eqxx. - suff ->: <>%VS = E by apply: rext_refl. + suff -> : <>%VS = E by apply: rext_refl. by rewrite (Fadjoin_idP _). move: primeN_n => /primePn[|[d /andP[d_gt1 d_ltn] dvd_dn n_gt1]]. by case: ltngtP. @@ -291,6 +291,7 @@ Local Notation "r .-tower" := (tower r) (at level 2, format "r .-tower") : ring_scope. Local Notation "r .-ext" := (extension_of r) (at level 2, format "r .-ext") : ring_scope. +#[global] Hint Resolve rext_refl : core. (* Following the french wikipedia proof : https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_d%27Abel_(alg%C3%A8bre)#D%C3%A9monstration_du_th%C3%A9or%C3%A8me_de_Galois @@ -364,116 +365,83 @@ Section Part1. Variables (F0 : fieldType) (L : splittingFieldType F0). Implicit Types (E F K : {subfield L}) (w : L) (n : nat). +Lemma muln_div_trans d m n : (d %| m)%N -> (n %| d)%N -> + ((m %/ d) * (d %/ n))%N = (m %/ n)%N. +Proof. by move=> dm nd; rewrite muln_divA// divnK. Qed. + +Lemma muln_dimv E F K : + (K <= E)%VS -> (E <= F)%VS -> (\dim_K E * \dim_E F)%N = \dim_K F. +Proof. by move=> KE EF; rewrite mulnC muln_div_trans// ?field_dimS. Qed. + +Lemma galX E n (x : gal_of E) [a : L] : a \in E -> (x ^+ n)%g a = iter n x a. +Proof. +by elim: n => [|n IHn] aE; rewrite (expg0, expgSr)/= (gal_id, galM)/= ?IHn. +Qed. + Lemma cyclic_radical_ext w E F : ((\dim_E F)`_[char L]^').-primitive_root w -> w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F. Proof. -case /boolP: (E == F :> {vspace L}) => [/eqP -> _ _ _ _ | EneF]. - by apply: rext_refl. -remember (\dim_E F) as n. -move: w E F Heqn EneF. -refine (@ltn_ind - (fun n => forall (w : L) (E F : {subfield L}), - n = \dim_E F -> - ((E : {vspace L}) != F)%VS -> - (n`_[char L]^').-primitive_root w -> - w \in E -> - galois E F -> - cyclic 'Gal(F / E) -> - radical.-ext E F) - _ n). -move: n => _ n IHn w E F dimEF EneF wroot wE galEF /[dup] cycEF /cyclicP[g GE]. +have [->|NEF] := eqVneq (E : {vspace _}) F; first by []. +have [n] := ubnP (\dim_E F); elim: n => // n IHn in w E F NEF *. +rewrite ltnS leq_eqVlt => /predU1P[/[dup] dimEF ->|]; last exact: IHn. +move=> wroot wE galEF /[dup] cycEF /cyclicP[/= g GE]. have ggen : generator ('Gal(F / E))%g g by rewrite GE generator_cycle. have ggal : g \in ('Gal(F / E))%g by rewrite GE cycle_id. have EF := galois_subW galEF. -have n_gt0: (0 < n)%N by rewrite dimEF divn_gt0 ?adim_gt0//; apply/dimvS. -have [k [a [k0 [aE [aF /rext_r arad]]]]]: - exists (k : nat) (a : L), (0 < k)%N /\ a \notin E /\ a \in F /\ radical E a k. - case /boolP: (n%:R == (0 : L)) => [n0 | n_ne0]. - move: (natf0_char n_gt0 n0) => [p pchar]; exists p. - have /eqP: galTrace E F (-1) = 0. - rewrite /galTrace. - transitivity (\sum_(x in ('Gal(F / E))%g) (-1 : L)). - apply: eq_bigr => x xgal. - by rewrite (fixed_gal EF) ?rpredN1. - move: n0 => /eqP n0. - by rewrite sumr_const -(galois_dim galEF) -dimEF -mulr_natl n0 mul0r. - have FN1: -1 \in F by rewrite rpredN1. - move=> /(Hilbert's_theorem_90_additive galEF ggen FN1) [a] aF. - move=> /(congr1 (@GRing.opp L))/(congr1 (GRing.add a)). - rewrite opprK opprB addrCA subrr addr0 => /esym ga. - have apF: a ^+ p - a \in F by rewrite rpredB// rpredX. - have: a ^+ p - a \in fixedField ('Gal(F / E))%g. - apply/fixedFieldP => //. - move=> x; rewrite GE => /cycleP[+ ->]; elim => [|m IHm]. - by rewrite expg0 gal_id. - rewrite expgSr galM// IHm rmorphB/= rmorphX/= ga. - rewrite -(Frobenius_autE pchar (a+1)) rmorphD/= (Frobenius_autE pchar a). - by rewrite rmorph1 opprD addrACA subrr addr0. - move: (galEF) => /galois_fixedField -> apE. - case /boolP: (a \in E) => aE. - move: ga; rewrite (fixed_gal EF)//. - move=> /(congr1 (fun x => x-a))/esym/eqP. - by rewrite addrAC subrr add0r oner_eq0. - exists a; repeat split => //. - by move: pchar => /andP [/prime_gt0]. - by apply/orP; right; apply/andP. - move: (n_ne0) wroot => /negPf; rewrite natf0_partn//. - move=> /negbT; rewrite negbK. - move=> /eqP/(congr1 (fun x => (x * n`_[char L]^'))%N). - rewrite mul1n partnC => // <- wroot. - exists n. - have HT90g := Hilbert's_theorem_90 ggen (subvP EF _ wE). - have /eqP/HT90g[x [xF xN0]] : galNorm E F w = 1. - rewrite /galNorm; under eq_bigr => g' g'G; - first by rewrite (fixed_gal EF g'G)//; over. - by rewrite prodr_const -galois_dim// -dimEF (prim_expr_order wroot). - have gxN0 : g x != 0 by rewrite fmorph_eq0. - have wN0 : w != 0. rewrite (primitive_root_eq0 wroot) -lt0n //. - move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. - have gXx i : (g ^+ i)%g x = w ^- i * x. - elim: i => [|i IHi]. - by rewrite expg0 expr0 invr1 mul1r gal_id. - rewrite expgSr exprSr invfM galM// IHi rmorphM/= gx mulrA. - by rewrite (fixed_gal EF ggal) ?rpredV ?rpredX. - exists x; repeat split=> //. - - apply/negP=> xE. - move: gx; rewrite (fixed_gal EF)// => /(congr1 (fun y => w * y / x)). - rewrite mulrA -2!mulrA mulfV// 2!mulr1 mulfV// => w1; subst w. - move: wroot; rewrite prim_root1 => /eqP n1; subst n. - move: n1 => /eqP; rewrite -eqn_mul ?adim_gt0 ?(field_dimS EF)//. - rewrite mul1n => /eqP dimEFe. - by move: EneF => /negP; apply => /=; rewrite eqEdim EF dimEFe leqnn. - - apply/orP; left; apply/andP; split. - apply/negP => /eqP n0. - by move: n_ne0; rewrite -scaler_nat n0 scale0r eqxx. - move: galEF => /galois_fixedField <-; apply/fixedFieldP. - by apply: rpredX. - rewrite GE => + /cycleP [i ->] => _. - rewrite rmorphX/= gXx exprMn exprVn exprAC (prim_expr_order wroot)//. - by rewrite expr1n invr1 mul1r. -apply: (rext_trans arad). -have gala: galois <> F. - refine (galoisS _ galEF); apply/andP; split; first by apply: subv_adjoin. - by apply/FadjoinP; split=> //; apply/galois_subW. -have dimEaF: (\dim_(<>) F < n)%N. - rewrite dimEF ltn_divRL; last by apply/field_dimS/galois_subW. - rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. - rewrite ltn_divLR ?adim_gt0// mulnC ltn_mul2l adim_gt0/=. - rewrite ltnNge; apply/negP => dimE. - move: (eqEdim E <>); rewrite dimE subv_adjoin/= => /eqP EE. - by move: aE; rewrite EE memv_adjoin. -case /boolP: (<>%AS == F) => [FE | Fne]. - move: FE => /eqP ->; apply: rext_refl. -apply: (IHn _ dimEaF - (w ^+ (n`_[char L]^' %/ (\dim_(<>) F)`_[char L]^')%N)) => //. -- rewrite dvdn_prim_root// partn_dvd//. - rewrite dimEF dvdn_divRL; last by apply/field_dimS/galois_subW. - rewrite mulnC muln_divA; last by apply/field_dimS/galois_subW. - rewrite dvdn_divLR ?adim_gt0//. - by rewrite mulnC dvdn_mul//; apply/field_dimS/subv_adjoin. - by apply/dvdn_mull/field_dimS/FadjoinP; rewrite EF aF. -- by apply/rpredX/subvP_adjoin. -- exact (cyclicS (galS F (subv_adjoin E a)) cycEF). +have n_gt1 : (n > 1)%N. + rewrite -dimEF ltn_divRL ?mul1n// ?field_dimS//. + by rewrite eqEdim EF/= -ltnNge in NEF. +have n_gt0: (0 < n)%N by apply: leq_trans n_gt1. +suff [k [a [k0 aE aF /rext_r arad]]]: + exists (k : nat) (a : L), [/\ (0 < k)%N, a \notin E, a \in F & radical E a k]. + have gala: galois <> F. + refine (galoisS _ galEF); apply/andP; split; first by apply: subv_adjoin. + by apply/FadjoinP; split=> //; apply/galois_subW. + have dimEaF: (\dim_(<>) F < n)%N. + rewrite dim_Fadjoin mulnC divnMA dimEF ltn_Pdiv//. + by rewrite ltn_neqAle eq_sym adjoin_deg_eq1 aE//. + apply: rext_trans arad _; have [->//|Fne] := eqVneq <>%AS F. + apply: (IHn (w ^+ (n`_[char L]^' %/ (\dim_(<>) F)`_[char L]^')%N)) => //. + - rewrite dvdn_prim_root// partn_dvd//; apply/dvdnP; exists (\dim_E <>). + by rewrite muln_dimv// ?subv_adjoin// galois_subW. + - by apply/rpredX/subvP_adjoin. + - exact (cyclicS (galS F (subv_adjoin E a)) cycEF). +have [n0 | n_ne0] := boolP (n%:R == 0 :> L). + have [p pchar] := natf0_char n_gt0 n0; exists p. + have p_gt0 : (p > 0)%N by move: pchar => /andP [/prime_gt0]. + have [|a aF] := Hilbert's_theorem_90_additive galEF ggen (rpredN1 _) _. + rewrite /galTrace; under eq_bigr do rewrite (fixed_gal EF) ?rpredN1//. + by rewrite sumr_const -galois_dim// dimEF -mulr_natl (eqP n0) mul0r. + have [aE|aNE] := boolP (a \in E). + by rewrite (fixed_gal EF)// subrr => /eqP; rewrite oppr_eq0 oner_eq0. + move=> /(canLR (addrNK _))/(canRL (addNKr _)) ga. + suff apE : a ^+ p - a \in E. + by exists a; split => //; apply/orP; right; apply/andP. + rewrite -(galois_fixedField galEF). + have apF : a ^+ p - a \in F by rewrite rpredB// rpredX. + apply/fixedFieldP => // h /[!GE]/cycleP[+ ->]. + elim=> [|m IHm]; first by rewrite expg0 gal_id. + rewrite expgSr galM// IHm rmorphB/= rmorphX/= ga -Frobenius_autE. + by rewrite rmorphD/= rmorph1 !Frobenius_autE opprD addrACA subrr add0r. +exists n; rewrite part_pnat_id -?natf_neq0// in wroot. +have [|x [xF xN0]] := Hilbert's_theorem_90 ggen (subvP EF _ wE) _. + rewrite /galNorm; under eq_bigr do rewrite (fixed_gal EF)//. + by rewrite prodr_const -galois_dim// dimEF (prim_expr_order wroot). +have gxN0 : g x != 0 by rewrite fmorph_eq0. +have wN0 : w != 0 by rewrite (primitive_root_eq0 wroot) -lt0n // dimEF. +have [xE|xNE] := boolP (x \in E). + rewrite (fixed_gal EF)// divff// => w1. + by rewrite w1 prim_root1// gtn_eqF in wroot. +move=> /(canLR (mulfVK gxN0))/(canRL (mulKf wN0)) gx. +have nF0_ne0: n%:R != 0 :> F0. + by rewrite natf0_partn// -(eq_partn _ (@char_lalg _ L)) -natf0_partn. +suff: x ^+ n \in E by exists x; split => //; apply/orP; left; apply/andP. +rewrite -(galois_fixedField galEF). +have xnF : x ^+ n \in F by rewrite rpredX. +apply/fixedFieldP => //= h /[!GE]/cycleP[+ ->]. +elim=> [|m IHm]; first by rewrite expg0 gal_id. +rewrite expgSr galM// IHm rmorphX/= gx exprMn exprVn. +by rewrite (prim_expr_order wroot) invr1 mul1r. Qed. Lemma solvableWradical_ext w E F (n := \dim_E F) : @@ -704,7 +672,7 @@ rewrite (@pradical_solvable p _ _ w)// ?memv_adjoin//. by rewrite (isog_sol (normalField_isog _ _ _)) ?galois_normalW ?subv_adjoin. Qed. -Lemma ArtinSchreier_solvable_ext (p : nat) (F0 : fieldType) +Lemma ArtinSchreier_solvable_ext (p : nat) (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) (x : L) : p \in [char L] -> x ^+ p - x \in E -> x \notin E -> solvable_ext E <>. Proof. @@ -771,7 +739,7 @@ Definition solvable_ext_poly (F : fieldType) (p : {poly F}) := solvable 'Gal(<<1 & rs>> / 1). Definition separable_splittingField (F : fieldType) (p : {poly F}) := - forall (L : splittingFieldType F) (rs : seq L), + forall (L : splittingFieldType F) (rs : seq L), p ^^ in_alg L %= \prod_(x <- rs) ('X - x%:P) -> separable 1 <<1 & rs>>. Lemma galois_solvable (F0 : fieldType) (L : splittingFieldType F0) @@ -1787,10 +1755,8 @@ elim: f => //= [x|c|u f1 IHf1|b f1 IHf1 f2 IHf2] in k {r fr} als1 als1E *. by rewrite [RHS](fmorph_eq_rat [rmorphism of iota \o in_alg _]). - case: als1 als1E => [|y []]//= []/=; rewrite adjoin_seq1. case: c => [/eqP|/eqP|n yomega]. - + rewrite fmorph_eq0 => /eqP->; rewrite (Fadjoin_idP _) ?rpred0//. - exact: rext_refl. - + rewrite fmorph_eq1 => /eqP->; rewrite (Fadjoin_idP _) ?rpred1//. - exact: rext_refl. + + by rewrite fmorph_eq0 => /eqP->; rewrite (Fadjoin_idP _) ?rpred0. + + by rewrite fmorph_eq1 => /eqP->; rewrite (Fadjoin_idP _) ?rpred1. + apply/(@rext_r _ _ _ n.+1)/radicalP; left; split. by apply/negP; rewrite pnatr_eq0. rewrite prim_expr_order ?rpred1//. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index 6a88026..48d0fdc 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -114,13 +114,9 @@ End tnth_shift. (**********) Lemma ffun_sum [T : finType] [R : ringType] [E : vectType R] - (f : seq (ffun_vectType T E)) (x : T) : + (f : seq {ffun T -> E}) (x : T) : ((\sum_(i <- f) i) x = \sum_(i <- f) i x)%R. -Proof. -elim: f; first by rewrite 2!big_nil ffunE. -move=> a f IHf. -by rewrite 2!big_cons ffunE IHf. -Qed. +Proof. by elim/big_rec2: _ => [|? ? ? ? <-]; rewrite ffunE. Qed. (*********) (* prime *) From 51af6b809b43843d3bb14ac1bf8aabcedd91d3d3 Mon Sep 17 00:00:00 2001 From: qvermande Date: Tue, 25 Jul 2023 23:28:52 +0200 Subject: [PATCH 14/14] shortens a few lines and puts lemmas away --- theories/abel.v | 20 +++----------------- theories/xmathcomp/various.v | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/theories/abel.v b/theories/abel.v index 58ac0dc..4180d11 100644 --- a/theories/abel.v +++ b/theories/abel.v @@ -2,7 +2,6 @@ From mathcomp Require Import all_ssreflect all_fingroup all_algebra. From mathcomp Require Import all_solvable all_field polyrcf. From Abel Require Import various classic_ext map_gal algR. From Abel Require Import char0 cyclotomic_ext real_closed_ext artin_scheier. -From Abel Require Import temp. (*****************************************************************************) (* We work inside a enclosing splittingFieldType L over a base field F0 *) @@ -365,23 +364,10 @@ Section Part1. Variables (F0 : fieldType) (L : splittingFieldType F0). Implicit Types (E F K : {subfield L}) (w : L) (n : nat). -Lemma muln_div_trans d m n : (d %| m)%N -> (n %| d)%N -> - ((m %/ d) * (d %/ n))%N = (m %/ n)%N. -Proof. by move=> dm nd; rewrite muln_divA// divnK. Qed. - -Lemma muln_dimv E F K : - (K <= E)%VS -> (E <= F)%VS -> (\dim_K E * \dim_E F)%N = \dim_K F. -Proof. by move=> KE EF; rewrite mulnC muln_div_trans// ?field_dimS. Qed. - -Lemma galX E n (x : gal_of E) [a : L] : a \in E -> (x ^+ n)%g a = iter n x a. -Proof. -by elim: n => [|n IHn] aE; rewrite (expg0, expgSr)/= (gal_id, galM)/= ?IHn. -Qed. - Lemma cyclic_radical_ext w E F : ((\dim_E F)`_[char L]^').-primitive_root w -> w \in E -> galois E F -> cyclic 'Gal(F / E) -> radical.-ext E F. Proof. -have [->|NEF] := eqVneq (E : {vspace _}) F; first by []. +have [->//|NEF] := eqVneq (E : {vspace _}) F. have [n] := ubnP (\dim_E F); elim: n => // n IHn in w E F NEF *. rewrite ltnS leq_eqVlt => /predU1P[/[dup] dimEF ->|]; last exact: IHn. move=> wroot wE galEF /[dup] cycEF /cyclicP[/= g GE]. @@ -389,7 +375,7 @@ have ggen : generator ('Gal(F / E))%g g by rewrite GE generator_cycle. have ggal : g \in ('Gal(F / E))%g by rewrite GE cycle_id. have EF := galois_subW galEF. have n_gt1 : (n > 1)%N. - rewrite -dimEF ltn_divRL ?mul1n// ?field_dimS//. + rewrite -dimEF ltn_divRL ?field_dimS// mul1n. by rewrite eqEdim EF/= -ltnNge in NEF. have n_gt0: (0 < n)%N by apply: leq_trans n_gt1. suff [k [a [k0 aE aF /rext_r arad]]]: @@ -428,7 +414,7 @@ have [|x [xF xN0]] := Hilbert's_theorem_90 ggen (subvP EF _ wE) _. rewrite /galNorm; under eq_bigr do rewrite (fixed_gal EF)//. by rewrite prodr_const -galois_dim// dimEF (prim_expr_order wroot). have gxN0 : g x != 0 by rewrite fmorph_eq0. -have wN0 : w != 0 by rewrite (primitive_root_eq0 wroot) -lt0n // dimEF. +have wN0 : w != 0 by rewrite (primitive_root_eq0 wroot) -lt0n. have [xE|xNE] := boolP (x \in E). rewrite (fixed_gal EF)// divff// => w1. by rewrite w1 prim_root1// gtn_eqF in wroot. diff --git a/theories/xmathcomp/various.v b/theories/xmathcomp/various.v index 48d0fdc..888ce1c 100644 --- a/theories/xmathcomp/various.v +++ b/theories/xmathcomp/various.v @@ -85,6 +85,14 @@ apply: (iffP andP) => [[ryz rzs] [|i]// /IHs->//|rS]. by rewrite (rS 0); split=> //; apply/IHs => i /(rS i.+1). Qed. +(*******) +(* div *) +(*******) + +Lemma muln_div_trans (d m n : nat) : (d %| m)%N -> (n %| d)%N -> + ((m %/ d) * (d %/ n))%N = (m %/ n)%N. +Proof. by move=> dm nd; rewrite muln_divA// divnK. Qed. + (*********) (* tuple *) (*********) @@ -786,6 +794,10 @@ Qed. (* fieldext *) (************) +Lemma muln_dimv [F0 : fieldType] [L : fieldExtType F0] (E F K : {subfield L}) : + (K <= E)%VS -> (E <= F)%VS -> (\dim_K E * \dim_E F)%N = \dim_K F. +Proof. by move=> KE EF; rewrite mulnC muln_div_trans// ?field_dimS. Qed. + Lemma ahom_eq_adjoin [F0 : fieldType] [K : fieldExtType F0] [rT : FalgType F0] (f g : 'AHom(K, rT)) (U : {subfield K}) (x : K) : {in U, f =1 g} -> f x = g x -> {in <>%VS, f =1 g}. @@ -1154,6 +1166,12 @@ Qed. (* galois *) (**********) +Lemma galX (F0 : fieldType) (L : splittingFieldType F0) (E : {subfield L}) + n (x : gal_of E) [a : L] : a \in E -> (x ^+ n)%g a = iter n x a. +Proof. +by elim: n => [|n IHn] aE; rewrite (expg0, expgSr)/= (gal_id, galM)/= ?IHn. +Qed. + Lemma gal1 (F0 : fieldType) (L : splittingFieldType F0) (K : {subfield L}) (g : gal_of K) : g \in 'Gal(K / 1%VS)%g. Proof. by rewrite gal_kHom ?sub1v// k1HomE ahomWin. Qed.