Theory Rabin_Irreducibility_Test
section ‹Rabin's test for irreducible polynomials›
theory Rabin_Irreducibility_Test
imports Card_Irreducible_Polynomials_Aux
begin
text ‹This section introduces an effective test for irreducibility of polynomials
(in finite fields) based on Rabin~\cite{rabin1980}.›
definition pcoprime :: "_ ⇒ 'a list ⇒ 'a list ⇒ bool" ("pcoprimeı")
where "pcoprime⇘R⇙ p q =
(∀r ∈ carrier (poly_ring R). r pdivides⇘R⇙ p ∧ r pdivides⇘R⇙ q ⟶ degree r = 0)"
lemma pcoprimeI:
assumes "⋀r. r ∈ carrier (poly_ring R) ⟹ r pdivides ⇘R⇙ p ⟹ r pdivides⇘R⇙ q ⟹ degree r = 0"
shows "pcoprime⇘R⇙ p q"
using assms unfolding pcoprime_def by auto
context field
begin
interpretation r:polynomial_ring R "(carrier R)"
unfolding polynomial_ring_def polynomial_ring_axioms_def
using carrier_is_subfield field_axioms by force
lemma pcoprime_one: "pcoprime⇘R⇙ p 𝟭⇘poly_ring R⇙"
proof (rule pcoprimeI)
fix r
assume r_carr: "r ∈ carrier (poly_ring R)"
moreover assume "r pdivides ⇘R⇙ 𝟭⇘poly_ring R⇙"
moreover have "𝟭⇘poly_ring R⇙ ≠ []" by (simp add:univ_poly_one)
ultimately have "degree r ≤ degree 𝟭⇘poly_ring R⇙"
by (intro pdivides_imp_degree_le[OF carrier_is_subring] r_carr) auto
also have "... = 0" by (simp add:univ_poly_one)
finally show "degree r = 0" by auto
qed
lemma pcoprime_left_factor:
assumes "x ∈ carrier (poly_ring R)"
assumes "y ∈ carrier (poly_ring R)"
assumes "z ∈ carrier (poly_ring R)"
assumes "pcoprime⇘R⇙ (x ⊗⇘poly_ring R⇙ y) z"
shows "pcoprime⇘R⇙ x z"
proof (rule pcoprimeI)
fix r
assume r_carr: "r ∈ carrier (poly_ring R)"
assume "r pdivides ⇘R⇙ x"
hence "r pdivides ⇘R⇙ (x ⊗⇘poly_ring R⇙ y)"
using assms(1,2) r_carr r.p.divides_prod_r unfolding pdivides_def by simp
moreover assume "r pdivides ⇘R⇙ z"
ultimately show "degree r = 0" using assms(4) r_carr unfolding pcoprime_def by simp
qed
lemma pcoprime_sym:
shows "pcoprime x y = pcoprime y x"
unfolding pcoprime_def by auto
lemma pcoprime_left_assoc_cong_aux:
assumes "x1 ∈ carrier (poly_ring R)" "x2 ∈ carrier (poly_ring R)"
assumes "x2 ∼⇘poly_ring R⇙ x1"
assumes "y ∈ carrier (poly_ring R)"
assumes "pcoprime x1 y"
shows "pcoprime x2 y"
using assms r.p.divides_cong_r[OF _ assms(3)] unfolding pcoprime_def pdivides_def by simp
lemma pcoprime_left_assoc_cong:
assumes "x1 ∈ carrier (poly_ring R)" "x2 ∈ carrier (poly_ring R)"
assumes "x1 ∼⇘poly_ring R⇙ x2"
assumes "y ∈ carrier (poly_ring R)"
shows "pcoprime x1 y = pcoprime x2 y"
using assms pcoprime_left_assoc_cong_aux r.p.associated_sym by metis
lemma pcoprime_right_assoc_cong:
assumes "x1 ∈ carrier (poly_ring R)" "x2 ∈ carrier (poly_ring R)"
assumes "x1 ∼⇘poly_ring R⇙ x2"
assumes "y ∈ carrier (poly_ring R)"
shows "pcoprime y x1 = pcoprime y x2"
using assms pcoprime_sym pcoprime_left_assoc_cong by metis
lemma pcoprime_step:
assumes "f ∈ carrier (poly_ring R)"
assumes "g ∈ carrier (poly_ring R)"
shows "pcoprime f g ⟷ pcoprime g (f pmod g)"
proof -
have "d pdivides f ⟷ d pdivides (f pmod g)" if "d ∈ carrier (poly_ring R)" "d pdivides g" for d
proof -
have "d pdivides f ⟷ d pdivides (g ⊗⇘r.P⇙ (f pdiv g) ⊕⇘r.P⇙ (f pmod g))"
using pdiv_pmod[OF carrier_is_subfield assms] by simp
also have "... ⟷ d pdivides ((f pmod g))"
using that assms long_division_closed[OF carrier_is_subfield] r.p.divides_prod_r
unfolding pdivides_def by (intro r.p.div_sum_iff) simp_all
finally show ?thesis by simp
qed
hence "d pdivides f ∧ d pdivides g ⟷ d pdivides g ∧ d pdivides (f pmod g)"
if "d ∈ carrier (poly_ring R)" for d
using that by auto
thus ?thesis
unfolding pcoprime_def by auto
qed
lemma pcoprime_zero_iff:
assumes "f ∈ carrier (poly_ring R)"
shows "pcoprime f [] ⟷ length f = 1"
proof -
consider (i) "length f = 0" | (ii) "length f = 1" | (iii) "length f > 1"
by linarith
thus ?thesis
proof (cases)
case i
hence "f = []" by simp
moreover have "X pdivides []" using r.pdivides_zero r.var_closed(1) by blast
moreover have "degree X = 1" using degree_var by simp
ultimately have "¬pcoprime f []" using r.var_closed(1) unfolding pcoprime_def by auto
then show ?thesis using i by auto
next
case ii
hence "f ≠ []" "degree f = 0" by auto
hence "degree d = 0" if "d pdivides f" "d ∈ carrier (poly_ring R)" for d
using that(1) pdivides_imp_degree_le[OF carrier_is_subring that(2) assms] by simp
hence "pcoprime f []" unfolding pcoprime_def by auto
then show ?thesis using ii by simp
next
case iii
have "f pdivides f" using assms unfolding pdivides_def by simp
moreover have "f pdivides []" using assms r.pdivides_zero by blast
moreover have "degree f > 0" using iii by simp
ultimately have "¬pcoprime f []" using assms unfolding pcoprime_def by auto
then show ?thesis using iii by auto
qed
qed
end
context finite_field
begin
interpretation r:polynomial_ring R "(carrier R)"
unfolding polynomial_ring_def polynomial_ring_axioms_def
using carrier_is_subfield field_axioms by force
lemma exists_irreducible_proper_factor:
assumes "monic_poly R f" "degree f > 0" "¬monic_irreducible_poly R f"
shows "∃g. monic_irreducible_poly R g ∧ g pdivides⇘R⇙ f ∧ degree g < degree f"
proof -
define S where "S = {d. monic_irreducible_poly R d ∧ 0 < pmult d f}"
have f_carr: "f ∈ carrier (poly_ring R)" "f ≠ 𝟬⇘poly_ring R⇙"
using assms(1) unfolding monic_poly_def univ_poly_zero by auto
have "S ≠ {}"
proof (rule ccontr)
assume S_empty: "¬(S ≠ {})"
have "f = (⨂⇘poly_ring R⇙d∈S. d [^]⇘poly_ring R⇙ pmult d f)"
unfolding S_def by (intro factor_monic_poly assms(1))
also have "... = 𝟭⇘poly_ring R⇙" using S_empty by simp
finally have "f = 𝟭⇘poly_ring R⇙" by simp
hence "degree f = 0" using degree_one by simp
thus "False" using assms(2) by simp
qed
then obtain g where g_irred: "monic_irreducible_poly R g" and "0 < pmult g f"
unfolding S_def by auto
hence "1 ≤ pmult g f" by simp
hence g_div: "g pdivides f" using multiplicity_ge_1_iff_pdivides f_carr g_irred by blast
then obtain h where f_def: "f = g ⊗⇘poly_ring R⇙ h" and h_carr:"h ∈ carrier (poly_ring R)"
unfolding pdivides_def by auto
have g_nz: "g ≠ 𝟬⇘poly_ring R⇙" and h_nz: "h ≠ 𝟬⇘poly_ring R⇙"
and g_carr: "g ∈ carrier (poly_ring R)"
using f_carr(2) h_carr g_irred unfolding f_def monic_irreducible_poly_def monic_poly_def
by auto
have "degree f = degree g + degree h"
using g_nz h_nz g_carr h_carr unfolding f_def by (intro degree_mult[OF r.K_subring]) auto
moreover have "degree h > 0"
proof (rule ccontr)
assume "¬(degree h > 0)"
hence "degree h = 0" by simp
hence "h ∈ Units (poly_ring R)"
using h_carr h_nz by (simp add: carrier_is_subfield univ_poly_units' univ_poly_zero)
hence "f ∼⇘poly_ring R⇙ g"
unfolding f_def using g_carr r.p.associatedI2' by force
hence "f ∼⇘mult_of (poly_ring R)⇙ g"
using f_carr g_nz g_carr by (simp add: r.p.assoc_iff_assoc_mult)
hence "f = g"
using monic_poly_not_assoc assms(1) g_irred unfolding monic_irreducible_poly_def by simp
hence "monic_irreducible_poly R f"
using g_irred by simp
thus "False"
using assms(3) by auto
qed
ultimately have "degree g < degree f" by simp
thus ?thesis using g_irred g_div by auto
qed
theorem rabin_irreducibility_condition:
assumes "monic_poly R f" "degree f > 0"
defines "N ≡ {degree f div p | p . Factorial_Ring.prime p ∧ p dvd degree f}"
shows "monic_irreducible_poly R f ⟷
(f pdivides gauss_poly R (order R^degree f) ∧ (∀n ∈ N. pcoprime (gauss_poly R (order R^n)) f))"
(is "?L ⟷ ?R1 ∧ ?R2")
proof -
have f_carr: "f ∈ carrier (poly_ring R)"
using assms(1) unfolding monic_poly_def by blast
have "?R1" if "?L"
using div_gauss_poly_iff[where n="degree f"] that assms(2) by simp
moreover have "False" if cthat:"¬pcoprime (gauss_poly R (order R^n)) f" "?L" "n ∈ N" for n
proof -
obtain d where d_def:
"d pdivides f"
"d pdivides (gauss_poly R (order R^n))" "degree d > 0" "d ∈ carrier (poly_ring R)"
using cthat(1) unfolding pcoprime_def by auto
obtain p where p_def:
"n = degree f div p" "Factorial_Ring.prime p" "p dvd degree f"
using cthat(3) unfolding N_def by auto
have n_gt_0: "n > 0"
using p_def assms(2) by (metis dvd_div_eq_0_iff gr0I)
have "d ∉ Units (poly_ring R)"
using d_def(3,4) univ_poly_units'[OF carrier_is_subfield] by simp
hence "f pdivides d"
using cthat(2) d_def(1,4) unfolding monic_irreducible_poly_def ring_irreducible_def
Divisibility.irreducible_def properfactor_def pdivides_def f_carr by auto
hence "f pdivides (gauss_poly R (order R^n))"
using d_def(2,4) f_carr r.p.divides_trans unfolding pdivides_def by metis
hence "degree f dvd n"
using n_gt_0 div_gauss_poly_iff[OF _ cthat(2)] by auto
thus "False"
using p_def by (metis assms(2) div_less_dividend n_gt_0 nat_dvd_not_less prime_gt_1_nat)
qed
moreover have "False" if not_l:"¬?L" and r1:"?R1" and r2: "?R2"
proof -
obtain g where g_def: "g pdivides f" "degree g < degree f" "monic_irreducible_poly R g"
using r1 not_l exists_irreducible_proper_factor assms(1,2) by auto
have g_carr: "g ∈ carrier (poly_ring R)" and g_nz: "g ≠ 𝟬⇘poly_ring R⇙"
using g_def(3) unfolding monic_irreducible_poly_def monic_poly_def by (auto simp:univ_poly_zero)
have "g pdivides gauss_poly R (order R^degree f)"
using g_carr r1 g_def(1) unfolding pdivides_def using r.p.divides_trans by blast
hence "degree g dvd degree f"
using div_gauss_poly_iff[OF assms(2) g_def(3)] by auto
then obtain t where deg_f_def:"degree f = t * degree g"
by fastforce
hence "t > 1" using g_def(2) by simp
then obtain p where p_prime: "Factorial_Ring.prime p" "p dvd t"
by (metis order_less_irrefl prime_factor_nat)
hence p_div_deg_f: "p dvd degree f"
unfolding deg_f_def by simp
define n where "n = degree f div p"
have n_in_N: "n ∈ N"
unfolding N_def n_def using p_prime(1) p_div_deg_f by auto
have deg_g_dvd_n: "degree g dvd n"
using p_prime(2) unfolding n_def deg_f_def by auto
have n_gt_0: "n > 0"
using p_div_deg_f assms(2) p_prime(1) unfolding n_def
by (metis dvd_div_eq_0_iff gr0I)
have deg_g_gt_0: "degree g > 0"
using monic_poly_min_degree[OF g_def(3)] by simp
have 0:"g pdivides gauss_poly R (order R^n)"
using deg_g_dvd_n div_gauss_poly_iff[OF n_gt_0 g_def(3)] by simp
have "pcoprime (gauss_poly R (order R^n)) f"
using n_in_N r2 by simp
thus "False"
using 0 g_def(1) g_carr deg_g_gt_0 unfolding pcoprime_def by simp
qed
ultimately show ?thesis
by auto
qed
text ‹A more general variant of the previous theorem for non-monic polynomials. The result is
from Lemma~1 \cite{rabin1980}.›
theorem rabin_irreducibility_condition_2:
assumes "f ∈ carrier (poly_ring R)" "degree f > 0"
defines "N ≡ {degree f div p | p . Factorial_Ring.prime p ∧ p dvd degree f}"
shows "pirreducible (carrier R) f ⟷
(f pdivides gauss_poly R (order R^degree f) ∧ (∀n ∈ N. pcoprime (gauss_poly R (order R^n)) f))"
(is "?L ⟷ ?R1 ∧ ?R2")
proof -
define α where "α = [inv (hd f)]"
let ?g = "(λx. gauss_poly R (order R^x))"
let ?h = "α ⊗⇘poly_ring R⇙ f"
have f_nz: "f ≠ 𝟬⇘poly_ring R⇙" unfolding univ_poly_zero using assms(2) by auto
hence "hd f ∈ carrier R - {𝟬}" using assms(1) lead_coeff_carr by simp
hence "inv (hd f) ∈ carrier R - {𝟬}" using field_Units by auto
hence α_unit: "α ∈ Units (poly_ring R)"
unfolding α_def using univ_poly_carrier_units by simp
have α_nz: "α ≠ 𝟬⇘poly_ring R⇙" unfolding univ_poly_zero α_def by simp
have "hd ?h = hd α ⊗ hd f"
using α_nz f_nz assms(1) α_unit by (intro lead_coeff_mult) auto
also have "... = inv (hd f) ⊗ hd f" unfolding α_def by simp
also have "... = 𝟭" using lead_coeff_carr f_nz assms(1) by (simp add: field_Units)
finally have "hd ?h = 𝟭" by simp
moreover have "?h ≠ []"
using α_nz f_nz univ_poly_zero by (metis α_unit assms(1) r.p.Units_closed r.p.integral)
ultimately have h_monic: "monic_poly R ?h"
using r.p.Units_closed[OF α_unit] assms(1) unfolding monic_poly_def by auto
have "degree ?h = degree α + degree f"
using assms(1) f_nz α_unit α_nz by (intro degree_mult[OF carrier_is_subring]) auto
also have "... = degree f" unfolding α_def by simp
finally have deg_f: "degree f = degree ?h" by simp
have hf_cong:"?h ∼⇘r.P⇙ f"
using assms(1) α_unit by (simp add: r.p.Units_closed r.p.associatedI2 r.p.m_comm)
hence 0: "f pdivides ?g (degree f) ⟷ ?h pdivides ?g (degree f)"
unfolding pdivides_def using r.p.divides_cong_l r.p.associated_sym
using r.p.Units_closed[OF α_unit] assms(1) gauss_poly_carr by blast
have 1: "pcoprime (?g n) f ⟷ pcoprime (?g n) ?h" for n
using hf_cong r.p.associated_sym r.p.Units_closed[OF α_unit] assms(1)
by (intro pcoprime_right_assoc_cong gauss_poly_carr) auto
have "?L ⟷ pirreducible (carrier R) (α ⊗⇘poly_ring R⇙ f)"
using α_unit α_nz assms(1) f_nz r.p.integral unfolding ring_irreducible_def
by (intro arg_cong2[where f="(∧)"] r.p.irreducible_prod_unit assms) auto
also have "... ⟷ monic_irreducible_poly R (α ⊗⇘poly_ring R⇙ f)"
using h_monic unfolding monic_irreducible_poly_def by auto
also have "... ⟷ ?h pdivides ?g (degree f) ∧ (∀n ∈ N. pcoprime (?g n) ?h)"
using assms(2) unfolding N_def deg_f by (intro rabin_irreducibility_condition h_monic) auto
also have "... ⟷ f pdivides ?g (degree f) ∧ (∀n ∈ N. pcoprime (?g n) f)"
using 0 1 by simp
finally show ?thesis by simp
qed
end
end