Theory Irrationals_From_THEBOOK

section ‹Some irrational numbers›
text ‹From Aigner and Ziegler, \emph{Proofs from THE BOOK} (Springer, 2018), Chapter 8, pp. 50--51.›

theory Irrationals_From_THEBOOK imports "Stirling_Formula.Stirling_Formula"
   
begin

subsection ‹Basic definitions and their consequences›

definition hf where "hf  λn. λx::real. (x^n * (1-x)^n) / fact n"

definition cf where "cf  λn i. if i < n then 0 else (n choose (i-n)) * (-1)^(i-n)"

text ‹Mere knowledge that the coefficients are integers is not enough later on.›
lemma hf_int_poly:
  fixes x::real
  shows "hf n = (λx. (1 / fact n) * (i=0..2*n. real_of_int (cf n i) * x^i))"
proof 
  fix x
  have inj: "inj_on ((+)n) {..n}" 
    by (auto simp: inj_on_def)
  have [simp]: "((+)n) ` {..n} = {n..2*n}"
    using nat_le_iff_add by fastforce
  have "(x^n * (-x + 1)^n) = x ^ n * (kn. real (n choose k) * (- x) ^ k)"
    unfolding binomial_ring by simp
  also have " = x ^ n * (kn. real_of_int ((n choose k) * (-1)^k) * x ^ k)"
    by (simp add: mult.assoc flip: power_minus)
  also have " = (kn. real_of_int ((n choose k) * (-1)^k) * x ^ (n+k))"
    by (simp add: sum_distrib_left mult_ac power_add)
  also have " = (i=n..2*n. real_of_int (cf n i) * x^i)"
    by (simp add: sum.reindex [OF inj, simplified] cf_def)
  finally have "hf n x = (1 / fact n) * (i = n..2 * n. real_of_int (cf n i) * x^i)"
    by (simp add: hf_def)
  moreover have "(i = 0..<n. real_of_int (cf n i) * x^i) = 0"
    by (simp add: cf_def)
  ultimately show "hf n x = (1 / fact n) * (i = 0..2 * n. real_of_int (cf n i) * x^i)"
    using sum.union_disjoint [of "{0..<n}" "{n..2*n}" "λi. real_of_int (cf n i) * x^i"]
    by (simp add: ivl_disj_int_two(7) ivl_disj_un_two(7) mult_2)
qed

text ‹Lemma (ii) in the text has strict inequalities, but that's more work and is less useful.›
lemma 
  assumes "0  x" "x  1" 
  shows hf_nonneg: "0  hf n x" and hf_le_inverse_fact: "hf n x  1/fact n"
  using assms by (auto simp: hf_def divide_simps mult_le_one power_le_one)

lemma hf_differt [iff]: "hf n differentiable at x"
  unfolding hf_int_poly differentiable_def
  by (intro derivative_eq_intros exI | simp)+

lemma deriv_sum_int:
  "deriv (λx. i=0..n. real_of_int (c i) * x^i) x 
       = (if n=0 then 0 else (i=0..n-1. of_int((i+1) * c(Suc i)) * x^i))"
  (is "deriv ?f x = (if n=0 then 0 else ?g)")
proof -
  have "(?f has_real_derivative ?g) (at x)" if "n > 0"
  proof -
    have "(i = 0..n. i * x ^ (i - Suc 0) * (c i))
        = (i = 1..n. (real (i-1) + 1) * of_int (c i) * x ^ (i-1))"
      using that by (auto simp: sum.atLeast_Suc_atMost intro!: sum.cong)
    also have " = sum ((λi. (real i + 1) * c (Suc i) * x^i)  (λn. n-1)) 
                     {1..Suc (n-1)}"
      using that by simp
    also have " = ?g"
      by (simp flip: sum.atLeast_atMost_pred_shift [where m=0])
    finally have §: "(a = 0..n. a * x ^ (a - Suc 0) * (c a)) = ?g" .
    show ?thesis
      by (rule derivative_eq_intros § | simp)+
  qed
  then show ?thesis
    by (force intro: DERIV_imp_deriv)
qed

text ‹We calculate the coefficients of the $k$th derivative precisely.›
lemma hf_deriv_int_poly:
  "(deriv^^k) (hf n) = (λx. (1/fact n) * (i=0..2*n-k. of_int (int({i<..i+k}) * cf n (i+k)) * x^i))"
proof (induction k)
  case 0
  show ?case 
    by (simp add: hf_int_poly)
next
  case (Suc k)
  define F where "F  λx. (i = 0..2*n - k. real_of_int (int({i<..i+k}) * cf n (i+k)) * x^i)"
  have Fd: "F field_differentiable at x" for x
    unfolding field_differentiable_def F_def
    by (rule derivative_eq_intros exI | force)+
  have [simp]: "prod int {i<..Suc (i + k)} = (1 + int i) * prod int {Suc i<..Suc (i + k)}" for i
    by (metis Suc_le_mono atLeastSucAtMost_greaterThanAtMost le_add1 of_nat_Suc prod.head) 
  have "deriv (λx. F x / fact n) x 
      = (i = 0..2 * n - Suc k. of_int (int({i<..i+ Suc k}) * cf n (Suc (i+k))) * x^i) / fact n" for x
    unfolding deriv_cdivide_right [OF Fd]
    by (fastforce simp add: F_def deriv_sum_int cf_def simp flip: of_int_mult intro: sum.cong)
  then show ?case
    by (simp add: Suc F_def)
qed

lemma hf_deriv_0: "(deriv^^k) (hf n) 0  "
proof (cases "n  k")
  case True
  then obtain j where "(fact k::real) = real_of_int j * fact n"
    by (metis fact_dvd dvd_def mult.commute of_int_fact of_int_mult) 
  moreover have "prod real {0<..k} = fact k"
    by (simp add: fact_prod atLeastSucAtMost_greaterThanAtMost)
  ultimately show ?thesis
    by (simp add: hf_deriv_int_poly dvd_def)
next
  case False
  then show ?thesis
    by (simp add: hf_deriv_int_poly cf_def)
qed

lemma deriv_hf_minus: "deriv (hf n) = (λx. - deriv (hf n) (1-x))"
proof 
  fix x
  have "hf n = hf n  (λx. (1-x))"
    by (simp add: fun_eq_iff hf_def mult.commute)
  then have "deriv (hf n) x = deriv (hf n  (λx. (1-x))) x"
    by fastforce
  also have " = deriv (hf n) (1-x) * deriv ((-) 1) x"
    by (intro real_derivative_chain) auto
  finally show "deriv (hf n) x = - deriv (hf n) (1-x)"
    by simp
qed

lemma deriv_n_hf_diffr [iff]: "(deriv^^k) (hf n) field_differentiable at x"
  unfolding field_differentiable_def hf_deriv_int_poly
  by (rule derivative_eq_intros exI | force)+

lemma deriv_n_hf_minus: "(deriv^^k) (hf n) = (λx. (-1)^k * (deriv^^k) (hf n) (1-x))"
proof (induction k)
  case 0
  then show ?case
    by (simp add: fun_eq_iff hf_def)
next
  case (Suc k)
  have o: "(λx. (deriv ^^ k) (hf n) (1-x)) = (deriv ^^ k) (hf n)  (-) 1"
    by auto
  show ?case
  proof
    fix x
    have [simp]: "((deriv^^k) (hf n)  (-) 1) field_differentiable at x"
      by (force intro: field_differentiable_compose)
    have "(deriv ^^ Suc k) (hf n) x = deriv (λx. (-1) ^ k * (deriv ^^ k) (hf n) (1-x)) x"
      by simp (metis Suc)
    also have " = (-1) ^ k * deriv (λx. (deriv ^^ k) (hf n) (1-x)) x"
      using o by fastforce
    also have " = (-1) ^ Suc k * (deriv ^^ Suc k) (hf n) (1-x)"
      by (subst o, subst deriv_chain, auto)
    finally show "(deriv ^^ Suc k) (hf n) x = (-1) ^ Suc k * (deriv ^^ Suc k) (hf n) (1-x)" .
  qed
qed

subsection ‹Towards the main result›

lemma hf_deriv_1: "(deriv^^k) (hf n) 1  "
  by (smt (verit, best) Ints_1 Ints_minus Ints_mult Ints_power deriv_n_hf_minus hf_deriv_0)

lemma hf_deriv_eq_0: "k > 2*n  (deriv^^k) (hf n) = (λx. 0)"
  by (force simp add: cf_def hf_deriv_int_poly)

text ‹The case for positive integers›
lemma exp_nat_irrational:
  assumes "s > 0" shows "exp (real_of_int s)  "
proof
  assume "exp (real_of_int s)  "
  then obtain a b where ab: "a > 0" "b > 0" "coprime a b" and exp_s: "exp s = of_int a / of_int b"
    by (smt (verit) Rats_cases' divide_nonpos_pos exp_gt_zero of_int_0_less_iff)
  define n where "n  nat (max (a^2) (3 * s^3))"
  then have ns3: "s^3  real n / 3"
    by linarith
  have "n > 0"
    using a > 0 by (simp add: n_def max.strict_coboundedI1)
  then have "s ^ (2*n+1)  s ^ (3*n)"
    using a > 0 assms by (intro power_increasing) auto
  also have " = real_of_int(s^3) ^ n"
    by (simp add: power_mult)
  also have "  (n / 3) ^ n"
    using assms ns3 by (simp add: power_mono)
  also have "  (n / exp 1) ^ n"
    using exp_le n > 0 by (auto simp: divide_simps)
  finally have s_le: "s ^ (2*n+1)  (n / exp 1) ^ n"
    by presburger 
  have a_less: "a < sqrt (2*pi*n)"
  proof -
    have "2*pi > 1"
      using pi_ge_two by linarith
    have "a  sqrt n"
      using 0 < n n_def of_nat_nat real_le_rsqrt by fastforce
    also have " < sqrt (2*pi*n)"
      by (simp add: 0 < n 1 < 2 * pi)
    finally show ?thesis .
  qed
  have "sqrt (2*pi*n) * (n / exp 1) ^ n > a * s ^ (2*n+1)"
    using mult_strict_right_mono [OF a_less] mult_left_mono [OF s_le]
    by (smt (verit, best) s_le ab(1) assms of_int_1 of_int_le_iff of_int_mult zero_less_power)
  then have n: "fact n > a * s ^ (2*n+1)"
    using fact_bounds(1) by (smt (verit, best) 0 < n of_int_fact of_int_less_iff)
  define F where "F  λx. i2*n. (-1)^i * s^(2*n-i) * (deriv^^i) (hf n) x"
  have Fder: "(F has_real_derivative -s * F x + s^(2*n+1) * hf n x) (at x)" for x
  proof -
    have *: "sum f {..n+n} = sum f {..<n+n}" if "f (n+n) = 0" for f::"nat  real"
      by (smt (verit, best) lessThan_Suc_atMost sum.lessThan_Suc that)
    have [simp]: "(deriv ((deriv ^^ (n+n)) (hf n)) x) = 0"
      using hf_deriv_eq_0 [where k= "Suc(n+n)"] by simp
    have §: "(kn+n. (-1) ^ k * ((deriv ^^ Suc k) (hf n) x * of_int s ^ (n+n - k))) 
           + s * (j=0..n+n. (-1) ^ j * ((deriv ^^ j) (hf n) x * of_int s ^ (n+n - j))) 
           = s * (hf n x * of_int s ^ (n+n))" 
      using n>0
      apply (subst sum_Suc_reindex)
      apply (simp add: algebra_simps atLeast0AtMost)
      apply (force simp add: * mult.left_commute [of "of_int s"] minus_nat.diff_Suc sum_distrib_left 
              simp flip: sum.distrib intro: comm_monoid_add_class.sum.neutral split: nat.split_asm)
      done
    show ?thesis
      unfolding F_def 
      apply (rule derivative_eq_intros field_differentiable_derivI | simp)+
      using § by (simp add: algebra_simps atLeast0AtMost eval_nat_numeral)
  qed
  have F01_Ints: "F 0  " "F 1  "
    by (simp_all add: F_def hf_deriv_0 hf_deriv_1 Ints_sum)
  define sF where "sF  λx. exp (of_int s * x) * F x"
  define sF' where "sF'  λx. of_int s ^ Suc(2*n) * (exp (of_int s * x) * hf n x)"
  have sF_der: "(sF has_real_derivative sF' x) (at x)" for x
    unfolding sF_def sF'_def
    by (rule refl Fder derivative_eq_intros | force simp: algebra_simps)+
  let ?N = "b * integral {0..1} sF'"
  have sF'_integral: "(sF' has_integral sF 1 - sF 0) {0..1}"
    by (smt (verit) fundamental_theorem_of_calculus has_real_derivative_iff_has_vector_derivative 
                    has_vector_derivative_at_within sF_der)
  then have "?N = a * F 1 - b * F 0"
    using b > 0 by (simp add: integral_unique exp_s sF_def algebra_simps)
  also have "  "
    using hf_deriv_1 by (simp add: F01_Ints)
  finally have N_Ints: "?N  " .
  have "sF' (1/2) > 0" and ge0: "x. x  {0..1}  0  sF' x"
    using assms by (auto simp: sF'_def hf_def)
  moreover have "continuous_on {0..1} sF'"
    unfolding sF'_def hf_def by (intro continuous_intros) auto
  ultimately have False if "(sF' has_integral 0) {0..1}"
    using has_integral_0_cbox_imp_0 [of 0 1 sF' "1/2"] that by auto
  then have "integral {0..1} sF' > 0"
    by (metis ge0 has_integral_nonneg integral_unique order_le_less sF'_integral) 
  then have "0 < ?N"
    by (simp add: b > 0)
  have "integral {0..1} sF' = of_int s ^ Suc(2*n) * integral {0..1} (λx. exp (s*x) * hf n x)"
    unfolding sF'_def by force 
  also have "  of_int s ^ Suc(2*n) * (exp s * (1 / fact n))"
  proof (rule mult_left_mono)
    have "integral {0..1} (λx. exp (s*x) * hf n x)  integral {0..1} (λx::real. exp s * (1/fact n))"
    proof (intro mult_mono integral_le)
      show "(λx. exp (s*x) * hf n x) integrable_on {0..1}"
        using 0 < ?N not_integrable_integral sF'_def by fastforce
    qed (use assms hf_nonneg hf_le_inverse_fact in auto)
    also have " = exp s * (1 / fact n)"
      by simp
    finally show "integral {0..1} (λx. exp (s*x) * hf n x)  exp s * (1 / fact n)" .
  qed (use assms in auto)
  finally have "?N  b * of_int s ^ Suc(2*n) * exp s * (1 / fact n)"
    using b > 0 by (simp add: sF'_def mult_ac divide_simps)
  also have " < 1"
    using n apply (simp add: field_simps exp_s)
    by (metis of_int_fact of_int_less_iff of_int_mult of_int_power)
  finally show False
    using 0 < ?N Ints_cases N_Ints by force
qed

theorem exp_irrational:
  fixes q::real assumes "q  " "q  0" shows "exp q  "
proof 
  assume q: "exp q  "
  obtain s t where "s  0" "t > 0" "q = of_int s / of_int t"
    by (metis Rats_cases' assms div_0 of_int_0)
  then have "(exp q) ^ (nat t) = exp s"
    by (smt (verit, best) exp_divide_power_eq of_nat_nat zero_less_nat_eq)
  moreover have "exp q ^ (nat t)  "
    by (simp add: q)
  ultimately show False
    by (smt (verit, del_insts) Rats_inverse s  0 exp_minus exp_nat_irrational of_int_of_nat)
qed

corollary ln_irrational: 
  fixes q::real assumes "q  " "q > 0"  "q  1" shows "ln q  "
  using assms exp_irrational [of "ln q"] exp_ln_iff [of q] by force

end