# HG changeset patch # User haftmann # Date 1762110103 -3600 # Node ID 518a1464f1ac0a3353267707765026d6671feb25 # Parent 1cf4f1e930afef71ca0b61353a82754c489abd1f more efficient naive prime test diff -r 1cf4f1e930af -r 518a1464f1ac src/HOL/Computational_Algebra/Computation_Checks.thy --- a/src/HOL/Computational_Algebra/Computation_Checks.thy Sun Nov 02 19:47:30 2025 +0100 +++ b/src/HOL/Computational_Algebra/Computation_Checks.thy Sun Nov 02 20:01:43 2025 +0100 @@ -13,11 +13,19 @@ \ text \ - @{lemma \prime (997 :: nat)\ by eval} + @{lemma \prime (97 :: nat)\ by simp} \ text \ - @{lemma \prime (997 :: int)\ by eval} + @{lemma \prime (97 :: int)\ by simp} +\ + +text \ + @{lemma \prime (9973 :: nat)\ by eval} +\ + +text \ + @{lemma \prime (9973 :: int)\ by eval} \ text \ diff -r 1cf4f1e930af -r 518a1464f1ac src/HOL/Computational_Algebra/Primes.thy --- a/src/HOL/Computational_Algebra/Primes.thy Sun Nov 02 19:47:30 2025 +0100 +++ b/src/HOL/Computational_Algebra/Primes.thy Sun Nov 02 20:01:43 2025 +0100 @@ -226,6 +226,21 @@ using prime_nat_naiveI [of n] by auto qed +lemma prime_nat_iff': + "prime (p :: nat) \ p > 1 \ (\n \ {2.. n dvd p)" +proof safe + assume "p > 1" and *: "\n\{2..n dvd p" + show "prime p" unfolding prime_nat_iff + proof (intro conjI allI impI) + fix m assume "m dvd p" + with \p > 1\ have "m \ 0" by (intro notI) auto + hence "m \ 1" by simp + moreover from \m dvd p\ and * have "m \ {2..m dvd p\ and \p > 1\ have "m \ 1 \ m = p" by (auto dest: dvd_imp_le) + ultimately show "m = 1 \ m = p" by simp + qed fact+ +qed (auto simp: prime_nat_iff) + lemma prime_int_iff: "prime (n::int) \ (1 < n \ (\m. m \ 0 \ m dvd n \ m = 1 \ m = n))" proof (intro iffI conjI allI impI; (elim conjE)?) @@ -256,6 +271,23 @@ unfolding prime_int_nat_transfer prime_nat_iff by auto qed +lemma prime_int_iff': + "prime (p :: int) \ p > 1 \ (\n \ {2.. n dvd p)" (is "?P \ ?Q") +proof (cases "p \ 0") + case True + have "?P \ prime (nat p)" + by simp + also have "\ \ p > 1 \ (\n\{2.. n dvd nat \p\)" + using True by (simp add: prime_nat_iff') + also have "{2.. ?Q" by simp +next + case False + then show ?thesis + by (auto simp add: prime_ge_0_int) +qed + lemma prime_nat_not_dvd: assumes "prime p" "p > n" "n \ (1::nat)" shows "\n dvd p" @@ -293,9 +325,119 @@ using assms irreducible_altdef[of m] by (auto simp: prime_elem_iff_irreducible irreducible_altdef) - + +subsection \Make prime naively executable\ + +lemma prime_int_numeral_eq [simp]: + "prime (numeral m :: int) \ prime (numeral m :: nat)" + by (simp add: prime_int_nat_transfer) + +class check_prime_by_range = normalization_semidom + discrete_linordered_semidom + + assumes prime_iff: \prime a \ 1 < a \ (\d\{2..a div 2}. \ d dvd a)\ +begin + +lemma two_is_prime [simp]: + \prime 2\ + by (simp add: prime_iff) + +end + +lemma divisor_less_eq_half_nat: + \m \ n div 2\ if \m dvd n\ \m < n\ for m n :: nat + using that by (auto simp add: less_eq_div_iff_mult_less_eq) + +instance nat :: check_prime_by_range + apply standard + apply (auto simp add: prime_nat_iff) + apply (rule ccontr) + apply (auto simp add: neq_iff) + apply (metis One_nat_def Suc_1 Suc_leI atLeastAtMost_iff divisor_less_eq_half_nat) + done + +lemma two_is_prime_nat [simp]: + \prime (2::nat)\ + by (fact two_is_prime) + +lemma divisor_less_eq_half_int: + \k \ l div 2\ if \k dvd l\ \k < l\ \l \ 0\ \k \ 0\ for k l :: int +proof - + define m n where \m = nat \k\\ \n = nat \l\\ + with \l \ 0\ \k \ 0\ have \k = int m\ \l = int n\ + by simp_all + with that show ?thesis + using divisor_less_eq_half_nat [of m n] by simp +qed + +instance int :: check_prime_by_range + apply standard + apply (auto simp add: prime_int_iff) + apply (smt (verit) int_div_less_self) + apply (rule ccontr) + apply (auto simp add: neq_iff zdvd_not_zless) + apply (metis div_by_0 dvd_div_eq_0_iff less_le_not_le one_dvd order_le_less + zdvd_not_zless) + apply (metis atLeastAtMost_iff divisor_less_eq_half_int dvd_div_eq_0_iff + int_one_le_iff_zero_less nle_le one_add_one pos_imp_zdiv_nonneg_iff zdiv_eq_0_iff + zless_imp_add1_zle) + done + +lemma prime_nat_numeral_eq [simp]: \ \TODO Sieve Of Erathosthenes might speed this up\ + "prime (numeral m :: nat) \ + (1::nat) < numeral m \ + (\n::nat \ set [2.. n dvd numeral m)" + using prime_iff [of \numeral m :: nat\] + by (simp only: set_upt atLeastLessThanSuc_atLeastAtMost) + +context check_prime_by_range +begin + +definition check_divisors :: \'a \ 'a \ 'a \ bool\ + where \check_divisors l u a \ (\d\{l..u}. \ d dvd a)\ + +lemma check_divisors_rec [code]: + \check_divisors l u a \ u < l \ (\ l dvd a \ check_divisors (l + 1) u a)\ + apply (auto simp add: check_divisors_def not_less) + apply (metis local.add_increasing2 local.atLeastAtMost_iff local.linear local.order_eq_iff + local.zero_le_one) + subgoal for d + apply (cases \l + 1 \ d\) + apply (auto simp add: not_le) + apply (metis local.dual_order.antisym local.less_eq_iff_succ_less) + done + done + +lemma prime_eq_check_divisors [code]: + \prime a \ a > 1 \ check_divisors 2 (a div 2) a\ + by (simp add: check_divisors_def prime_iff) + +end + + subsection \Largest exponent of a prime factor\ +lemma prime_factor_nat: + "n \ (1::nat) \ \p. prime p \ p dvd n" + using prime_divisor_exists[of n] + by (cases "n = 0") (auto intro: exI[of _ "2::nat"]) + +lemma prime_factor_int: + fixes k :: int + assumes "\k\ \ 1" + obtains p where "prime p" "p dvd k" +proof (cases "k = 0") + case True + then have "prime (2::int)" and "2 dvd k" + by simp_all + with that show thesis + by blast +next + case False + with assms prime_divisor_exists [of k] obtain p where "prime p" "p dvd k" + by auto + with that show thesis + by blast +qed + text\Possibly duplicates other material, but avoid the complexities of multisets.\ lemma prime_power_cancel_less: @@ -353,83 +495,6 @@ qed -subsubsection \Make prime naively executable\ - -lemma prime_nat_iff': - "prime (p :: nat) \ p > 1 \ (\n \ {2.. n dvd p)" -proof safe - assume "p > 1" and *: "\n\{2..n dvd p" - show "prime p" unfolding prime_nat_iff - proof (intro conjI allI impI) - fix m assume "m dvd p" - with \p > 1\ have "m \ 0" by (intro notI) auto - hence "m \ 1" by simp - moreover from \m dvd p\ and * have "m \ {2..m dvd p\ and \p > 1\ have "m \ 1 \ m = p" by (auto dest: dvd_imp_le) - ultimately show "m = 1 \ m = p" by simp - qed fact+ -qed (auto simp: prime_nat_iff) - -lemma prime_int_iff': - "prime (p :: int) \ p > 1 \ (\n \ {2.. n dvd p)" (is "?P \ ?Q") -proof (cases "p \ 0") - case True - have "?P \ prime (nat p)" - by simp - also have "\ \ p > 1 \ (\n\{2.. n dvd nat \p\)" - using True by (simp add: prime_nat_iff') - also have "{2.. ?Q" by simp -next - case False - then show ?thesis - by (auto simp add: prime_ge_0_int) -qed - -lemma prime_int_numeral_eq [simp]: - "prime (numeral m :: int) \ prime (numeral m :: nat)" - by (simp add: prime_int_nat_transfer) - -lemma two_is_prime_nat [simp]: "prime (2::nat)" - by (simp add: prime_nat_iff') - -lemma prime_nat_numeral_eq [simp]: - "prime (numeral m :: nat) \ - (1::nat) < numeral m \ - (\n::nat \ set [2.. n dvd numeral m)" - by (simp only: prime_nat_iff' set_upt) \ \TODO Sieve Of Erathosthenes might speed this up\ - - -text\A bit of regression testing:\ - -lemma "prime(97::nat)" by simp -lemma "prime(97::int)" by simp - -lemma prime_factor_nat: - "n \ (1::nat) \ \p. prime p \ p dvd n" - using prime_divisor_exists[of n] - by (cases "n = 0") (auto intro: exI[of _ "2::nat"]) - -lemma prime_factor_int: - fixes k :: int - assumes "\k\ \ 1" - obtains p where "prime p" "p dvd k" -proof (cases "k = 0") - case True - then have "prime (2::int)" and "2 dvd k" - by simp_all - with that show thesis - by blast -next - case False - with assms prime_divisor_exists [of k] obtain p where "prime p" "p dvd k" - by auto - with that show thesis - by blast -qed - - subsection \Infinitely many primes\ lemma next_prime_bound: "\p::nat. prime p \ n < p \ p \ fact n + 1" @@ -1060,44 +1125,4 @@ lemmas prime_divprod_pow_nat = prime_elem_divprod_pow[where ?'a = nat] lemmas prime_exp = prime_elem_power_iff[where ?'a = nat] -text \Code generation\ - -lemma divisor_less_eq_half_nat: - \m \ n div 2\ if \m dvd n\ \m < n\ for m n :: nat - using that by (auto simp add: less_eq_div_iff_mult_less_eq) - -lemma divisor_less_eq_half_int: - \k \ l div 2\ if \k dvd l\ \k < l\ \l \ 0\ \k \ 0\ for k l :: int -proof - - define m n where \m = nat \k\\ \n = nat \l\\ - with \l \ 0\ \k \ 0\ have \k = int m\ \l = int n\ - by simp_all - with that show ?thesis - using divisor_less_eq_half_nat [of m n] by simp -qed - -lemma - \prime n \ 1 < n \ (\n\{1<..n div 2}. \ n dvd p)\ - -thm prime_nat_iff prime_int_iff [no_vars] - -context -begin - -qualified definition prime_nat :: "nat \ bool" - where [simp, code_abbrev]: "prime_nat = prime" - -lemma prime_nat_naive [code]: - "prime_nat p \ p > 1 \ (\n \{1<.. n dvd p)" - by (auto simp add: prime_nat_iff') - -qualified definition prime_int :: "int \ bool" - where [simp, code_abbrev]: "prime_int = prime" - -lemma prime_int_naive [code]: - "prime_int p \ p > 1 \ (\n \{1<.. n dvd p)" - by (auto simp add: prime_int_iff') - end - -end