Theory Primitive_Roots
section ‹Primitive roots in an integral domain›
theory Primitive_Roots
imports
Complex_Main
"HOL-Number_Theory.Cong"
"HOL-Computational_Algebra.Computational_Algebra"
"HOL-Library.Real_Mod"
begin
text ‹
We define the notion of a primitive root in an integral domain: an $n$-th root of unity
that is not a $k$-th root of unity for any $k < n$ and therefore generates all $n$-th roots
of unity.
›
locale primroot =
fixes n :: nat and w :: "'a :: idom"
assumes pos_order: "n > 0"
assumes root_of_unity: "w ^ n = 1"
assumes primitive: "⋀k. 0 < k ⟹ k < n ⟹ w ^ k ≠ 1"
begin
lemma nonzero: "w ≠ 0"
using root_of_unity pos_order by (auto simp: power_0_left)
lemma power_eq_iff: "w ^ k = w ^ l ⟷ [k = l] (mod n)"
proof (induction k l rule: linorder_wlog)
case (le k l)
define m where "m = l - k"
have l: "l = k + m"
using le by (simp add: m_def)
define a where "a = m div n"
define b where "b = m mod n"
have m: "m = n * a + b"
by (simp add: a_def b_def)
have b: " b < n"
using pos_order by (simp add: b_def)
have "w ^ k = w ^ l ⟷ w ^ k = w ^ k * w ^ m"
by (simp add: l power_add)
also have "… ⟷ w ^ m = 1"
using nonzero by simp
also have "… ⟷ w ^ b = 1"
by (simp add: m power_add power_mult root_of_unity)
also have "… ⟷ b = 0"
using primitive[of b] b by (cases "b = 0") auto
also have "… ⟷ [k = l] (mod n)"
by (simp add: l cong_altdef_nat' b_def mod_eq_0_iff_dvd)
finally show ?case .
qed (simp add: cong_sym_eq eq_commute)
lemma inj_on_power: "inj_on (λk. w ^ k) {..<n}"
by (auto intro!: inj_onI simp: power_eq_iff cong_def)
end
locale primroot_field = primroot n w for n and w :: "'a :: field"
begin
lemma power_int_eq_iff: "w powi k = w powi l ⟷ [k = l] (mod (int n))"
proof -
define a where "a = min k l"
define k' where "k' = nat (k - a)"
define l' where "l' = nat (l - a)"
have k: "k = a + int k'" and l: "l = a + int l'"
by (simp_all add: k'_def l'_def a_def)
have "w powi k = w powi l ⟷ [k' = l'] (mod n)"
using nonzero by (simp add: k l power_int_add power_eq_iff)
also have "… ⟷ [k = l] (mod (int n))"
by (simp add: k l cong_add_lcancel cong_int_iff)
finally show ?thesis .
qed
end
interpretation primroot_1: primroot 1 1
by standard auto
interpretation primroot_neg1: primroot 2 "-1 :: 'a :: {idom, ring_char_0}"
by standard (auto simp: numeral_2_eq_2 less_Suc_eq)
locale primroot_cis =
fixes n :: nat and k :: int
assumes coprime: "coprime k n"
assumes pos_order': "n > 0"
begin
sublocale primroot n "cis (2 * pi * k / n)"
proof
show "n > 0"
using pos_order' by simp
next
show "cis (2 * pi * real_of_int k / real n) ^ n = 1"
using pos_order' by (simp add: Complex.DeMoivre)
next
fix j :: nat assume j: "j > 0" "j < n"
show "cis (2 * pi * real_of_int k / real n) ^ j ≠ 1"
proof
assume "cis (2 * pi * real_of_int k / real n) ^ j = 1"
then obtain l where "real j * (2 * pi * real_of_int k / real n) = real_of_int l * (2 * pi)"
unfolding Complex.DeMoivre cis_eq_1_iff by blast
hence "real_of_int (k * j) = real_of_int (l * n)"
unfolding of_int_mult using pos_order' by (simp add: field_simps)
hence eq: "k * j = l * n"
by linarith
have "n dvd k * j"
by (simp add: eq)
with coprime have "n dvd j"
by (simp add: coprime_commute coprime_dvd_mult_right_iff)
with j show False
by force
qed
qed
end
interpretation primroot_ii: primroot 4 𝗂
proof -
interpret primroot_cis 4 1
by standard auto
show "primroot 4 𝗂"
using primroot_axioms by simp
qed
lemma (in primroot) cyclotomic_poly_conv_prod_unity_root:
"Polynomial.monom 1 n - 1 = (∏k<n. [:-(w ^ k), 1:])" (is "?lhs = ?rhs")
proof (rule ccontr)
assume neq: "?lhs ≠ ?rhs"
have "?lhs = Polynomial.monom 1 n + (-1)"
by simp
also have "degree … = n"
by (subst degree_add_eq_left) (use pos_order in ‹auto simp: degree_monom_eq›)
finally have deg1: "degree ?lhs = n" .
have "poly.coeff (?lhs - ?rhs) n = 0"
proof -
have "poly.coeff ?rhs n = lead_coeff ?rhs"
by (simp add: degree_prod_sum_eq)
also have "… = 1"
by (subst lead_coeff_prod) auto
finally show ?thesis
using pos_order by simp
qed
moreover have "?lhs - ?rhs ≠ 0"
using neq by simp
ultimately have "degree (?lhs - ?rhs) ≠ n"
by (metis leading_coeff_0_iff)
moreover have "degree (?lhs - ?rhs) ≤ n"
by (rule degree_diff_le) (use deg1 in ‹auto simp: degree_prod_sum_eq›)
ultimately have "degree (?lhs - ?rhs) < n"
by linarith
have root1: "poly ?lhs (w ^ k) = 0" for k
proof -
have "poly ?lhs (w ^ k) = w ^ (n * k) - 1"
by (simp add: poly_monom mult_ac flip: power_mult)
also have "… = 0"
by (simp add: power_mult root_of_unity)
finally show ?thesis .
qed
have root2: "poly ?rhs (w ^ k) = 0" if "k < n" for k
using that by (auto simp: poly_prod)
have "inj_on (λk. w ^ k) {..<n}"
by (rule inj_on_power)
hence "card {..<n} = card ((λk. w ^ k) ` {..<n})"
by (subst card_image) auto
also have "card ((λk. w ^ k) ` {..<n}) ≤ card {z. poly (?lhs - ?rhs) z = 0}"
by (intro card_mono poly_roots_finite) (use neq root1 root2 in auto)
also have "card {z. poly (?lhs - ?rhs) z = 0} ≤ degree (?lhs - ?rhs)"
by (rule card_poly_roots_bound) (use neq in auto)
also have "… < n"
by fact
finally show False
by simp
qed
lemma (in primroot) cyclotomic_poly_conv_prod_unity_root':
"1 - Polynomial.monom 1 n = (∏k<n. [:1, -(w ^ k):])" (is "?lhs = ?rhs")
proof -
define A where "A = insert 0 ((λk. w ^ k) ` {..<n})"
have card_A: "card A = Suc n"
proof -
have "card A = Suc (card ((λk. w ^ k) ` {..<n}))"
unfolding A_def using nonzero by (subst card.insert) auto
also have "card ((λk. w ^ k) ` {..<n}) = n"
by (subst card_image) (use pos_order inj_on_power in auto)
finally show ?thesis .
qed
show ?thesis
proof (rule poly_eqI_degree)
have "degree (1 - Polynomial.monom 1 n :: 'a poly) ≤ n"
by (intro degree_diff_le) (auto simp: degree_monom_eq)
thus "degree (1 - Polynomial.monom 1 n :: 'a poly) < card A"
by (simp add: card_A)
next
have "degree (∏k<n. [:1, - (w ^ k):]) ≤ n"
by (rule order.trans[OF degree_prod_sum_le]) (auto simp: nonzero)
thus "degree (∏k<n. [:1, - (w ^ k):]) < card A"
by (simp add: card_A)
next
fix x assume x: "x ∈ A"
have "poly (1 - Polynomial.monom 1 n) (w ^ k) = 0" for k
proof -
have "poly (1 - Polynomial.monom 1 n) (w ^ k) = 1 - w ^ (n * k)"
by (simp add: poly_monom mult_ac flip: power_mult)
also have "… = 0"
by (simp add: power_mult root_of_unity)
finally show ?thesis .
qed
moreover have "poly (1 - Polynomial.monom 1 n :: 'a poly) 0 = 1"
using pos_order by (simp add: poly_monom power_0_left)
moreover have "poly (∏k<n. [:1, -(w ^ k):]) (w ^ k) = 0" if k: "k < n" for k
proof -
define k' where "k' = (if k = 0 then 0 else n - k)"
have "k' < n"
using pos_order k by (auto simp: k'_def)
have "w ^ k * w ^ k' = w ^ (k + k')"
by (simp add: power_add)
also have "… = w ^ 0"
by (subst power_eq_iff) (use k in ‹auto simp: k'_def cong_def›)
finally show ?thesis
using that ‹k' < n› by (auto simp: poly_prod)
qed
moreover have "poly (∏k<n. [:1, -(w ^ k):]) 0 = 1"
by (simp add: poly_prod)
ultimately show "poly (1 - Polynomial.monom 1 n) x = poly (∏k<n. [:1, -(w ^ k):]) x"
using x by (auto simp: A_def)
qed
qed
end