Theory Chebyshev_Prime_Exhaust
section ‹Concrete bounds for Chebyshev's prime counting functions›
theory Chebyshev_Prime_Exhaust
imports
"HOL-Decision_Procs.Approximation"
"HOL-Library.Code_Target_Numeral"
"Prime_Number_Theorem.Prime_Counting_Functions"
begin
text ‹
The well-known Prime Number Theorem states that $\psi(x) \sim \theta(x) \sim (x)$, i.e.\
that both $\psi(x)$ and $\vartheta(x)$ are bounded by $(1 \pm \varepsilon) x$
for sufficiently large $x$ for any $\varepsilon > 0$. However, these are asymptotic bounds
without giving any concrete information on how $\psi$ and $\vartheta$ behave for small $x$,
or even how big $x$ must be until these bound shold.
To complement this, we shall prove some concrete, non-asymptotic bounds. Concretely:
▪ $\psi(x) \geq 0.9x$ if $x\geq 41$
▪ $\theta(x) \geq 0.82x$ if $x\geq 97$
▪ $\theta(x) \leq \psi(x) \leq 1.2x$ if $x\geq 0$
\noindent Our formalisation loosely follows a blog entry by A.W.\ Walker:
🌐‹https://awwalker.com/2017/02/05/notes-on-the-chebyshev-theorem/›
›
subsection ‹Brute-force checking of bounds for ‹ψ› and ‹θ››
subsubsection ‹Computing powers of a number›
function powers_below_aux :: "nat ⇒ nat ⇒ nat ⇒ nat list" where
"powers_below_aux ub n acc = (if acc = 0 ∨ n ≤ 1 ∨ acc > ub then [] else
acc # powers_below_aux ub n (acc * n))"
by auto
termination
by (relation "Wellfounded.measure (λ(ub, n, acc). 1 + ub - acc)")
(auto intro!: diff_less_mono2)
lemmas [simp del] = powers_below_aux.simps
lemma set_powers_below_aux:
assumes "acc > 0" "n > 1"
shows "set (powers_below_aux ub n acc) = range (λi. acc * n ^ i) ∩ {..ub}"
using assms
proof (induction ub n acc rule: powers_below_aux.induct)
case (1 ub n acc)
show ?case
proof (cases "acc > ub")
case True
have "range (λi. acc * n ^ i) ∩ {..ub} = {}"
proof (intro equalityI subsetI)
fix k assume "k ∈ range (λi. acc * n ^ i) ∩ {..ub}"
then obtain i where "acc * n ^ i ≤ ub"
by auto
also have "ub < acc * n ^ 0"
using True by simp
finally have "n ^ i < n ^ 0"
using ‹acc > 0› by (subst (asm) mult_less_cancel1) auto
hence "i < 0"
by (subst (asm) power_strict_increasing_iff) (use ‹n > 1› in auto)
thus "k ∈ {}"
by simp
qed auto
thus ?thesis
using True by (auto simp: powers_below_aux.simps)
next
case False
have "set (powers_below_aux ub n acc) = insert acc (set (powers_below_aux ub n (acc * n)))"
using False "1.prems" by (subst powers_below_aux.simps) auto
also have "set (powers_below_aux ub n (acc * n)) = range (λi. acc * n ^ Suc i) ∩ {..ub}"
by (subst "1.IH") (use "1.prems" False in ‹auto simp: mult_ac›)
also have "insert acc (range (λi. acc * n ^ Suc i) ∩ {..ub}) =
range (λi. acc * n ^ i) ∩ {..ub}" (is "insert acc ?lhs = ?rhs")
proof (intro equalityI subsetI)
fix x assume "x ∈ insert acc ?lhs"
thus "x ∈ ?rhs" using False
by (auto intro: rev_image_eqI[of 0] rev_image_eqI[of "Suc i" for i])
next
fix x assume "x ∈ ?rhs"
then obtain i where i: "x = acc * n ^ i" and le: "acc * n ^ i ≤ ub"
by auto
show "x ∈ insert acc ?lhs"
proof (cases "i = 0")
case False
hence "x ∈ ?lhs"
by (intro IntI rev_image_eqI[of "i-1"]) (use i le in auto)
thus ?thesis
by blast
qed (use i le in auto)
qed
finally show ?thesis .
qed
qed
definition powers_below :: "nat ⇒ nat ⇒ nat list" where
"powers_below ub n = powers_below_aux ub n n"
lemma set_powers_below:
assumes "n > 1"
shows "set (powers_below ub n) = (λi. n ^ i) ` {1..} ∩ {..ub}"
proof -
have "set (powers_below ub n) = range (λi. n * n ^ i) ∩ {..ub}"
unfolding powers_below_def
by (rule set_powers_below_aux) (use assms in auto)
also have "range (λi. n * n ^ i) = (λi. n ^ i) ` Suc ` UNIV"
by (simp add: image_image o_def)
also have "bij_betw Suc UNIV {1..}"
by (rule bij_betwI[of _ _ _ "λi. i - 1"]) auto
hence "Suc ` UNIV = {1..}"
by (simp add: bij_betw_def)
finally show ?thesis .
qed
lemma distinct_powers_below_aux:
assumes "n > 1" "acc > 0"
shows "distinct (powers_below_aux ub n acc)"
using assms
by (induction ub n acc rule: powers_below_aux.induct; subst powers_below_aux.simps)
(auto simp: set_powers_below_aux)
lemma distinct_powers_below: "n > 1 ⟹ distinct (powers_below ub n)"
unfolding powers_below_def by (rule distinct_powers_below_aux) auto
lemma hd_powers_below_aux:
assumes "acc ≤ ub" "n > 1" "acc > 0"
shows "hd (powers_below_aux ub n acc) = acc"
by (subst powers_below_aux.simps) (use assms in auto)
lemma hd_powers_below:
assumes "n ≤ ub" "n > 1"
shows "hd (powers_below ub n) = n"
unfolding powers_below_def by (subst hd_powers_below_aux) (use assms in auto)
subsubsection ‹Computing prime powers›
definition prime_powers_upto :: "nat ⇒ (nat × nat) list" where
"prime_powers_upto n =
sort_key fst (concat (map (λp. map (λk. (k, p)) (powers_below n p)) (primes_upto n)))"
lemma map_key_sort_key: "map f (sort_key f xs) = sort (map f xs)"
proof -
have [simp]: "map f (insort_key f x xs) = insort (f x) (map f xs)" for x xs
by (induction xs) auto
have [simp]: "map f (foldr (insort_key f) xs acc) =
foldr insort (map f xs) (map f acc)" for acc
by (induction xs arbitrary: acc) auto
show ?thesis
unfolding sort_key_def by simp
qed
lemma distinct_prime_powers_upto:
"distinct (map fst (prime_powers_upto n))"
proof -
have inj: "inj_on (powers_below n) {p. prime p ∧ p ≤ n}"
proof
fix p q assume pq: "p ∈ {p. prime p ∧ p ≤ n}" "q ∈ {p. prime p ∧ p ≤ n}"
assume eq: "powers_below n p = powers_below n q"
from eq have "hd (powers_below n p) = hd (powers_below n q)"
by simp
thus "p = q"
using pq by (simp add: hd_powers_below prime_gt_Suc_0_nat)
qed
have "distinct (concat (map (powers_below n) (primes_upto n)))"
proof (rule distinct_concat, goal_cases)
case 1
thus ?case
unfolding distinct_map using inj
by (simp add: set_primes_upto conj_commute)
next
case (2 ys)
thus ?case
by (auto simp: distinct_powers_below set_primes_upto prime_gt_Suc_0_nat)
next
case (3 ys zs)
thus ?case
by (auto simp: set_primes_upto set_powers_below prime_gt_Suc_0_nat prime_power_inj'')
qed
thus ?thesis
by (simp add: prime_powers_upto_def map_key_sort_key map_concat o_def)
qed
lemma sorted_prime_powers_upto:
"sorted (map fst (prime_powers_upto n))"
by (simp add: prime_powers_upto_def)
lemma set_prime_powers_upto:
"set (prime_powers_upto n) = {(q, aprimedivisor q) |q. primepow q ∧ q ≤ n}"
proof -
have "set (prime_powers_upto n) =
(⋃p∈{p. p ≤ n ∧ prime p}. (λx. (x, p)) ` ((λi. p ^ i) ` {1..} ∩ {..n}))"
by (simp add: prime_powers_upto_def set_primes_upto set_powers_below prime_gt_Suc_0_nat)
also have "… = {(q, aprimedivisor q) |q. primepow q ∧ q ≤ n}"
(is "?lhs = ?rhs")
proof (intro equalityI subsetI)
fix qp assume qp: "qp ∈ ?lhs"
then obtain q p where [simp]: "qp = (q, p)"
by (cases qp)
from qp obtain i where i: "prime p" "p ≤ n" "p ^ i ≤ n" "q = p ^ i" "i ≥ 1"
by auto
show "qp ∈ ?rhs"
using i by (auto simp: aprimedivisor_prime_power)
next
fix qp assume qp: "qp ∈ ?rhs"
then obtain q p where [simp]: "qp = (q, p)"
by (cases qp)
from qp have "primepow q"
by auto
then obtain p' i where i: "prime p'" "q = p' ^ i" "i > 0"
by (auto simp: primepow_def)
have [simp]: "p' = p"
using qp i by (auto simp: aprimedivisor_prime_power)
have "p ^ 1 ≤ p ^ i"
by (rule power_increasing) (use i prime_gt_0_nat[of p] in auto)
also have "… ≤ n"
using i qp by simp
finally have "p ≤ n"
by simp
with i qp show "qp ∈ ?lhs"
by auto
qed
finally show ?thesis .
qed
subsubsection ‹A generic checking function›
locale chebyshev_check =
fixes f :: "nat ⇒ real"
and F :: "nat ⇒ 'a ⇒ float"
and A :: "nat set"
and plus :: "nat ⇒ float ⇒ float ⇒ float"
and rel :: "real ⇒ real ⇒ bool"
and P :: "nat ⇒ real ⇒ bool"
and num :: "'a ⇒ nat"
assumes plus: "⋀prec. rel X x ⟹ rel Y y ⟹ rel (plus prec X Y) (x + y)"
assumes P_rel: "⋀x y k. P k x ⟹ rel x y ⟹ P k y"
assumes rel_0: "rel 0 0"
assumes A: "0 ∉ A"
begin
definition S where "S n = (∑k∈A∩{..n}. f k)"
definition S' where "S' n = (∑k∈A∩{..<n}. f k)"
context
fixes prec :: nat
begin
function check_aux :: "'a list ⇒ nat ⇒ nat ⇒ float ⇒ nat ⇒ bool" where
"check_aux ps lb ub acc n = (if n > ub then True else
(let (acc', ps') =
(if ps ≠ [] ∧ num (hd ps) = n then
(plus prec acc (F prec (hd ps)), tl ps)
else (acc, ps))
in (n < lb ∨ P n (real_of_float acc')) ∧ check_aux ps' lb ub acc' (n+1)))"
by auto
termination
by (relation "Wellfounded.measure (λ(_, _, ub, _, n). Suc ub - n)")
(auto split: if_splits)
definition check :: "'a list ⇒ nat ⇒ nat ⇒ bool" where
"check xs lb ub =
check_aux xs lb ub 0 (if xs = [] then lb else min lb (num (hd xs)))"
lemmas [simp del] = check_aux.simps
lemma check_aux_correct:
assumes "sorted (map num ps)" "distinct (map num ps)"
assumes "⋀p. p ≤ ub ⟹ p ∈ num ` set ps ⟷ p ∈ A ∧ p ≥ n"
assumes "⋀x. x ∈ set ps ⟹ rel (real_of_float (F prec x)) (f (num x))"
assumes "rel (real_of_float acc) (S' n)"
assumes "check_aux ps lb ub acc n"
assumes "k ∈ {max lb n..ub}"
shows "P k (S k)"
using assms
proof (induction ps lb ub acc n rule: check_aux.induct)
case (1 ps lb ub acc n)
hence "n ≤ ub"
by auto
define ps' where "ps' = (if ps = [] ∨ num (hd ps) ≠ n then ps else tl ps)"
define acc' where "acc' = (if ps = [] ∨ num (hd ps) ≠ n then acc else plus prec acc (F prec (hd ps)))"
have acc': "rel (real_of_float acc') (S n)"
proof (cases "n ∈ A")
case False
hence "acc' = acc" using "1.prems"(3)[of n] ‹n ≤ ub›
by (cases ps) (auto simp: acc'_def)
hence "rel (real_of_float acc') (S' n)"
using "1.prems"(5) by simp
also from False have "A ∩ {..<n} = A ∩ {..n}"
using nless_le by blast
hence "S' n = S n"
by (simp add: S_def S'_def)
finally show ?thesis .
next
case True
hence "n ∈ num ` set ps" "n > 0"
using "1.prems"(3)[of n] ‹n ≤ ub› A by (auto intro: Nat.gr0I)
have *: "num p ≥ n" if "p ∈ set ps" for p
using "1.prems"(3)[of "num p"] that ‹n ≤ ub›
by (cases "num p ≤ ub") auto
from ‹n ∈ num ` set ps› obtain x
where ps_eq: "ps = x # ps'" "num x = n"
using ‹sorted (map num ps)› ‹distinct (map num ps)› *
by (cases ps) (fastforce simp: ps'_def)+
have "acc' = plus prec acc (F prec x)"
using ps_eq by (auto simp: acc'_def)
also have "rel (real_of_float …) (S' n + f (num x))"
by (intro plus "1.prems" ‹n > 0›) (auto simp: ps_eq)
also have "… = sum f (insert n (A ∩ {..<n}))"
unfolding S'_def by (subst sum.insert) (auto simp: ps_eq)
also have "insert n (A ∩ {..<n}) = A ∩ {..n}"
using True by auto
also have "sum f … = S n"
by (simp add: S_def)
finally show ?thesis .
qed
show ?case
proof (cases "n = k")
case True
have "P k (real_of_float acc')"
using "1.prems"(6,7)
by (subst (asm) check_aux.simps) (use True in ‹auto simp: acc'_def›)
moreover have "rel (real_of_float acc') (S n)"
by fact
ultimately show ?thesis
using True P_rel by simp
next
case False
show ?thesis
proof (rule "1.IH"[of "(acc', ps')", OF _ _ refl])
show "sorted (map num ps')"
using ‹sorted (map num ps)›
by (auto simp: ps'_def sorted_tl map_tl)
show "distinct (map num ps')"
using ‹distinct (map num ps)›
by (auto simp: ps'_def distinct_tl map_tl)
show "(p ∈ num ` set ps') = (p ∈ A ∧ n + 1 ≤ p)" if p: "p ≤ ub" for p
proof (cases "n ∈ A")
case False
hence "n ∉ num ` set ps"
using "1.prems"(3)[of n] ‹n ≤ ub› by auto
hence [simp]: "ps' = ps"
by (auto simp: ps'_def)
show ?thesis using "1.prems"(3)[of p] p False
by (cases "n = p") auto
next
case True
hence "n ∈ num ` set ps"
using "1.prems"(3)[of n] ‹n ≤ ub› by auto
have *: "num p ≥ n" if "p ∈ set ps" for p
using "1.prems"(3)[of "num p"] that ‹n ≤ ub›
by (cases "num p ≤ ub") auto
from ‹n ∈ num ` set ps› obtain x
where ps_eq: "ps = x # ps'" "num x = n"
using ‹sorted (map num ps)› ‹distinct (map num ps)› *
by (cases ps) (fastforce simp: ps'_def)+
show ?thesis
by (cases "p = n")
(use "1.prems"(3)[of p] p ‹distinct (map num ps)› in ‹auto simp: ps_eq›)
qed
next
have "rel (real_of_float acc') (S n)"
by fact
also have "S n = S' (n + 1)"
unfolding S_def S'_def by (simp add: lessThan_Suc_atMost)
finally show "rel (real_of_float acc') (S' (n + 1))" .
next
show "check_aux ps' lb ub acc' (n + 1)"
using "1.prems"(6,7)
by (subst (asm) check_aux.simps) (auto simp: acc'_def ps'_def)
next
show "k ∈ {max lb (n+1)..ub}"
using "1.prems" False by auto
next
show "rel (real_of_float (F prec x)) (f (num x))"
if "x ∈ set ps'" for x
using "1.prems"(4)[of x] that
by (cases ps) (auto simp: ps'_def split: if_splits)
qed (use ‹n ≤ ub› in ‹auto simp: acc'_def ps'_def›)
qed
qed
lemma check_correct:
assumes "sorted (map num ps)" "distinct (map num ps)"
assumes "⋀p. p ≤ ub ⟹ p ∈ num ` set ps ⟷ p ∈ A"
assumes "⋀x. x ∈ set ps ⟹ rel (real_of_float (F prec x)) (f (num x))"
assumes "check ps lb ub"
assumes "k ∈ {lb..ub}"
shows "P k (S k)"
proof (rule check_aux_correct)
define n where "n = (if ps = [] then lb else min lb (num (hd ps)))"
have "n ≤ ub"
using assms by (auto simp: n_def)
show "sorted (map num ps)" "distinct (map num ps)"
by fact+
show "check_aux ps lb ub 0 n"
using assms unfolding check_def n_def by simp
show "k ∈ {max lb n..ub}"
using assms by (auto simp: n_def)
show "p ∈ num ` set ps ⟷ p ∈ A ∧ n ≤ p" if "p ≤ ub" for p
using assms(3)[of p] that ‹sorted (map num ps)›
by (cases ps) (auto simp: n_def)
have "A ∩ {..<n} = {}"
proof (intro equalityI subsetI)
fix p assume p: "p ∈ A ∩ {..<n}"
hence "p ∈ num ` set ps"
using assms(3)[of p] ‹n ≤ ub› by auto
hence False
using p ‹sorted (map num ps)› by (cases ps) (auto simp: n_def)
thus "p ∈ {}" ..
qed auto
thus "rel (real_of_float 0) (S' n)"
by (simp add: S'_def rel_0)
qed (use assms in auto)
end
end
subsubsection ‹The ‹θ› function›
context
begin
interpretation primes_theta: chebyshev_check
"λn. ln (real n)"
"λprec n. the (lb_ln prec (Float (int n) 0))"
"{p. prime p}"
"float_plus_down"
"(≤)"
"λk x. x ≥ c * (real k + 1)"
"λn. n"
for c :: real
proof
show "real_of_float (float_plus_down prec X Y) ≤ x + y"
if "real_of_float X ≤ x" "real_of_float Y ≤ y"
for x y :: real and X Y :: float and prec :: nat
using that by (simp add: float_plus_down_le)
qed auto
definition check_theta_lower_aux
where "check_theta_lower_aux = primes_theta.check_aux"
definition check_theta_lower where
"check_theta_lower c prec lb ub =
primes_theta.check c prec (primes_upto ub) lb ub"
lemma check_theta_lower_aux_code [code]:
"check_theta_lower_aux c prec ps lb ub acc n =
(if ub < n then True else let (acc', ps') =
if ps ≠ [] ∧ hd ps = n
then (float_plus_down prec acc (the (lb_ln prec (Float (int (hd ps)) 0))), tl ps)
else (acc, ps)
in (n < lb ∨ c * (real n + 1) ≤ real_of_float acc') ∧
check_theta_lower_aux c prec ps' lb
ub acc' (n + 1))"
unfolding check_theta_lower_aux_def
by (rule primes_theta.check_aux.simps)
lemma check_theta_lower_code [code]:
"check_theta_lower c prec lb ub = (let ps = primes_upto ub in
check_theta_lower_aux c prec ps lb ub 0
(if ps = [] then lb else min lb (hd ps)))"
unfolding check_theta_lower_def primes_theta.check_def check_theta_lower_aux_def
by (simp add: Let_def)
lemma check_theta_lower_correct:
assumes "check_theta_lower c prec lb ub"
shows "∀x∈{real lb..real ub}. primes_theta x ≥ c * x"
proof
fix x assume x: "x ∈ {real lb..real ub}"
define k where "k = nat ⌊x⌋"
show "c * x ≤ primes_theta x"
proof (cases "c ≥ 0")
case False
hence "c * x ≤ 0"
using x by (auto intro: mult_nonpos_nonneg)
also have "0 ≤ primes_theta x"
by (rule θ_nonneg)
finally show ?thesis .
next
case True
hence "c * x ≤ c * (real k + 1)"
using x by (intro mult_left_mono) (auto simp: k_def)
also have "c * (real k + 1) ≤ primes_theta.S k"
proof (rule primes_theta.check_correct)
show "sorted (map (λn. n) (primes_upto ub))"
"distinct (map (λn. n) (primes_upto ub))"
by (simp_all add: sorted_primes_upto distinct_primes_upto)
show "k ∈ {lb..ub}"
using x by (auto simp: k_def le_nat_iff le_floor_iff nat_le_iff floor_le_iff)
show "primes_theta.check c prec (primes_upto ub) lb ub"
using assms by (simp add: check_theta_lower_def)
next
fix p assume "p ≤ ub"
thus "p ∈ (λn. n) ` set (primes_upto ub) ⟷ p ∈ {p. prime p}"
by (auto simp: set_primes_upto)
next
fix n
assume n: "n ∈ set (primes_upto ub)"
hence "n > 0"
by (auto simp: set_primes_upto prime_gt_0_nat)
define x where "x = the (lb_ln prec (Float (int n) 0))"
have "lb_ln prec (Float (int n) 0) ≠ None"
using ‹n > 0› by (subst lb_ln.simps) auto
hence "lb_ln prec (Float (int n) 0) = Some x"
by (cases "lb_ln prec (Float (int n) 0)") (auto simp: x_def)
from lb_lnD[OF this] show "real_of_float x ≤ ln (real n)"
by simp
qed
also have "primes_theta.S k = primes_theta k"
unfolding primes_theta.S_def primes_theta_def prime_sum_upto_def
by (intro sum.cong) auto
also have "primes_theta k = primes_theta x"
unfolding k_def by simp
finally show "c * x ≤ primes_theta x" .
qed
qed
end
context
begin
interpretation primes_theta: chebyshev_check
"λn. ln (real n)"
"λprec n. the (ub_ln prec (Float (int n) 0))"
"{p. prime p}"
"float_plus_up"
"(≥)"
"λk x. x ≤ c * real k"
"λn. n"
for c :: real
proof
show "real_of_float (float_plus_up prec X Y) ≥ x + y"
if "real_of_float X ≥ x" "real_of_float Y ≥ y"
for x y :: real and X Y :: float and prec :: nat
using that by (simp add: float_plus_up_le)
qed auto
definition check_theta_upper_aux
where "check_theta_upper_aux = primes_theta.check_aux"
definition check_theta_upper where
"check_theta_upper c prec lb ub =
primes_theta.check c prec (primes_upto ub) lb ub"
lemma check_theta_upper_aux_code [code]:
"check_theta_upper_aux c prec ps lb ub acc n =
(if ub < n then True else let (acc', ps') =
if ps ≠ [] ∧ hd ps = n
then (float_plus_up prec acc (the (ub_ln prec (Float (int (hd ps)) 0))), tl ps)
else (acc, ps)
in (n < lb ∨ c * real n ≥ real_of_float acc') ∧
check_theta_upper_aux c prec ps' lb
ub acc' (n + 1))"
unfolding check_theta_upper_aux_def
by (rule primes_theta.check_aux.simps)
lemma check_theta_upper_code [code]:
"check_theta_upper c prec lb ub = (let ps = primes_upto ub in
check_theta_upper_aux c prec ps lb ub 0
(if ps = [] then lb else min lb (hd ps)))"
unfolding check_theta_upper_def primes_theta.check_def check_theta_upper_aux_def
by (simp add: Let_def)
lemma check_theta_upper_correct:
assumes "check_theta_upper c prec lb ub" "c ≥ 0"
shows "∀x∈{real lb..real ub}. primes_theta x ≤ c * x"
proof
fix x assume x: "x ∈ {real lb..real ub}"
define k where "k = nat ⌊x⌋"
have "primes_theta.S k ≤ c * real k"
proof (rule primes_theta.check_correct)
show "sorted (map (λn. n) (primes_upto ub))"
"distinct (map (λn. n) (primes_upto ub))"
by (simp_all add: sorted_primes_upto distinct_primes_upto)
show "k ∈ {lb..ub}"
using x by (auto simp: k_def le_nat_iff le_floor_iff nat_le_iff floor_le_iff)
show "primes_theta.check c prec (primes_upto ub) lb ub"
using assms by (simp add: check_theta_upper_def)
next
fix p assume "p ≤ ub"
thus "p ∈ (λn. n) ` set (primes_upto ub) ⟷ p ∈ {p. prime p}"
by (auto simp: set_primes_upto)
next
fix n
assume n: "n ∈ set (primes_upto ub)"
hence "n > 0"
by (auto simp: set_primes_upto prime_gt_0_nat)
define x where "x = the (ub_ln prec (Float (int n) 0))"
have "ub_ln prec (Float (int n) 0) ≠ None"
using ‹n > 0› by (subst ub_ln.simps) auto
hence "ub_ln prec (Float (int n) 0) = Some x"
by (cases "ub_ln prec (Float (int n) 0)") (auto simp: x_def)
from ub_lnD[OF this] show "real_of_float x ≥ ln (real n)"
by simp
qed
also have "primes_theta.S k = primes_theta k"
unfolding primes_theta.S_def primes_theta_def prime_sum_upto_def
by (intro sum.cong) auto
also have "primes_theta k = primes_theta x"
unfolding k_def by simp
also have "c * real k ≤ c * x"
using ‹c ≥ 0› x by (intro mult_left_mono) (auto simp: k_def)
finally show "primes_theta x ≤ c * x" .
qed
end
subsubsection ‹The ‹ψ› function›
context
begin
interpretation primes_psi: chebyshev_check
"λn. ln (real (aprimedivisor n))"
"λprec x. the (lb_ln prec (Float (int (snd x)) 0))"
"{p. primepow p}"
"float_plus_down"
"(≤)"
"λk x. x ≥ c * (real k + 1)"
"fst"
for c :: real
proof
show "real_of_float (float_plus_down prec X Y) ≤ x + y"
if "real_of_float X ≤ x" "real_of_float Y ≤ y"
for x y :: real and X Y :: float and prec :: nat
using that by (simp add: float_plus_down_le)
qed auto
definition check_psi_lower_aux
where "check_psi_lower_aux = primes_psi.check_aux"
definition check_psi_lower where
"check_psi_lower c prec lb ub =
primes_psi.check c prec (prime_powers_upto ub) lb ub"
lemma check_psi_lower_aux_code [code]:
"check_psi_lower_aux c prec ps lb ub acc n =
(if ub < n then True else let (acc', ps') =
if ps ≠ [] ∧ fst (hd ps) = n
then (float_plus_down prec acc (the (lb_ln prec (Float (int (snd (hd ps))) 0))), tl ps)
else (acc, ps)
in (n < lb ∨ c * (real n + 1) ≤ real_of_float acc') ∧
check_psi_lower_aux c prec ps' lb
ub acc' (n + 1))"
unfolding check_psi_lower_aux_def
by (rule primes_psi.check_aux.simps)
lemma check_psi_lower_code [code]:
"check_psi_lower c prec lb ub = (let ps = prime_powers_upto ub in
check_psi_lower_aux c prec ps lb ub 0
(if ps = [] then lb else min lb (fst (hd ps))))"
unfolding check_psi_lower_def primes_psi.check_def check_psi_lower_aux_def
by (simp add: Let_def)
lemma check_psi_lower_correct:
assumes "check_psi_lower c prec lb ub"
shows "∀x∈{real lb..real ub}. primes_psi x ≥ c * x"
proof
fix x assume x: "x ∈ {real lb..real ub}"
define k where "k = nat ⌊x⌋"
show "c * x ≤ primes_psi x"
proof (cases "c ≥ 0")
case False
hence "c * x ≤ 0"
using x by (auto intro: mult_nonpos_nonneg)
also have "0 ≤ primes_psi x"
by (rule ψ_nonneg)
finally show ?thesis .
next
case True
hence "c * x ≤ c * (real k + 1)"
using x by (intro mult_left_mono) (auto simp: k_def)
also have "c * (real k + 1) ≤ primes_psi.S k"
proof (rule primes_psi.check_correct)
show "sorted (map fst (prime_powers_upto ub))"
"distinct (map fst (prime_powers_upto ub))"
by (simp_all add: sorted_prime_powers_upto distinct_prime_powers_upto)
show "k ∈ {lb..ub}"
using x by (auto simp: k_def le_nat_iff le_floor_iff nat_le_iff floor_le_iff)
show "primes_psi.check c prec (prime_powers_upto ub) lb ub"
using assms by (simp add: check_psi_lower_def)
next
fix p assume "p ≤ ub"
thus "p ∈ fst ` set (prime_powers_upto ub) ⟷ p ∈ {p. primepow p}"
by (force simp: set_prime_powers_upto)
next
fix y
assume y: "y ∈ set (prime_powers_upto ub)"
hence "snd y > 0"
by (auto simp: set_prime_powers_upto intro!: aprimedivisor_pos_nat primepow_gt_Suc_0)
define x where "x = the (lb_ln prec (Float (int (snd y)) 0))"
have "lb_ln prec (Float (int (snd y)) 0) ≠ None"
using ‹snd y > 0› by (subst lb_ln.simps) auto
hence "lb_ln prec (Float (int (snd y)) 0) = Some x"
by (cases "lb_ln prec (Float (int (snd y)) 0)") (auto simp: x_def)
from lb_lnD[OF this] show "real_of_float x ≤ ln (real (aprimedivisor (fst y)))"
using y by (auto simp: set_prime_powers_upto)
qed
also have "primes_psi.S k = primes_psi k"
unfolding primes_psi.S_def primes_psi_def sum_upto_def
by (intro sum.mono_neutral_cong_left) (auto simp: primepow_gt_0_nat mangoldt_def)
also have "primes_psi k = primes_psi x"
unfolding k_def by simp
finally show "c * x ≤ primes_psi x" .
qed
qed
end
context
begin
interpretation primes_psi: chebyshev_check
"λn. ln (real (aprimedivisor n))"
"λprec x. the (ub_ln prec (Float (int (snd x)) 0))"
"{p. primepow p}"
"float_plus_up"
"(≥)"
"λk x. x ≤ c * real k"
"fst"
for c :: real
proof
show "real_of_float (float_plus_up prec X Y) ≥ x + y"
if "real_of_float X ≥ x" "real_of_float Y ≥ y"
for x y :: real and X Y :: float and prec :: nat
using that by (simp add: float_plus_up_le)
qed auto
definition check_psi_upper_aux
where "check_psi_upper_aux = primes_psi.check_aux"
definition check_psi_upper where
"check_psi_upper c prec lb ub =
primes_psi.check c prec (prime_powers_upto ub) lb ub"
lemma check_psi_upper_aux_code [code]:
"check_psi_upper_aux c prec ps lb ub acc n =
(if ub < n then True else let (acc', ps') =
if ps ≠ [] ∧ fst (hd ps) = n
then (float_plus_up prec acc (the (ub_ln prec (Float (int (snd (hd ps))) 0))), tl ps)
else (acc, ps)
in (n < lb ∨ c * real n ≥ real_of_float acc') ∧
check_psi_upper_aux c prec ps' lb
ub acc' (n + 1))"
unfolding check_psi_upper_aux_def
by (rule primes_psi.check_aux.simps)
lemma check_psi_upper_code [code]:
"check_psi_upper c prec lb ub = (let ps = prime_powers_upto ub in
check_psi_upper_aux c prec ps lb ub 0
(if ps = [] then lb else min lb (fst (hd ps))))"
unfolding check_psi_upper_def primes_psi.check_def check_psi_upper_aux_def
by (simp add: Let_def)
lemma check_psi_upper_correct:
assumes "check_psi_upper c prec lb ub" "c ≥ 0"
shows "∀x∈{real lb..real ub}. primes_psi x ≤ c * x"
proof
fix x assume x: "x ∈ {real lb..real ub}"
define k where "k = nat ⌊x⌋"
have "primes_psi.S k ≤ c * real k"
proof (rule primes_psi.check_correct)
show "sorted (map fst (prime_powers_upto ub))"
"distinct (map fst (prime_powers_upto ub))"
by (simp_all add: sorted_prime_powers_upto distinct_prime_powers_upto)
show "k ∈ {lb..ub}"
using x by (auto simp: k_def le_nat_iff le_floor_iff nat_le_iff floor_le_iff)
show "primes_psi.check c prec (prime_powers_upto ub) lb ub"
using assms by (simp add: check_psi_upper_def)
next
fix p assume "p ≤ ub"
thus "p ∈ fst ` set (prime_powers_upto ub) ⟷ p ∈ {p. primepow p}"
by (force simp: set_prime_powers_upto)
next
fix y
assume y: "y ∈ set (prime_powers_upto ub)"
hence "snd y > 0"
by (auto simp: set_prime_powers_upto intro!: aprimedivisor_pos_nat primepow_gt_Suc_0)
define x where "x = the (ub_ln prec (Float (int (snd y)) 0))"
have "ub_ln prec (Float (int (snd y)) 0) ≠ None"
using ‹snd y > 0› by (subst ub_ln.simps) auto
hence "ub_ln prec (Float (int (snd y)) 0) = Some x"
by (cases "ub_ln prec (Float (int (snd y)) 0)") (auto simp: x_def)
from ub_lnD[OF this] show "real_of_float x ≥ ln (real (aprimedivisor (fst y)))"
using y by (auto simp: set_prime_powers_upto)
qed
also have "primes_psi.S k = primes_psi k"
unfolding primes_psi.S_def primes_psi_def sum_upto_def
by (intro sum.mono_neutral_cong_left) (auto simp: primepow_gt_0_nat mangoldt_def)
also have "primes_psi k = primes_psi x"
unfolding k_def by simp
also have "c * real k ≤ c * x"
using x assms by (intro mult_left_mono) (auto simp: k_def)
finally show "primes_psi x ≤ c * x" .
qed
end
end