Theory Far_From_Diagonal

section ‹An exponential improvement far from the diagonal›

theory Far_From_Diagonal 
  imports Zigzag "Stirling_Formula.Stirling_Formula"

begin
                               

subsection ‹An asymptotic form for binomial coefficients via Stirling's formula›

text ‹From Appendix D.3, page 56›

lemma const_smallo_real: "(λn. x)  o(real)"
  by real_asymp

lemma o_real_shift:
  assumes "f  o(real)"
  shows "(λi. f(i+j))  o(real)"
  unfolding smallo_def
proof clarify
  fix c :: real
  assume "(0::real) < c"
  then have *: "F i in sequentially. norm (f i)  c/2 * norm i"
    using assms half_gt_zero landau_o.smallD by blast
  have "F i in sequentially. norm (f (i + j))  c/2 * norm (i + j)"
    using eventually_all_ge_at_top [OF *]
    by (metis (mono_tags, lifting) eventually_sequentially le_add1)
  then have "F i in sequentially. ij  norm (f (i + j))  c * norm i"
    apply eventually_elim
    apply clarsimp
    by (smt (verit, best) 0 < c mult_left_mono nat_distrib(2) of_nat_mono)
  then show "F i in sequentially. norm (f (i + j))  c * norm i"
    using eventually_mp by fastforce
qed

lemma tendsto_zero_imp_o1:
  fixes a :: "nat  real"
  assumes "a  0"
  shows "a  o(1)"
proof -
  have "F n in sequentially. ¦a n¦  c" if "c>0" for c
    using assms order_tendstoD(2) tendsto_rabs_zero_iff eventually_sequentially less_eq_real_def that
      by metis
  then show ?thesis
    by (auto simp: smallo_def)
qed

subsection ‹Fact D.3 from the Appendix›

text ‹And hence, Fact 9.4›

definition "stir  λn. fact n / (sqrt (2*pi*n) * (n / exp 1) ^ n) - 1"

text ‹Generalised to the reals to allow derivatives›
definition "stirG  λn. Gamma (n+1) / (sqrt (2*pi*n) * (n / exp 1) powr n) - 1"

lemma stir_eq_stirG: "n>0  stir n = stirG (real n)"
  by (simp add: stirG_def stir_def add.commute powr_realpow Gamma_fact)

lemma stir_ge0: "n>0  stir n  0"
  using fact_bounds[of n] by (simp add: stir_def)

lemma stir_to_0: "stir  0"
  using fact_asymp_equiv by (simp add: asymp_equiv_def stir_def LIM_zero)

lemma stir_o1: "stir  o(1)"
  using stir_to_0 tendsto_zero_imp_o1 by presburger

lemma fact_eq_stir_times: "n  0  fact n = (1 + stir n) * (sqrt (2*pi*n) * (n / exp 1) ^ n)"
  by (simp add: stir_def)

definition "logstir  λn. if n=0 then 0 else log 2 ((1 + stir n) * sqrt (2*pi*n))"

lemma logstir_o_real: "logstir  o(real)"
proof -
  have "n. 0 < n  ¦log 2 ((1 + stir n) * sqrt (2*pi*n))¦  c * real n" if "c>0" for c
  proof -
    have "n. 2 powr (c*n) / sqrt (2*pi*n)  c+1"
      using that by real_asymp
    moreover have "n. ¦stir n¦  c"
      using stir_o1 that by (auto simp: smallo_def)
    ultimately have "n. ((1 + stir n) * sqrt (2*pi*n))  2 powr (c * n)"
    proof eventually_elim
      fix n
      assume c1: "c+1  2 powr (c * n) / sqrt (2*pi*n)" and lec: "¦stir n¦  c"
      then have "stir n  c"
        by auto
      then show "(1 + stir n) * sqrt (2*pi*n)  2 powr (c*n)"
        using mult_right_mono [OF c1, of "sqrt (2*pi*n)"] lec
        by (smt (verit, ccfv_SIG) c1 mult_right_mono nonzero_eq_divide_eq pos_prod_le powr_gt_zero)
    qed
    then show ?thesis
    proof (eventually_elim, clarify)
      fix n
      assume n: "(1 + stir n) * sqrt (2 * pi * n)  2 powr (c * n)"
        and "n>0"
      have "(1 + stir n) * sqrt (2 * pi * real n)  1"
        using stir_ge0 0 < n mult_ge1_I pi_ge_two by auto
      with n show "¦log 2 ((1 + stir n) * sqrt (2 * pi * n))¦  c * n"
        by (simp add: abs_if le_powr_iff)
    qed
  qed
  then show ?thesis
    by (auto simp: smallo_def logstir_def)
qed

lemma logfact_eq_stir_times:
   "fact n = 2 powr (logstir n) * (n / exp 1) ^ n"
proof-
  have "1 + stir n > 0" if "n0"
    using that by (simp add: stir_def)
  then show ?thesis
    by (simp add: logstir_def fact_eq_stir_times)
qed

lemma mono_G:
  defines "G  (λx::real. Gamma (x + 1) / (x / exp 1) powr x)"
  shows "mono_on {0<..} G"
  unfolding monotone_on_def
proof (intro strip)
  fix x y::real
  assume x: "x  {0<..}" "x  y"
  define GD where "GD  λu::real. Gamma(u+1) * (Digamma(u+1) - ln(u)) / (u / exp 1) powr u"
  have *: "D. (G has_real_derivative D) (at u)  D > 0" if "0 < u" for u 
  proof (intro exI conjI)
    show "(G has_real_derivative GD u) (at u)"
      unfolding G_def GD_def
      using that
      by (force intro!: derivative_eq_intros has_real_derivative_powr' simp: ln_div pos_prod_lt field_simps)
    show "GD u > 0"
      using that by (auto simp: GD_def Digamma_plus_1_gt_ln) ―‹Thank you, Manuel!›
  qed
  show "G x  G y"
    using x DERIV_pos_imp_increasing [OF _ *] by (force simp: less_eq_real_def)
qed

lemma mono_logstir: "mono logstir"
  unfolding monotone_on_def
proof (intro strip)
  fix i j::nat
  assume "ij"
  show "logstir i  logstir j"
  proof (cases "j=0")
    case True
    with ij show ?thesis
      by auto
  next
    case False
    with pi_ge_two have "1 * 1  2 * pi * j"
      by (intro mult_mono) auto
    with False stir_ge0 [of j] have *: "1 * 1  (1 + stir j) * sqrt (2 * pi * real j)"
      by (intro mult_mono) auto
    with i  j mono_G show ?thesis
      by (auto simp: logstir_def stir_eq_stirG stirG_def monotone_on_def)
  qed
qed

definition "ok_fun_94  λk. - logstir k"

lemma ok_fun_94: "ok_fun_94  o(real)"
  unfolding ok_fun_94_def
  using logstir_o_real by simp 

lemma fact_9_4:
  assumes l: "0 < l" "l  k"
  defines "γ  l / (real k + real l)"
  shows "k+l choose l  2 powr ok_fun_94 k * γ powr (-l) * (1-γ) powr (-k)" 
proof -
  have *: "ok_fun_94 k  logstir (k+l) - (logstir k + logstir l)"
    using mono_logstir by (auto simp: ok_fun_94_def monotone_def)
  have "2 powr ok_fun_94 k * γ powr (- real l) * (1-γ) powr (- real k)
      = (2 powr ok_fun_94 k) * (k+l) powr(k+l) / (k powr k * l powr l)"
    by (simp add: γ_def powr_minus powr_add powr_divide divide_simps)
  also have "  (2 powr (logstir (k+l)) / (2 powr (logstir k)  * 2 powr (logstir l)))
                 * (k+l) powr (k+l) / (k powr k * l powr l)"
    by (smt (verit, del_insts) * divide_right_mono mult_less_0_iff mult_right_mono powr_add powr_diff powr_ge_zero powr_mono)
  also have " = fact(k+l) / (fact k * fact l)"
    using l by (simp add: logfact_eq_stir_times powr_add divide_simps flip: powr_realpow)
  also have " = real (k+l choose l)"
    by (simp add: binomial_fact)
  finally show ?thesis .
qed

subsection ‹Fact D.2›

text ‹For Fact 9.6›

lemma D2:
  fixes k l
  assumes t: "0<t" "t  k"
  defines "γ  l / (real k + real l)"
  shows "(k+l-t choose l)  exp (- γ * (t-1)^2 / (2*k)) * (k / (k+l))^t * (k+l choose l)"
proof -
  have "(k+l-t choose l) * inverse (k+l choose l) = (i<t. (k-i) / (k+l-i))"
    using t  k
  proof (induction t)
    case (Suc t)
    then have "t  k"
      by simp
    have "(k + l - t) * (k + l - Suc t choose l) = (k - t) * (k + l - t choose l)"
      by (metis binomial_absorb_comp diff_Suc_eq_diff_pred diff_add_inverse2 diff_commute)
    with Suc.IH [symmetric] Suc(2) show ?case 
      by (simp add: field_simps flip: of_nat_mult of_nat_diff)
  qed auto
  also have " = (real k / (k+l))^t * (i<t. 1 - real i * real l / (real k * (k+l-i)))"
  proof -
    have "1 - i * real l / (real k * (k+l-i)) = ((k-i)/(k+l-i)) * ((k+l) / k)" 
      if "i<t" for i
      using that t  k by (simp add: divide_simps) argo
    then have *: "(i<t. 1 - real i * real l / (real k * (k+l-i))) = (i<t. ((k-i)/(k+l-i)) * ((k+l) / k))"
      by auto
    show ?thesis
      unfolding * prod.distrib by (simp add: power_divide)
  qed
  also have "  (real k / (k+l))^t * exp (- (i<t. real i * real l / (real k * (k+l))))"
  proof (intro mult_left_mono)
    have "real i * real l / (real k * real (k+l-i))  1"
      if "i < t" for i
      using that t  k by (simp add: divide_simps mult_mono)
    moreover have "1 - i * l / (k * real (k+l-i))  exp (- (i * real l / (k * (k + real l))))" (is "_  ?R")
      if "i < t" for i 
    proof -
      have "exp (- (i*l / (k * real (k+l-i))))  ?R"
        using that t  k by (simp add: frac_le_eq divide_le_0_iff mult_mono)
      with exp_minus_ge show ?thesis
        by (smt (verit, best)) 
    qed
    ultimately show "(i<t. 1 - i * real l / (k * real (k+l-i)))  exp (- (i<t. i * real l / (k * real (k+l))))"
      by (force simp: exp_sum simp flip: sum_negf intro!: prod_mono)
  qed auto
  finally have 1: "(k+l-t choose l) * inverse (k+l choose l) 
                  (real k / (k+l))^t * exp (- (i<t. i * γ / k))"
    by (simp add: γ_def mult.commute)
  have **: "γ * (t - 1)^2 / (2*k)  (i<t. i * γ / k)"
  proof -
    have g: "(i<t. real i) = real (t*(t-1)) / 2"
      by (induction t) (auto simp: algebra_simps eval_nat_numeral)
    have "γ * (t-1)^2 / (2*k)  real(t*(t-1)) / 2 * γ/k"
      by (simp add: field_simps eval_nat_numeral divide_right_mono mult_mono γ_def)
    also have " = (i<t. i * γ / k)" 
      unfolding g [symmetric] by (simp add: sum_distrib_right sum_divide_distrib)
    finally show ?thesis .
  qed
  have 0: "0  real (k + l choose l)"
    by simp
  have *: "(k+l-t choose l)  (k / (k+l))^t * exp (- (i<t. i * γ / k)) * (k+l choose l)"
    using order_trans [OF _  mult_right_mono [OF 1 0]]
    by (simp add: less_eq_real_def)
  also have "  (k / (k+l))^t * exp (- γ * (t-1)^2 / (2*k)) *(k+l choose l)"
    using ** by (intro mult_mono) auto
  also have "  exp (- γ * (t-1)^2 / (2 * real k)) * (k / (k+l))^t * (k+l choose l)"
    by (simp add: mult_ac)
  finally show ?thesis 
    using t by simp
qed

text ‹Statement borrowed from Bhavik; no o(k) function›
corollary Far_9_6:
  fixes k l
  assumes t: "0<t" "t  k"
  defines "γ  l / (k + real l)"
  shows "exp (-1) * (1-γ) powr (- real t) * exp (γ * (real t)2 / real(2*k)) * (k-t+l choose l)  (k+l choose l)"
proof -
  have kkl: "k / (k + real l) = 1 - γ" "k+l-t = k-t+l"
    using t by (auto simp: γ_def divide_simps)
  have [simp]: "t + t  Suc (t * t)"
    using t
    by (metis One_nat_def Suc_leI mult_2 mult_right_mono nle_le not_less_eq_eq numeral_2_eq_2 mult_1_right)
  have "0  γ" "γ < 1"
    using t by (auto simp: γ_def)
  then have "γ * (real t * 2)  γ + real k * 2"
    using t by (smt (verit, best) mult_less_cancel_right2 of_nat_0_less_iff of_nat_mono)
  then have *: "γ * t^2 / (2*k) - 1  γ * (t-1)^2 / (2*k)"
    using t 
    apply (simp add: power2_eq_square pos_divide_le_eq divide_simps)
    apply (simp add: algebra_simps)
    done
  then have *: "exp (-1) * exp (γ * t^2 / (2*k))  exp (γ * (t-1)^2 / (2*k))"
    by (metis exp_add exp_le_cancel_iff uminus_add_conv_diff)
  have 1: "exp (γ * (t-1)^2 / (2*k)) * (k+l-t choose l)  (k / (k+l))^t * (k+l choose l)"
    using mult_right_mono [OF D2 [OF t], of "exp (γ * (t-1)^2 / (2*k))" l] t
    by (simp add: γ_def exp_minus field_simps)
  have 2: "(k / (k+l)) powr (- real t) * exp (γ * (t-1)^2 / (2*k)) * (k+l-t choose l)  (k+l choose l)"
    using mult_right_mono [OF 1, of "(1-γ) powr (- real t)"] t
    by (simp add: powr_minus γ_def powr_realpow mult_ac divide_simps)
  then have 3: "(1-γ) powr (- real t) * exp (γ * (t-1)^2 / (2*k)) * (k-t+l choose l)  (k+l choose l)"
    by (simp add: kkl)
  show ?thesis
    apply (rule order_trans [OF _ 3])
    using "*" less_eq_real_def by fastforce
qed


subsection ‹Lemma 9.3›

definition "ok_fun_93g  λγ k. (nat k powr (3/4)) * log 2 k - (ok_fun_71 γ k + ok_fun_94 k) + 1"

lemma ok_fun_93g: 
  assumes "0 < γ" "γ < 1"
  shows "ok_fun_93g γ  o(real)"
proof -
  have "(λk. (nat k powr (3/4)) * log 2 k)  o(real)"
    by real_asymp
  then show ?thesis
    unfolding ok_fun_93g_def
    by (intro ok_fun_71 [OF assms] ok_fun_94 sum_in_smallo const_smallo_real)
qed

definition "ok_fun_93h  λγ k. (2 / (1-γ)) * k powr (19/20) * (ln γ + 2 * ln k)
                                 + ok_fun_93g γ k * ln 2"

lemma ok_fun_93h:
  assumes "0 < γ" "γ < 1"
  shows  "ok_fun_93h γ  o(real)"
proof -
  have "(λk. (2 / (1-γ)) * k powr (19/20) * (ln γ + 2 * ln k))  o(real)"
    by real_asymp
  then show ?thesis
    unfolding ok_fun_93h_def by (metis (mono_tags) ok_fun_93g assms sum_in_smallo(1) cmult_in_smallo_iff')
qed

lemma ok_fun_93h_uniform:
  assumes μ01: "0<μ0" "μ1<1" 
  assumes "e>0" 
  shows  "k. μ. μ  {μ0..μ1}  ¦ok_fun_93h μ k¦ / k  e"
proof -
  define f where "f  λk. ok_fun_73 k + ok_fun_74 k + ok_fun_76 k + ok_fun_94 k"
  define g where "g  λμ k. 2 * real k powr (19/20) * (ln μ + 2 * ln k) / (1-μ)"
  have g: "k. μ. μ0  μ  μ  μ1  ¦g μ k¦ / k  e" if "e>0" for e
  proof (intro eventually_all_geI1 [where L = "nat1 / μ0"])
    show "k. ¦g μ1 k¦ / real k  e"
      using assms that unfolding g_def by real_asymp
  next
    fix k μ 
    assume le_e: "¦g μ1 k¦ / k  e" and μ: "μ0  μ" "μ  μ1" and k: "nat 1/μ0  k"
    then have "k>0"
      using assms gr0I by force
    have ln_k: "ln k  ln (1/μ0)"
      using k 0<μ0 ln_mono by fastforce
    with μ μ01 
    have "¦ln μ + 2 * ln (real k)¦  ¦ln μ1 + 2 * ln (real k)¦"
      by (smt (verit) ln_div ln_mono ln_one)
    with μ k μ1 < 1
    have "¦g μ k¦  ¦g μ1 k¦"       
      by (simp add: g_def abs_mult frac_le mult_mono)
    then show "¦g μ k¦ / real k  e"
      by (smt (verit, best) divide_right_mono le_e of_nat_less_0_iff)
  qed
  have eq93: "ok_fun_93h μ k = g μ k +
         k powr (3/4) * ln k - ((ok_fun_72 μ k + f k) - 1) * ln 2" for μ k
    by (simp add: ok_fun_93h_def g_def ok_fun_71_def ok_fun_93g_def f_def log_def field_simps)

  have ln2: "ln 2  (0::real)"
    by simp
  have le93: "¦ok_fun_93h μ k¦ 
      ¦g μ k¦ + ¦k powr (3/4) * ln k¦ + (¦ok_fun_72 μ k¦ + ¦f k¦ + 1) * ln 2" for μ k
    unfolding eq93
    by (smt (verit, best) mult.commute ln_gt_zero_iff mult_le_cancel_left_pos mult_minus_left)
  define e5 where "e5  e/5"
  have "e5 > 0"
    by (simp add: e>0 e5_def)
  then have A: "k. μ. μ  {μ0..μ1}  ¦g μ k¦ / k  e5" 
    using g by simp
  have B: "k. ¦k powr (3/4) * ln k¦ / k  e5" 
    using 0 < e5 by real_asymp
  have C: "k. μ. μ  {μ0..μ1}  ¦ok_fun_72 μ k¦ * ln 2 / k  e5"
    using ln2 assms ok_fun_72_uniform[OF μ01, of "e5 / ln 2"] e5 > 0
    by (simp add: divide_simps)
  have "f  o(real)"
    by (simp add: f_def ok_fun_73 ok_fun_74 ok_fun_76 ok_fun_94 sum_in_smallo(1))
  then have D: "k. ¦f k¦ * ln 2 / k  e5"
    using e5 > 0 ln2
    by (force simp: smallo_def field_simps eventually_at_top_dense dest!: spec [where x="e5 / ln 2"])
  have E: "k.  ln 2 / k  e5"
    using e5 > 0 ln2 by real_asymp
  have "k. μ. μ  {μ0..μ1}  ¦ok_fun_93h μ k¦ / real k  e5+e5+e5+e5+e5"
    using A B C D E
    apply eventually_elim
    by (fastforce simp: add_divide_distrib distrib_right
          intro!: order_trans [OF  divide_right_mono [OF le93]])
  then show ?thesis
    by (simp add: e5_def)
qed

context P0_min
begin

definition "Big_Far_9_3      
   λμ l. Big_ZZ_8_5 μ l  Big_X_7_1 μ l  Big_Y_6_2 μ l  Big_Red_5_3 μ l
       (kl. p0_min - 3 * eps k > 1/k  k2
              ¦ok_fun_93h μ k / (μ * (1 + 1 / (exp 1 * (1-μ))))¦ / k  0.667 - 2/3)"

lemma Big_Far_9_3:
  assumes "0<μ0" "μ0μ1" "μ1<1" 
  shows "l. μ. μ  {μ0..μ1}  Big_Far_9_3 μ l"
proof -
  define d where "d  λμ::real. μ * (1 + 1 / (exp 1 * (1-μ)))"
  have "d μ0 > 0" 
    using assms by (auto simp: d_def divide_simps add_pos_pos)
  then have dgt: "d μ  d μ0" if "μ  {μ0..μ1}" for μ
    using that assms by (auto simp: d_def frac_le mult_mono)

  define e::real where "e  0.667 - 2/3"
  have "e>0"
    by (simp add: e_def)
  have *: "l. μ. μ  {μ0..μ1}  (kl. ¦ok_fun_93h μ k / d μ¦ / k  e)" 
  proof -
    have "l. kl. (μ. μ  {μ0..μ1}  ¦ok_fun_93h μ k¦ / k  d μ0 * e)" 
      using mult_pos_pos[OF d μ0 > 0 e>0] assms
      using ok_fun_93h_uniform eventually_all_ge_at_top
      by blast  
    then show ?thesis
      apply eventually_elim 
      using dgt 0 < d μ0 0 < e
      by (auto simp: mult_ac divide_simps mult_less_0_iff zero_less_mult_iff split: if_split_asm)
        (smt (verit) mult_less_cancel_left nat_neq_iff of_nat_0_le_iff)
  qed
  with p0_min show ?thesis
    unfolding Big_Far_9_3_def eps_def d_def e_def
    using assms Big_ZZ_8_5 Big_X_7_1 Big_Y_6_2 Big_Red_5_3
    apply (simp add: eventually_conj_iff all_imp_conj_distrib)  
    apply (intro conjI strip eventually_all_ge_at_top; real_asymp)
    done
qed

end (*context P0_Min*)

lemma "(λk. (nat real k powr (3/4)) * log 2 k)  o(real)"
  by real_asymp

lemma RN34_le_2powr_ok:
  fixes l k::nat
  assumes "l  k" "0<k"
  defines "l34  nat real l powr (3/4)"
  shows "RN k l34  2 powr (k powr (3/4) * log 2 k)"
proof -
  have §: "l powr (3/4)  k powr (3/4)"
    by (simp add: assms(1) ceiling_mono powr_mono2)
  have "RN k l34  k powr (l34-1)"
    ―‹Bhavik's off-diagonal Ramsey upper bound; can't use @{term "2^(k+l34)"}
    using RN_le_argpower' k>0 powr_realpow by auto
  also have "  k powr l34"
    using k>0 powr_mono by force
  also have "  2 powr (l34 * log 2 k)"
    by (smt (verit, best) mult.commute k>0 of_nat_0_less_iff powr_log_cancel powr_powr)
  also have "  2 powr (real k powr (3/4) * log 2 k)"
    unfolding l34_def 
  proof (intro powr_mono powr_mono2 mult_mono ceiling_mono of_nat_mono nat_mono l  k)
    show "0  real_of_int k powr (3/4)"
      by (meson le_of_int_ceiling order.trans powr_ge_zero)
  qed (use assms § in auto)
  finally show ?thesis .
qed

text ‹Here @{term n} really refers to the cardinality of @{term V}, 
   so actually @{term nV}
lemma (in Book') Far_9_3:
  defines "δ  min (1/200) (γ/20)"
  defines "  Step_class {red_step}"
  defines "t  card "
  assumes γ15: "γ  1/5" and p0: "p0  1/4" 
    and nge: "n  exp (-δ * real k) * (k+l choose l)" 
    and X0ge: "card X0  n/2" 
           ―‹Because @{term"card X0  n div 2"} makes the proof harder›
  assumes big: "Big_Far_9_3 γ l"
  shows "t  2*k / 3"
proof -
  define 𝒮 where "𝒮  Step_class {dboost_step}"
  have "k2" and big85: "Big_ZZ_8_5 γ l" and big71: "Big_X_7_1 γ l" 
    and big62: "Big_Y_6_2 γ l"  and big53: "Big_Red_5_3 γ l"
    using big l_le_k by (auto simp: Big_Far_9_3_def)
  define l34 where "l34  nat real l powr (3/4)"
  have "l34 > 0"
    using l34_def ln0 by fastforce
  have γ01: "0 < γ" "γ < 1"
    using ln0 l_le_k by (auto simp: γ_def)
  then have bigbeta01: "0 < bigbeta" "bigbeta < 1"
    using big53 assms bigbeta_gt0 bigbeta_less1 by (auto simp: bigbeta_def)
  have one_minus: "1-γ = real k / (real k + real l)"
    using ln0 by (simp add: γ_def divide_simps)
  have "t < k"
    using red_step_limit by (auto simp: ℛ_def t_def)
  have f: "2 powr ok_fun_94 k * γ powr (- real l) * (1-γ) powr (- real k)
           k+l choose l" 
    unfolding γ_def using fact_9_4 l_le_k ln0 by blast
  have powr_combine_right: "x powr a * (x powr b * y) = x powr (a+b) * y" for x y a b::real
    by (simp add: powr_add)
  have "(2 powr ok_fun_71 γ k * 2 powr ok_fun_94 k) * (bigbeta/γ) ^ card 𝒮 * (exp (-δ*k) * (1-γ) powr (- real k + t) / 2)
       2 powr ok_fun_71 γ k * γ^l * (1-γ) ^ t * (bigbeta/γ) ^ card 𝒮 * (exp (-δ*k) * (k+l choose l) / 2)"
    using γ01 0<bigbeta mult_right_mono [OF f, of "2 powr ok_fun_71 γ k * γ^l * (1-γ) ^ t * (bigbeta/γ) ^ card 𝒮 * (exp (-δ*k)) / 2"]
    by (simp add: mult_ac zero_le_mult_iff powr_minus powr_diff divide_simps powr_realpow)
  also have "  2 powr ok_fun_71 γ k * γ^l * (1-γ) ^ t * (bigbeta/γ) ^ card 𝒮 * card X0"
  proof (intro mult_left_mono order_refl)
    show "exp (-δ * k) * real (k+l choose l) / 2  real (card X0)"
      using X0ge nge by force
    show "0  2 powr ok_fun_71 γ k * γ ^ l * (1-γ) ^ t * (bigbeta/γ) ^ card 𝒮"
      using γ01 bigbeta_ge0 by (force simp: bigbeta_def)
  qed
  also have "  card (Xseq halted_point)"
    unfolding ℛ_def 𝒮_def t_def using big 
    by (intro X_7_1) (auto simp: Big_Far_9_3_def)
  also have "  RN k l34"
  proof -
    have "p0 - 3 * ε > 1/k" and "pseq halted_point  p0 - 3 * ε"
      using l_le_k big p0_ge Y_6_2_halted by (auto simp: Big_Far_9_3_def γ_def)
    then show ?thesis
      using halted_point_halted γ01
      by (fastforce simp: step_terminating_iff termination_condition_def pseq_def l34_def)
  qed
  also have "  2 powr (k powr (3/4) * log 2 k)"
    using RN34_le_2powr_ok l34_def l_le_k ln0 by blast
  finally have "2 powr (ok_fun_71 γ k + ok_fun_94 k) * (bigbeta/γ) ^ card 𝒮
               * exp (-δ*k) * (1-γ) powr (- real k + t) / 2
               2 powr (k powr (3/4) * log 2 k)"
    by (simp add: powr_add)
  then have le_2_powr_g: "exp (-δ*k) * (1-γ) powr (- real k + t) * (bigbeta/γ) ^ card 𝒮
              2 powr ok_fun_93g γ k"
    using k2 by (simp add: ok_fun_93g_def field_simps powr_add powr_diff flip: powr_realpow)

  let  = "bigbeta * t / (1-γ) + (2 / (1-γ)) * k powr (19/20)"
  have bigbeta_le: "bigbeta  γ" and bigbeta_ge: "bigbeta  1 / (real k)2"
    using bigbeta_def γ01 big53 bigbeta_le bigbeta_ge_square by blast+
  
  define φ where "φ  λu. (u / (1-γ)) * ln (γ/u)"  ―‹finding the maximum via derivatives›
  have ln_eq: "ln (γ / (γ / exp 1)) / (1-γ) = 1/(1-γ)"
    using γ01 by simp
  have φ: "φ (γ / exp 1)  φ bigbeta"
  proof (cases "γ / exp 1  bigbeta")    ―‹Could perhaps avoid case analysis via 2nd derivatives›
    case True
    show ?thesis 
    proof (intro DERIV_nonpos_imp_nonincreasing [where f = φ])
      fix x
      assume x: "γ / exp 1  x" "x  bigbeta"
      with γ01 have "x>0"
        by (smt (verit, best) divide_pos_pos exp_gt_zero)
      with γ01 x have "ln (γ/x) / (1-γ) - 1 / (1-γ)  0"
        by (smt (verit, ccfv_SIG) divide_pos_pos exp_gt_zero frac_le ln_eq ln_mono)
      with x x>0 γ01 show "D. (φ has_real_derivative D) (at x)  D  0"
        unfolding φ_def by (intro exI conjI derivative_eq_intros | force)+
    qed (simp add: True)
  next
    case False
    show ?thesis
    proof (intro DERIV_nonneg_imp_nondecreasing [where f = φ])
      fix x
      assume x: "bigbeta  x" "x  γ / exp 1"
      with bigbeta01 γ01 have "x>0" by linarith
      with γ01 x have "ln (γ/x) / (1-γ) - 1 / (1-γ)  0"
        by (smt (verit, best) frac_le ln_eq ln_mono zero_less_divide_iff)
      with x x>0 γ01 show "D. (φ has_real_derivative D) (at x)  D  0"
        unfolding φ_def
        by (intro exI conjI derivative_eq_intros | force)+
    qed (use False in force)
  qed

  define c where "c  λx::real. 1 + 1 / (exp 1 * (1-x))" 
  have mono_c: "mono_on {0<..<1} c"
    by (auto simp: monotone_on_def c_def field_simps)
  have cgt0: "c x > 0" if "x<1" for x
    using that by (simp add: add_pos_nonneg c_def)

  have "card 𝒮  bigbeta * t / (1-bigbeta) + (2 / (1-γ)) * k powr (19/20)" 
    using ZZ_8_5 [OF big85] by (auto simp: ℛ_def 𝒮_def t_def)
  also have "  " 
    using bigbeta_le by (simp add: γ01 bigbeta_ge0 frac_le)
  finally have "card 𝒮  " .
  with bigbeta_le bigbeta01 have " * ln (bigbeta/γ)  card 𝒮 * ln (bigbeta/γ)"
    by (simp add: mult_right_mono_neg)
  then have "- * ln (γ/bigbeta)  card 𝒮 * ln (bigbeta/γ)"
    using bigbeta01 γ01 by (smt (verit) ln_div minus_mult_minus)
  then have "γ * (real k - t) - δ*k -  * ln (γ/bigbeta)  γ * (real k - t) - δ*k + card 𝒮 * ln (bigbeta/γ)"
    by linarith
  also have "  (t - real k) * ln (1-γ) - δ*k + card 𝒮 * ln (bigbeta/γ)"
    using t < k γ01 mult_right_mono [OF ln_add_one_self_le_self2 [of "-γ"], of "real k - t"] 
    by (simp add: algebra_simps)
  also have " = ln (exp (-δ*k) * (1-γ) powr (- real k + t) * (bigbeta/γ) ^ card 𝒮)"
    using γ01 bigbeta01 by (simp add: ln_mult ln_div ln_realpow)
  also have "  ln (2 powr ok_fun_93g γ k)"
    using le_2_powr_g γ01 bigbeta01 by (simp del: ln_powr)
  also have " = ok_fun_93g γ k * ln 2"
    by auto
  finally have "γ * (real k - t) - δ*k -  * ln (γ/bigbeta)  ok_fun_93g γ k * ln 2" .
  then have "γ * (real k - t)   * ln (γ/bigbeta) + δ*k + ok_fun_93g γ k * ln 2"
    by simp
  also have "  (bigbeta * t / (1-γ)) * ln (γ/bigbeta) + δ*k + ok_fun_93h γ k"
  proof -
    have "γ/bigbeta  γ * (real k)2"
      using kn0 bigbeta_le bigbeta_ge bigbeta>0 by (simp add: field_simps)
    then have X: "ln (γ/bigbeta)  ln γ + 2 * ln k"
      using bigbeta>0 γ>0 kn0 
      by (metis ln_mult_pos ln_realpow of_nat_numeral of_nat_zero_less_power_iff divide_pos_pos ln_mono)
    show ?thesis
      using mult_right_mono [OF X, of "2 * k powr (19/20) / (1-γ)"] γ<1
      by (simp add: ok_fun_93h_def algebra_simps)
  qed
  also have "  ((γ / exp 1) * t / (1-γ)) + δ*k + ok_fun_93h γ k"
    using γ01 mult_right_mono [OF φ, of t] by (simp add: φ_def mult_ac)
  finally have "γ * (real k - t)  ((γ / exp 1) * t / (1-γ)) + δ*k + ok_fun_93h γ k" .
  then have "(γ-δ) * k - ok_fun_93h γ k  t * γ * c γ"
    by (simp add: c_def algebra_simps)
  then have "((γ-δ) * k - ok_fun_93h γ k) / (γ * c γ)  t"
    using γ01 cgt0 by (simp add: pos_divide_le_eq)
  then have *: "t  (1-δ / γ) * inverse (c γ) * k - ok_fun_93h γ k / (γ * c γ)"  
    using γ01 cgt0[of γ] by (simp add: divide_simps)
  define f47 where "f47  λx. (1 - 1/(200*x)) * inverse (c x)"
  have "concave_on {1/10..1/5} f47"
    unfolding f47_def
  proof (intro concave_on_mul)
    show "concave_on {1/10..1/5} (λx. 1 - 1/(200*x))"
    proof (intro f''_le0_imp_concave)
      fix x::real
      assume "x  {1/10..1/5}"
      then have x01: "0<x" "x<1" by auto
      show "((λx. (1 - 1/(200*x))) has_real_derivative 1/(200*x^2)) (at x)"
        using x01 by (intro derivative_eq_intros | force simp: eval_nat_numeral)+
      show "((λx. 1/(200*x^2)) has_real_derivative -1/(100*x^3)) (at x)"
        using x01 by (intro derivative_eq_intros | force simp: eval_nat_numeral)+
      show "-1/(100*x^3)  0"
        using x01 by (simp add: divide_simps)
    qed auto
    show "concave_on {1/10..1/5} (λx. inverse (c x))"
    proof (intro f''_le0_imp_concave)
      fix x::real
      assume "x  {1/10..1/5}"
      then have x01: "0<x" "x<1" by auto
      have swap: "u * (x-1) = (-u) * (1-x)" for u
        by (metis minus_diff_eq minus_mult_commute)
      have §: "exp 1 * (x - 1) < 0"
        using x01 by (meson exp_gt_zero less_iff_diff_less_0 mult_less_0_iff)
      then have non0: "1 + 1 / (exp 1 * (1-x))  0"
        using x01 by (smt (verit) exp_gt_zero mult_pos_pos zero_less_divide_iff)
      let ?f1 = "λx. -exp 1 /(- 1 + exp 1 * (- 1 + x))2"
      let ?f2 = "λx. 2*exp(1)^2/(-1 + exp(1)*(-1 + x))^3"
      show "((λx. inverse (c x)) has_real_derivative ?f1 x) (at x)"
        unfolding c_def power2_eq_square
        using x01 § non0
        apply (intro exI conjI derivative_eq_intros | force)+
        apply (simp add: divide_simps square_eq_iff swap)
        done
      show "(?f1 has_real_derivative ?f2 x) (at x)"
        using x01 §
        by (intro derivative_eq_intros | force simp: divide_simps eval_nat_numeral)+
      show "?f2 (x::real)  0"
        using x01 § by (simp add: divide_simps)
    qed auto
    show "mono_on {(1::real)/10..1/5} (λx. 1 - 1 / (200 * x))"
      by (auto simp: monotone_on_def frac_le)
    show "monotone_on {1/10..1/5} (≤) (λx y. y  x) (λx. inverse (c x))"
      using mono_c cgt0 by (auto simp: monotone_on_def divide_simps)
  qed (auto simp: c_def)
  moreover have "f47(1/10) > 0.667"
    unfolding f47_def c_def by (approximation 15)
  moreover have "f47(1/5) > 0.667"
    unfolding f47_def c_def by (approximation 15)
  ultimately have 47: "f47 x > 0.667" if "x  {1/10..1/5}" for x
    using concave_on_ge_min that by fastforce

  define f48 where "f48  λx. (1 - 1/20) * inverse (c x)"
  have 48: "f48 x > 0.667" if "x  {0<..<1/10}" for x
  proof -
    have "(0.667::real) < (1 - 1/20) * inverse(c(1/10))"
      unfolding c_def by (approximation 15)
    also have "  f48 x"
      using that unfolding f48_def c_def
      by (intro mult_mono le_imp_inverse_le add_mono divide_left_mono) (auto simp: add_pos_pos)
    finally show ?thesis .
  qed
  define e::real where "e  0.667 - 2/3"
  have BIGH: "abs (ok_fun_93h γ k / (γ * c γ)) / k  e"
    using big l_le_k unfolding Big_Far_9_3_def all_imp_conj_distrib e_def [symmetric] c_def 
    by auto
  consider "γ  {0<..<1/10}" | "γ  {1/10..1/5}"
    using δ_def γ  1/5 γ01 by fastforce
  then show ?thesis
  proof cases
    case 1
    then have δγ: "δ / γ = 1/20"
      by (auto simp: δ_def)
    have "(2/3::real)  f48 γ - e"
      using 48[OF 1] e_def by force
    also have "  (1-δ / γ) * inverse (c γ) - ok_fun_93h γ k / (γ * c γ) / k"
      unfolding f48_def δγ using BIGH
      by (smt (verit, best) divide_nonneg_nonneg of_nat_0_le_iff zero_less_divide_iff)
    finally
    have A: "2/3  (1-δ / γ) * inverse (c γ) - ok_fun_93h γ k / (γ * c γ) / k" .
    have "real (2 * k) / 3  (1 - δ / γ) * inverse (c γ) * k - ok_fun_93h γ k / (γ * c γ)"
      using mult_left_mono [OF A, of k] cgt0 [of γ] γ01 kn0
      by (simp add: divide_simps mult_ac)
    with * show ?thesis
      by linarith
  next
    case 2
    then have δγ: "δ / γ = 1/(200*γ)"
      by (auto simp: δ_def)
    have "(2/3::real)  f47 γ - e"
      using 47[OF 2] e_def by force
    also have "  (1 - δ / γ) * inverse (c γ) - ok_fun_93h γ k / (γ * c γ) / k"
      unfolding f47_def δγ using BIGH
      by (smt (verit, best) divide_right_mono of_nat_0_le_iff)
    finally
    have "2/3  (1 - δ / γ) * inverse (c γ) - ok_fun_93h γ k / (γ * c γ) / k" .
    from mult_left_mono [OF this, of k] cgt0 [of γ] γ01 kn0
    have "real (2 * k) / 3  (1 - δ / γ) * inverse (c γ) * k - ok_fun_93h γ k / (γ * c γ)"
      by (simp add: divide_simps mult_ac)
    with * show ?thesis
      by linarith
  qed
qed

subsection ‹Lemma 9.5›

context P0_min
begin

text ‹Again stolen from Bhavik: cannot allow a dependence on @{term γ}
definition "ok_fun_95a  λk. ok_fun_61 k - (2 + 4 * k powr (19/20))"

definition "ok_fun_95b  λk. ln 2 * ok_fun_95a k - 1"

lemma ok_fun_95a: "ok_fun_95a  o(real)"
proof -
  have "(λk. 2 + 4 * k powr (19/20))  o(real)"
    by real_asymp
  then show ?thesis
    unfolding ok_fun_95a_def using ok_fun_61 sum_in_smallo by blast
qed

lemma ok_fun_95b: "ok_fun_95b  o(real)"
  using ok_fun_95a by (auto simp: ok_fun_95b_def sum_in_smallo const_smallo_real)

definition "Big_Far_9_5  λμ l. Big_Red_5_3 μ l  Big_Y_6_1 μ l  Big_ZZ_8_5 μ l"

lemma Big_Far_9_5:
  assumes "0<μ0" "μ1<1" 
  shows "l. μ. μ0  μ  μ  μ1  Big_Far_9_5 μ l"
  using assms Big_Red_5_3 Big_Y_6_1 Big_ZZ_8_5
  unfolding Big_Far_9_5_def  eps_def
  by (simp add: eventually_conj_iff all_imp_conj_distrib)  

end

text ‹Y0 is an additional assumption found in Bhavik's version. (He had a couple of others).
 The first $o(k)$ function adjusts for the error in $n/2$›
lemma (in Book') Far_9_5:
  fixes δ η::real
  defines "  Step_class {red_step}"
  defines "t  card "
  assumes nV: "real nV  exp (-δ * k) * (k+l choose l)" and Y0: "card Y0  nV div 2"
  assumes p0: "1/2  1-γ-η" "1-γ-η  p0" and "0η"
  assumes big: "Big_Far_9_5 γ l"
  shows "card (Yseq halted_point)  
     exp (-δ * k + ok_fun_95b k) * (1-γ-η) powr (γ*t / (1-γ)) * ((1-γ-η)/(1-γ))^t 
   * exp (γ * (real t)2 / (2*k)) * (k-t+l choose l)"   (is "_  ?rhs")
proof -
  define 𝒮 where "𝒮  Step_class {dboost_step}"
  define s where "s  card 𝒮"
  have γ01: "0 < γ" "γ < 1"
    using ln0 l_le_k by (auto simp: γ_def)
  have big85: "Big_ZZ_8_5 γ l" and big61: "Big_Y_6_1 γ l" and big53: "Big_Red_5_3 γ l"
    using big by (auto simp: Big_Far_9_5_def)
  have "bigbeta  γ" 
    using bigbeta_def γ01 big53 bigbeta_le by blast 
  have 85: "s  (bigbeta / (1-bigbeta)) * t + (2 / (1-γ)) * k powr (19/20)"
    unfolding s_def t_def ℛ_def 𝒮_def using ZZ_8_5 γ01 big85 by blast
  also have "  (γ / (1-γ)) * t + (2 / (1-γ)) * k powr (19/20)"
    using γ01 bigbeta  γ by (intro add_mono mult_right_mono frac_le) auto
  finally have D85: "s  γ*t / (1-γ) + (2 / (1-γ)) * k powr (19/20)"
    by auto
  have "t<k"
    unfolding t_def ℛ_def using γ01 red_step_limit by blast
  have st: "card (Step_class {red_step,dboost_step}) = t + s"
    using γ01
    by (simp add: s_def t_def ℛ_def 𝒮_def Step_class_insert_NO_MATCH card_Un_disjnt disjnt_Step_class)
  then have 61: "2 powr (ok_fun_61 k) * p0 ^ (t+s) * card Y0  card (Yseq halted_point)"
    using Y_6_1[OF big61] card_XY0 γ01 by (simp add: divide_simps)
  have "(1-γ-η) powr (t + γ*t / (1-γ)) * nV  (1-γ-η) powr (t+s - 4 * k powr (19/20)) * (4 * card Y0)"
  proof (intro mult_mono)
    show "(1-γ-η) powr (t + γ*t / (1-γ))  (1-γ-η) powr (t+s - 4 * k powr (19/20))"
    proof (intro powr_mono')
      have "γ  1/2"
        using 0η p0 by linarith
      then have 22: "1 / (1 - γ)  2"
        using divide_le_eq_1 by fastforce
      show "real (t + s) - 4 * real k powr (19 / 20)  real t + γ * real t / (1 - γ)"
        using mult_left_mono [OF 22, of "2 * real k powr (19 / 20)"] D85
        by (simp add: algebra_simps)
    next
      show "0  1 - γ - η" "1 - γ - η  1"
        using assms γ01 by linarith+
    qed
    have "nV  2"
      by (metis nontriv wellformed two_edges card_mono ex_in_conv finV)
    then have "nV  4 * (nV div 2)" by linarith
    also have "  4 * card Y0"
      using Y0 mult_le_mono2 by presburger 
    finally show "real nV  real (4 * card Y0)"      
      by force
  qed (use Y0 in auto)
  also have "  (1-γ-η) powr (t+s) / (1-γ-η) powr (4 * k powr (19/20)) * (4 * card Y0)"
    by (simp add: divide_powr_uminus powr_diff)
  also have "  (1-γ-η) powr (t+s) / (1/2) powr (4 * k powr (19/20)) * (4 * card Y0)"
  proof (intro mult_mono divide_left_mono)
    show "(1/2) powr (4 * k powr (19/20))  (1-γ-η) powr (4 * k powr (19/20))"
      using γ01 p0 0η by (intro powr_mono_both') auto
  qed (use p0 in auto)
  also have "  p0 powr (t+s) / (1/2) powr (4 * k powr (19/20)) * (4 * card Y0)"
    using p0 powr_mono2 by (intro mult_mono divide_right_mono) auto
  also have " = (2 powr (2 + 4 * k powr (19/20))) * p0 ^ (t+s) * card Y0"
    using p0_01 by (simp add: powr_divide powr_add power_add powr_realpow)
  finally have "2 powr (ok_fun_95a k) * (1-γ-η) powr (t + γ*t / (1-γ)) * nV  2 powr (ok_fun_61 k) * p0 ^ (t+s) * card Y0"
    by (simp add: ok_fun_95a_def powr_diff field_simps)
  with 61 have *: "card (Yseq halted_point)  2 powr (ok_fun_95a k) * (1-γ-η) powr (t + γ*t / (1-γ)) * nV"
    by linarith

  have F: "exp (ok_fun_95b k) = 2 powr ok_fun_95a k * exp (- 1)"
    by (simp add: ok_fun_95b_def exp_diff exp_minus powr_def field_simps)
  have "?rhs
    exp (-δ * k) * 2 powr (ok_fun_95a k) * exp (-1) * (1-γ-η) powr (γ*t / (1-γ))
         * (((1-γ-η)/(1-γ)) ^t * exp (γ * (real t)2 / real(2*k)) * (k-t+l choose l))"
    unfolding exp_add F by simp
  also have "   exp (-δ * k) * 2 powr (ok_fun_95a k) * (1-γ-η) powr (γ*t / (1-γ))
         * (exp (-1) * ((1-γ-η)/(1-γ)) ^t * exp (γ * (real t)2 / real(2*k)) * (k-t+l choose l))"
    by (simp add: mult.assoc)
  also have "  2 powr (ok_fun_95a k) * (1-γ-η) powr (t + γ*t / (1-γ)) * exp (-δ * k)
                * (exp (-1) * (1-γ) powr (- real t) * exp (γ * (real t)2 / real(2*k)) * (k-t+l choose l))"
    using p0 γ01
    unfolding powr_add powr_minus by (simp add: mult_ac divide_simps flip: powr_realpow)
  also have "  2 powr (ok_fun_95a k) * (1-γ-η) powr (t + γ*t / (1-γ)) * exp (-δ * k) * (k+l choose l)"
  proof (cases "t=0")
    case False
    then show ?thesis
      unfolding γ_def using t<k by (intro mult_mono order_refl Far_9_6) auto
  qed auto
  also have "  2 powr (ok_fun_95a k) * (1-γ-η) powr (t + γ*t / (1-γ)) * nV"
    using nV mult_left_mono by fastforce
  also have "  card (Yseq halted_point)"
    by (rule *)
  finally show ?thesis .
qed

subsection ‹Lemma 9.2›

context P0_min
begin

lemma error_9_2:
  assumes "μ>0" "d > 0"
  shows "k. ok_fun_95b k + μ * real k / d  0"
proof -
  have "k. ¦ok_fun_95b k¦  (μ/d) * k"
    using ok_fun_95b assms unfolding smallo_def
    by (auto dest!: spec [where x = "μ/d"])
  then show ?thesis
    by eventually_elim force
qed

definition "Big_Far_9_2  λμ l. Big_Far_9_3 μ l  Big_Far_9_5 μ l  (kl. ok_fun_95b k + μ*k/60  0)"

lemma Big_Far_9_2:
  assumes "0<μ0" "μ0μ1" "μ1<1" 
  shows "l. μ. μ0  μ  μ  μ1  Big_Far_9_2 μ l"
proof -
  have "l. kl. (μ. μ0  μ  μ  μ1  0  ok_fun_95b k + μ * k / 60)"
    using assms 
    apply (intro eventually_all_ge_at_top eventually_all_geI0 error_9_2)
     apply (auto simp: divide_right_mono mult_right_mono elim!: order_trans)
    done
  then show ?thesis
    using assms Big_Far_9_3 Big_Far_9_5
    unfolding Big_Far_9_2_def
    apply (simp add: eventually_conj_iff all_imp_conj_distrib)  
    by (smt (verit, ccfv_threshold) eventually_sequentially)
qed

end

text ‹Used for both 9.2 and 10.2›
lemma (in Book') Off_diagonal_conclusion:
  defines "  Step_class {red_step}"
  defines "t  card "
  assumes Y: "(k-t+l choose l)  card (Yseq halted_point)"
  shows False
proof -
  have "t<k"
    unfolding t_def ℛ_def using red_step_limit by blast
  have "RN (k-t) l  card (Yseq halted_point)"
    by (metis Y add.commute RN_commute RN_le_choose le_trans)
  then obtain K 
    where Ksub: "K  Yseq halted_point" 
      and K: "card K = k-t  clique K Red  card K = l  clique K Blue"
    by (meson Red_Blue_RN Yseq_subset_V size_clique_def)
  show False
    using K
  proof
    assume K: "card K = k - t  clique K Red"
    have "clique (K  Aseq halted_point) Red"
    proof (intro clique_Un)
      show "clique (Aseq halted_point) Red"
        by (meson A_Red_clique valid_state_seq)
      have "all_edges_betw_un (Aseq halted_point) (Yseq halted_point)  Red"
        using valid_state_seq Ksub
        by (auto simp: valid_state_def RB_state_def all_edges_betw_un_Un2)
      then show "all_edges_betw_un K (Aseq halted_point)  Red"
        using Ksub all_edges_betw_un_commute all_edges_betw_un_mono2 by blast
      show "K  V"
        using Ksub Yseq_subset_V by blast
    qed (use K Aseq_subset_V in auto)
    moreover have "card (K  Aseq halted_point) = k"
    proof -
      have eqt: "card (Aseq halted_point) = t"
        using red_step_eq_Aseq ℛ_def t_def by simp
      have "card (K  Aseq halted_point) = card K + card (Aseq halted_point) "
      proof (intro card_Un_disjoint)
        show "finite K"
          by (meson Ksub Yseq_subset_V finV finite_subset)
        have "disjnt (Yseq halted_point) (Aseq halted_point)"
          using valid_state_seq by (auto simp: valid_state_def disjoint_state_def)
        with Ksub show "K  Aseq halted_point = {}"
          by (auto simp: disjnt_def)
      qed (simp add: finite_Aseq)
      also have " = k"
        using eqt K t < k by simp
      finally show ?thesis .
    qed
    moreover have "K  Aseq halted_point  V"
      using Aseq_subset_V Ksub Yseq_subset_V by blast
    ultimately show False
      using no_Red_clique size_clique_def by blast
  next
    assume "card K = l  clique K Blue"
    then show False
      using Ksub Yseq_subset_V no_Blue_clique size_clique_def by blast
  qed
qed


text ‹A little tricky to express since the Book locale assumes that 
      there are no cliques in the original graph (page 9). So it's a contrapositive›
lemma (in Book') Far_9_2_aux:
  fixes δ η::real
  defines "δ  γ/20"
  assumes 0: "real (card X0)  nV/2" "card Y0  nV div 2" "p0  1-γ-η"
     ―‹These are the assumptions about the red density of the graph›
  assumes γ: "γ  1/10" and η: "0η" "η  γ/15"
  assumes nV: "real nV  exp (-δ * k) * (k+l choose l)" 
  assumes big: "Big_Far_9_2 γ l"
  shows False
proof -
  define  where "  Step_class {red_step}"
  define t where "t  card "
  have γ01: "0 < γ" "γ < 1"
    using ln0 l_le_k by (auto simp: γ_def)
  have big93: "Big_Far_9_3 γ l" 
    using big by (auto simp: Big_Far_9_2_def)
  have t23: "t  2*k / 3"
    unfolding t_def ℛ_def
  proof (rule Far_9_3)
    show "γ  1/5"
      using γ unfolding γ_def by linarith
    have "min (1/200) (γ / 20)  δ"
      unfolding δ_def using γ ln0 by (simp add: γ_def)
    then show "exp (- min (1/200) (γ / 20) * k) * (k+l choose l)  nV"
      using δ_def γ_def nV by force
    show "1/4  p0"
      using η γ 0 by linarith
    show "Big_Far_9_3 (γ) l"
      using γ_def big93 by blast
  qed (use assms in auto)
  have "t<k"
    unfolding t_def ℛ_def using γ01 red_step_limit by blast

  have ge_half: "1/2  1-γ-η"
    using γ η by linarith
  have "exp (-1/3 + (1/5::real))  exp (10/9 * ln (134/150))"
    by (approximation 9)
  also have "  exp (1 / (1-γ) * ln (134/150))"
    using γ by (auto simp: divide_simps)
  also have "  exp (1 / (1-γ) * ln (1-γ-η))"
    using γ η by (auto simp: divide_simps)
  also have " = (1-γ-η) powr (1 / (1-γ))"
    using ge_half by (simp add: powr_def)
  finally have A: "exp (-1/3 + 1/5)  (1-γ-η) powr (1 / (1-γ))" .

  have "3*t / (10*k)  (-1/3 + 1/5) + t/(2*k)"
    using t23 kn0 by (simp add: divide_simps)
  from mult_right_mono [OF this, of "γ*t"] γ01
  have "3*γ*t2 / (10*k)  γ*t*(-1/3 + 1/5) + γ*t2/(2*k)"
    by (simp add: eval_nat_numeral algebra_simps) 
  then have "exp (3*γ*t2 / (10*k))  exp (-1/3 + 1/5) powr (γ*t) * exp (γ*t2/(2*k))"
    by (simp add: mult_exp_exp exp_powr_real)
  also have "  (1-γ-η) powr ((γ*t) / (1-γ)) * exp (γ*t2/(2*k))"
    using γ01 powr_powr powr_mono2 [of "γ*t" "exp (-1/3 + 1/5)", OF _ _ A]
    by (intro mult_right_mono) auto
  finally have B: "exp (3*γ*t2 / (10*k))  (1-γ-η) powr ((γ*t) / (1-γ)) * exp (γ*t2/(2*k))" .

  have "(2*k / 3)^2  t2"
    using t23 by auto
  from kn0 γ01 mult_right_mono [OF this, of "γ/(80*k)"]
  have C: "δ*k + γ*k/60  3*γ*t2 / (20*k)"
    by (simp add: field_simps δ_def eval_nat_numeral)

  have "exp (- 3*γ*t / (20*k))  exp (-3 * η/2)"
  proof -
    have "1  3/2 * t/k"
      using t23 kn0 by (auto simp: divide_simps)
    from mult_right_mono [OF this, of "γ/15"] γ01 η 
    show ?thesis
      by simp
  qed
  also have "  1 - η / (1-γ)"
  proof -
    have §: "2/3  (1 - γ - η)"
      using γ η by linarith
    have "1 / (1-η / (1-γ)) = 1 + η / (1-γ-η)"
      using ge_half η by (simp add: divide_simps split: if_split_asm)
    also have "  1 + 3 * η / 2"
      using mult_right_mono [OF §, of η] η ge_half by (simp add: field_simps)
    also have "  exp (3 * η / 2)"
      using exp_minus_ge [of "-3*η/2"] by simp
    finally show ?thesis
      using γ01 ge_half 
      by (simp add: exp_minus divide_simps mult.commute split: if_split_asm)
  qed
  also have " = (1-γ-η) / (1-γ)"
    using γ01 by (simp add: divide_simps)
  finally have "exp (- 3*γ*t / (20*k))  (1-γ-η) / (1-γ)" .
  from powr_mono2 [of t, OF _ _ this] ge_half γ01
  have D: "exp (- 3*γ*t2 / (20*k))  ((1-γ-η) / (1-γ))^t"
    by (simp add: eval_nat_numeral powr_powr exp_powr_real mult_ac flip: powr_realpow)

  have Y: "(k-t+l choose l)  card (Yseq halted_point)"
  proof -
    have "1 * real(k-t+l choose l) 
             exp (ok_fun_95b k + γ*k/60) * (k-t+l choose l)"
      using big l_le_k unfolding Big_Far_9_2_def
      by (intro mult_right_mono mult_ge1_I) auto
    also have "  exp (3*γ*t2 / (20*k) + -δ * k + ok_fun_95b k) * (k-t+l choose l)"
      using C by simp
    also have " = exp (3*γ*t2 / (10*k)) * exp (-δ * k + ok_fun_95b k) * exp (- 3*γ*t2 / (20*k))
            * (k-t+l choose l)"
      by (simp flip: exp_add)
    also have "  exp (3*γ*t2 / (10*k)) * exp (-δ * k + ok_fun_95b k) * ((1-γ-η)/(1-γ))^t 
            * (k-t+l choose l)"
      using γ01 ge_half D by (intro mult_right_mono) auto
    also have "  (1-γ-η) powr (γ*t / (1-γ)) * exp (γ * t2 / (2*k)) * exp (-δ * k + ok_fun_95b k) 
                  * ((1-γ-η)/(1-γ))^t * (k-t+l choose l)"
      using γ01 ge_half by (intro mult_right_mono B) auto
    also have " = exp (-δ * k + ok_fun_95b k) * (1-γ-η) powr (γ*t / (1-γ)) * ((1-γ-η)/(1-γ))^t 
                  * exp (γ * (real t)2 / (2*k)) * (k-t+l choose l)"
      by (simp add: mult_ac)
    also have 95: "  real (card (Yseq halted_point))"
      unfolding t_def ℛ_def
    proof (rule Far_9_5)
      show "1/2  1 - γ - η"
        using ge_half γ_def by blast
      show "Big_Far_9_5 (γ) l"
        using Big_Far_9_2_def big unfolding γ_def by presburger
    qed (use assms in auto)
    finally show ?thesis by simp
  qed
  then show False
    using Off_diagonal_conclusion by (simp flip: ℛ_def t_def)
qed

text ‹Mediation of 9.2 (and 10.2) from locale @{term Book_Basis} to the book locales
   with the starting sets of equal size›
lemma (in No_Cliques) to_Book:
  assumes gd: "p0_min  graph_density Red"
  assumes μ01: "0 < μ" "μ < 1"
  obtains X0 Y0 where "l2" "card X0  real nV / 2" "card Y0 = gorder div 2" 
    and "X0 = V  Y0" "Y0V" 
    and "graph_density Red  gen_density Red X0 Y0"
    and "Book V E p0_min Red Blue l k μ X0 Y0" 
proof -
  have "Red  {}"
    using gd p0_min by (auto simp: graph_density_def)
  then have "gorder  2"
    by (metis Red_E card_mono equals0I finV subset_empty two_edges wellformed)
  then have div2: "0 < gorder div 2" "gorder div 2 < gorder"
    by auto
  then obtain Y0 where Y0: "card Y0 = gorder div 2" "Y0V" 
    "graph_density Red  gen_density Red (VY0) Y0"
    by (metis complete Red_E exists_density_edge_density gen_density_commute)
  define X0 where "X0  V  Y0" 
  interpret Book V E p0_min Red Blue l k μ X0 Y0
  proof
    show "X0V" "disjnt X0 Y0"
      by (auto simp: X0_def disjnt_iff)
    show "p0_min  gen_density Red X0 Y0"
      using X0_def Y0 gd gen_density_commute p0_min by auto
  qed (use assms Y0V in auto)
  have False if "l<2"
    using that unfolding less_2_cases_iff
  proof
    assume "l = Suc 0" 
    with Y0 div2 show False
      by (metis RN_1' no_Red_clique no_Blue_clique Red_Blue_RN Suc_leI kn0)
  qed (use ln0 in auto)
  with l_le_k have "l2"
    by force
  have card_X0: "card X0  nV/2"
    using Y0 Y0V unfolding X0_def
    by (simp add: card_Diff_subset finite_Y0)
  then show thesis
    using Book_axioms X0_def Y0 2  l that by blast
qed

text ‹Material that needs to be proved \textbf{outside} the book locales›

text ‹As above, for @{term Book'}
lemma (in No_Cliques) to_Book':
  assumes gd: "p0_min  graph_density Red"
  assumes l: "0<l" "lk"
  obtains X0 Y0 where "l2" "card X0  real nV / 2" "card Y0 = gorder div 2" and "X0 = V  Y0" "Y0V" 
    and "graph_density Red  gen_density Red X0 Y0"
    and "Book' V E p0_min Red Blue l k (real l / (real k + real l)) X0 Y0" 
proof -
  define γ where "γ  real l / (real k + real l)"
  have "0 < γ" "γ < 1"
    using l by (auto simp: γ_def)
  with assms to_Book [of  γ]
  obtain X0 Y0 where *: "l2" "card X0  real nV / 2" "card Y0 = gorder div 2" "X0 = V  Y0" "Y0V" 
    "graph_density Red  gen_density Red X0 Y0" "Book V E p0_min Red Blue l k γ X0 Y0"
    by blast
  then interpret Book V E p0_min Red Blue l k γ X0 Y0
    by blast
  have "Book' V E p0_min Red Blue l k γ X0 Y0"
    using Book' γ_def by auto
  with * assms show ?thesis
    using γ_def  that by blast
qed

lemma (in No_Cliques) Far_9_2:
  fixes δ γ η::real
  defines "γ  l / (real k + real l)"
  defines "δ  γ/20"
  assumes gd: "graph_density Red  1-γ-η" and p0_min_OK: "p0_min  1-γ-η"  
  assumes "γ  1/10" and η: "0η" "η  γ/15"
  assumes nV: "real nV  exp (-δ * k) * (k+l choose l)" 
  assumes big: "Big_Far_9_2 γ l" 
  shows False
proof -
  obtain X0 Y0 where "l2" and card_X0: "card X0  real nV / 2" 
    and card_Y0: "card Y0 = gorder div 2" 
    and X0_def: "X0 = V  Y0" and "Y0V" 
    and gd_le: "graph_density Red  gen_density Red X0 Y0"
    and "Book' V E p0_min Red Blue l k γ X0 Y0" 
    using to_Book' assms p0_min no_Red_clique no_Blue_clique ln0 by auto
  then interpret Book' V E p0_min Red Blue l k γ X0 Y0
    by blast 
  show False
  proof (intro Far_9_2_aux [of η])
    show "1 - γ - η  p0"
      using X0_def γ_def gd gd_le gen_density_commute p0_def by auto
  qed (use assms card_X0 card_Y0 in auto)
qed

subsection ‹Theorem 9.1›

text ‹An arithmetical lemma proved outside of the locales›
lemma kl_choose: 
  fixes l k::nat
  assumes "m<l" "k>0"
  defines "PM  i<m. (l - real i) / (k+l-real i)"
  shows "(k+l choose l) = (k+l-m choose (l-m)) / PM"
proof -
  have inj: "inj_on (λi. i-m) {m..<l}" ―‹relating the power and binomials; maybe easier using factorials›
    by (auto simp: inj_on_def)
  have "(i<l. (k+l-i) / (l-i)) / (i<m. (k+l-i) / (l-i))
      = (i = m..<l. (k+l-i) / (l-i))"
    using prod_divide_nat_ivl [of 0 m l "λi. (k+l-i) / (l-i)"] m < l
    by (simp add: atLeast0LessThan)
  also have " = (i<l - m. (k+l-m - i) / (l-m-i))"
    apply (intro prod.reindex_cong [OF inj, symmetric])
    by (auto simp: image_minus_const_atLeastLessThan_nat)
  finally
  have "(i < l-m. (k+l-m - i) / (l-m-i)) 
      = (i < l. (k+l-i) / (l-i)) / (i<m. (k+l-i) / (l-i))" 
    by linarith
  also have " = (k+l choose l) * inverse (i<m. (k+l-i) / (l-i))"
    by (simp add: field_simps atLeast0LessThan binomial_altdef_of_nat) 
  also have " = (k+l choose l) * PM"
    unfolding PM_def using m < l k>0
    by (simp add: atLeast0LessThan flip: prod_inversef)
  finally have "(k+l-m choose (l-m)) = (k+l choose l) * PM"
    by (simp add: atLeast0LessThan binomial_altdef_of_nat)
  then show "real(k+l choose l) = (k+l-m choose (l-m)) / PM"
    by auto
qed


context P0_min
begin

text ‹The proof considers a smaller graph, so @{term l} needs to be so big
   that the smaller @{term l'} will be big enough.›
definition Big_Far_9_1 :: "real  nat  bool" where
  "Big_Far_9_1  λμ l. l3  (l' γ. real l'  (10/11) * μ * real l  μ2  γ  γ  1/10  Big_Far_9_2 γ l')"

text ‹The proof of theorem 10.1 requires a range of values›
lemma Big_Far_9_1:
  assumes "0<μ0" "μ01/10"
  shows "l. μ. μ0  μ  μ  1/10  Big_Far_9_1 μ l"
proof -
  have "μ02  1/10"
    using assms by (smt (verit, ccfv_threshold) le_divide_eq_1 mult_left_le power2_eq_square)
  then have "l. γ. μ02  γ  γ  1/10  Big_Far_9_2 γ l"
    using assms by (intro Big_Far_9_2) auto
  then obtain N where N: "lN. γ. μ02  γ  γ  1/10  Big_Far_9_2 γ l"
    using eventually_sequentially by auto
  define M where "M  nat11*N / (10*μ0)"
  have "(10/11) * μ0 * l  N" if "l  M" for l
    using that by (simp add: M_def μ0>0 mult_of_nat_commute pos_divide_le_eq)
  with N have "lM. l' γ. (10/11) * μ0 * l  l'  μ02  γ  γ  1 / 10  Big_Far_9_2 γ l'"
    by (smt (verit, ccfv_SIG) of_nat_le_iff)
  then have "l. l' γ. (10/11) * μ0 * l  l'  μ02  γ  γ  1 / 10  Big_Far_9_2 γ l'"
    by (auto simp: eventually_sequentially)
  moreover have "l. l3"
    by simp
  ultimately show ?thesis
    unfolding Big_Far_9_1_def 
    apply eventually_elim
    by (smt (verit) 0<μ0 mult_left_mono mult_right_mono of_nat_less_0_iff power_mono zero_less_mult_iff)
qed

text ‹The text claims the result for all @{term k} and @{term l}, not just those sufficiently large,
  but the $o(k)$ function allowed in the exponent provides a fudge factor›
theorem Far_9_1:
  fixes l k::nat
  fixes δ γ::real
  defines "γ  real l / (real k + real l)"
  defines "δ  γ/20"
  assumes γ: "γ  1/10" 
  assumes big: "Big_Far_9_1 γ l"
  assumes p0_min_91: "p0_min  1 - (1/10) * (1 + 1/15)"
  shows "RN k l  exp (-δ*k + 1) * (k+l choose l)"
proof (rule ccontr)
  assume non: "¬ RN k l  exp (-δ * k + 1) * (k+l choose l)"
  with RN_eq_0_iff have "l>0" by force
  with γ have l9k: "9*l  k"
    by (auto simp: γ_def divide_simps)
  have "lk"
    using γ_def γ nat_le_real_less by fastforce
  with l>0 have "k>0" by linarith
  define ξ::real where "ξ  1/15"
  define U_lower_bound_ratio where ―‹Bhavik's name›
    "U_lower_bound_ratio  λm. (1+ξ)^m * (i<m. (l - real i) / (k+l - real i))"

  define n where "n  RN k l - 1"
  have "l3"
    using big by (auto simp: Big_Far_9_1_def)
  have "k27"
    using l9k l3 by linarith
  have "exp 1 / (exp 1 - 2) < (27::real)"
    by (approximation 5)
  also have RN27: "  RN k l"
    by (meson RN_3plus' l3 k27 le_trans numeral_le_real_of_nat_iff)
  finally have "exp 1 / (exp 1 - 2) < RN k l" .
  moreover have "n < RN k l"
    using RN27 by (simp add: n_def)
  moreover have "2 < exp (1::real)"
    by (approximation 5)
  ultimately have nRNe: "n/2 > RN k l / exp 1"
    by (simp add: n_def field_split_simps)

  have "(k+l choose l) / exp (-1 + δ*k) < RN k l"
    by (smt (verit) divide_inverse exp_minus mult_minus_left mult_of_nat_commute non)
  then have "(RN k l / exp 1) * exp (δ*k) > (k+l choose l)"
    unfolding exp_add exp_minus by (simp add: field_simps)
  with nRNe have n2exp_gt: "(n/2) * exp (δ*k) > (k+l choose l)"
    by (smt (verit, best) exp_gt_zero mult_le_cancel_right_pos)
  then have nexp_gt: "n * exp (δ*k) > (k+l choose l)"
    by simp

  define V where "V  {..<n}"
  define E where "E  all_edges V" 
  interpret Book_Basis V E
  proof qed (auto simp: V_def E_def comp_sgraph.wellformed comp_sgraph.two_edges)
  have [simp]: "nV = n"
    by (simp add: V_def)
  then obtain Red Blue
    where Red_E: "Red  E" and Blue_def: "Blue = E-Red" 
      and no_Red_K: "¬ (K. size_clique k K Red)"
      and no_Blue_K: "¬ (K. size_clique l K Blue)"
    by (metis n < RN k l less_RN_Red_Blue)
  have Blue_E: "Blue  E" and disjnt_Red_Blue: "disjnt Red Blue" 
  and  Blue_eq: "Blue = all_edges V - Red"
    using complete by (auto simp: Blue_def disjnt_iff E_def) 
  define is_good_clique where
    "is_good_clique  λi K. clique K Blue  K  V 
                                 card (V  (wK. Neighbours Blue w))
                                  real i * U_lower_bound_ratio (card K) - card K"
  have is_good_card: "card K < l" if "is_good_clique i K" for i K
    using no_Blue_K that unfolding is_good_clique_def 
    by (metis nat_neq_iff size_clique_def size_clique_smaller)
  define GC where "GC  {C. is_good_clique n C}"
  have "GC  {}"
    by (auto simp: GC_def is_good_clique_def U_lower_bound_ratio_def E_def V_def)
  have "GC  Pow V"
    by (auto simp: is_good_clique_def GC_def)
  then have "finite GC"
    by (simp add: finV finite_subset)
  then obtain W where "W  GC" and MaxW: "Max (card ` GC) = card W"
    using GC  {} obtains_MAX by blast
  then have 49: "is_good_clique n W"
    using GC_def by blast
  have max49: "¬ is_good_clique n (insert x W)" if "xVW" for x
  proof 
    assume x: "is_good_clique n (insert x W)"
    then have "card (insert x W) = Suc (card W)"
      using finV is_good_clique_def finite_subset that by fastforce
    with x finite GC have "Max (card ` GC)  Suc (card W)"
      by (simp add: GC_def rev_image_eqI)
    then show False
      by (simp add: MaxW)
  qed

  have "WV"
    using 49 by (auto simp: is_good_clique_def)
  define m where "m  card W"
  define γ' where "γ'  (l - real m) / (k+l-real m)"
  define η where "η  ξ * γ'"

  have Red_Blue_RN: "K  X. size_clique m K Red  size_clique n K Blue"
    if "card X  RN m n" "XV" for m n and X 
    using partn_lst_imp_is_clique_RN [OF is_Ramsey_number_RN [of m n]] finV that  
    unfolding is_clique_RN_def size_clique_def clique_indep_def Blue_eq 
    by (metis clique_iff_indep finite_subset subset_trans)
  define U where "U  V  (wW. Neighbours Blue w)"
  define EU where "EU  E  Pow U"
  define RedU where "RedU  Red  Pow U"
  define BlueU where "BlueU  Blue  Pow U"

  have "RN k l > 0"
    using n < RN k l by auto
  have "γ' > 0"
    using is_good_card [OF 49] by (simp add: γ'_def m_def)
  then have "η > 0"
    by (simp add: η_def ξ_def)
  have "finite W"
    using W  V finV finite_subset by (auto simp: V_def)
  have "U  V" and VUU: "V  U = U"
    by (force simp: U_def)+
  have "disjnt U W"
    using Blue_E not_own_Neighbour unfolding E_def V_def U_def disjnt_iff by blast
  have "m<l"
    using 49 is_good_card m_def by blast
  then have γ1516: "γ'  15/16"
    using γ_def γ by (simp add: γ'_def divide_simps)
  then have γ'_le1: "(1+ξ) * γ'  1"
    by (simp add: ξ_def)

  have cardU: "n * U_lower_bound_ratio m  m + card U"
    using 49 VUU unfolding is_good_clique_def U_def m_def by force
  obtain [iff]: "finite RedU" "finite BlueU" "RedU  EU"
    using BlueU_def EU_def RedU_def E_def V_def Red_E Blue_E fin_edges finite_subset by blast 
  have card_RedU_le: "card RedU  card EU"
    by (metis EU_def E_def RedU  EU card_mono fin_all_edges finite_Int)
  interpret UBB: Book_Basis U "E  Pow U" p0_min 
  proof
    fix e 
    assume "e  E  Pow U"
    with two_edges show "e  U" "card e = 2" by auto
  next
    show "finite U"
      using U  V by (simp add: V_def finite_subset)
    have "x  E" if "x  all_edges U" for x 
      using U  V all_edges_mono that complete E_def by blast
    then show "E  Pow U = all_edges U"
      using comp_sgraph.wellformed U  V by (auto intro: e_in_all_edges_ss)
  qed auto

  have clique_W: "size_clique m W Blue"
    using 49 is_good_clique_def size_clique_def V_def m_def by blast

  define PM where "PM  i<m. (l - real i) / (k+l-real i)"
  then have U_lower_m: "U_lower_bound_ratio m = (1+ξ)^m * PM"
    using U_lower_bound_ratio_def by blast
  have prod_gt0: "PM > 0"
    unfolding PM_def using m<l by (intro prod_pos) auto

  have kl_choose: "real(k+l choose l) = (k+l-m choose (l-m)) / PM"
    unfolding PM_def using kl_choose 0 < k m < l by blast
  ―‹Now a huge effort just to show that @{term U} is nontrivial.
     Proof probably shows its cardinality exceeds a multiple of @{term l}
  define ekl20 where "ekl20  exp (k / (20*(k+l)))"
  have ekl20_eq: "exp (δ*k) = ekl20^l"
      by (simp add: δ_def γ_def ekl20_def field_simps flip: exp_of_nat2_mult)
  have "ekl20  exp(1/20)"
    unfolding ekl20_def using m < l by fastforce
  also have "  (1+ξ)"
    unfolding ξ_def by (approximation 10)
  finally have exp120: "ekl20  1 + ξ" .
  have ekl20_gt0: "0 < ekl20"
    by (simp add: ekl20_def)

  have "3*l + Suc l - q  (k+q choose q) / exp(δ*k) * (1+ξ) ^ (l - q)"
    if "1q" "ql" for q
    using that
  proof (induction q rule: nat_induct_at_least)
    case base
    have "ekl20^l = ekl20^(l-1) * ekl20"
      by (metis 0 < l power_minus_mult)
    also have "  (1+ξ) ^ (l-1) * ekl20"
      using ekl20_def exp120 power_mono by fastforce
    also have "  2 * (1+ξ) ^ (l-1)"
    proof -
      have §: "ekl20  2"
        using ξ_def exp120 by linarith
      from mult_right_mono [OF this, of "(1+ξ) ^ (l-1)"] 
      show ?thesis by (simp add: mult_ac ξ_def)
    qed
    finally have "ekl20^l  2 * (1+ξ) ^ (l-1)"
      by argo 
    then have "1/2  (1+ξ) ^ (l-1) / ekl20^l"
      using ekl20_def by auto
    moreover have "4 * real l / (1 + real k)  1/2"
      using l9k by (simp add: divide_simps)
    ultimately have "4 * real l / (1 + real k)  (1+ξ) ^ (l-1) / ekl20^l"
      by linarith
    then show ?case
      by (simp add: field_simps ekl20_eq)
  next
    case (Suc q)
    then have : "(1+ξ) ^ (l - q) = (1+ξ) * (1+ξ) ^ (l - Suc q)"
      by (metis Suc_diff_le diff_Suc_Suc power.simps(2))
    have "real(k + q choose q)  real(k + q choose Suc q)" "0  (1+ξ) ^ (l - Suc q)"
      using Suc q  l l9k by (auto simp: ξ_def binomial_mono) 
    from mult_right_mono [OF this]
    have "(k + q choose q) * (1+ξ) ^ (l - q) / exp (δ * k) - 1 
         (real (k + q choose q) + (k + q choose Suc q)) * (1+ξ) ^ (l - Suc q) / exp (δ * k)"
      unfolding  by (simp add: ξ_def field_simps add_increasing)
    with Suc show ?case by force      
  qed
  from m<l this [of "l-m"] 
  have "1 + 3*l + real m  (k+l-m choose (l-m)) / exp δ ^ k * (1+ξ) ^ m"
    by (simp add: Suc_leI exp_of_nat2_mult)
  also have "  (k+l-m choose (l-m)) / exp (δ * k) * (1+ξ) ^ m"
    by (simp add: exp_of_nat2_mult)
  also have " < PM * (real n * (1+ξ) ^ m)"
  proof -
    have §: "(k+l choose l) / exp (δ * k) < n"
      by (simp add: less_eq_real_def nexp_gt pos_divide_less_eq)
    show ?thesis
      using mult_strict_left_mono [OF §, of "PM * (1+ξ) ^ m"] kl_choose prod_gt0
      by (auto simp: field_simps ξ_def)
  qed
  also have " = real n * U_lower_bound_ratio m"
    by (simp add: U_lower_m)
  finally have U_MINUS_M: "3*l + 1 < real n * U_lower_bound_ratio m - m"
    by linarith
  then have cardU_gt: "card U > 3*l + 1"
    using cardU by linarith
  with UBB.complete have "card EU > 0" "card U > 1"
    by (simp_all add: EU_def UBB.finV card_all_edges)
  have BlueU_eq: "BlueU = EU  RedU" 
    using Blue_eq complete by (fastforce simp: BlueU_def RedU_def EU_def V_def E_def)
  have [simp]: "UBB.graph_size = card EU"
    using EU_def by blast
  have "γ'  γ"
    using m<l k>0 by (simp add: γ_def γ'_def field_simps)
  have False if "UBB.graph_density RedU < 1 - γ' - η"
  proof -    ―‹by maximality, etc.›
    have §: "UBB.graph_density BlueU  γ' + η" 
      using that card EU > 0 card_RedU_le 
      by (simp add: BlueU_eq UBB.graph_density_def diff_divide_distrib card_Diff_subset)
    have Nx: "Neighbours BlueU x  (U  {x}) = Neighbours BlueU x" for x 
      using that by (auto simp: BlueU_eq EU_def Neighbours_def)
    have "BlueU  E  Pow U"
      using BlueU_eq EU_def by blast
    with UBB.exists_density_edge_density [of 1 BlueU]
    obtain x where "xU" and x: "UBB.graph_density BlueU  UBB.gen_density BlueU {x} (U{x})"
      by (metis UBB.complete 1 < UBB.gorder card_1_singletonE insertI1 zero_less_one subsetD)
    with § have "γ' + η  UBB.gen_density BlueU (U{x}) {x}"
      using UBB.gen_density_commute by auto
    then have *: "(γ' + η) * (card U - 1)  card (Neighbours BlueU x)"
      using BlueU  E  Pow U card U > 1 x  U
      by (simp add: UBB.gen_density_def UBB.edge_card_eq_sum_Neighbours UBB.finV divide_simps Nx)

    have x: "x  VW"
      using x  U U  V disjnt U W by (auto simp: U_def disjnt_iff)
    moreover
    have "is_good_clique n (insert x W)"
      unfolding is_good_clique_def
    proof (intro conjI)
      show "clique (insert x W) Blue"
      proof (intro clique_insert)
        show "clique W Blue"
          using 49 is_good_clique_def by blast
        show "all_edges_betw_un {x} W  Blue"
          using xU by (auto simp: U_def all_edges_betw_un_def insert_commute in_Neighbours_iff)
      qed (use W  V x  VW in auto)
    next
      show "insert x W  V"
        using W  V x  VW by auto
    next
      have NB_Int_U: "Neighbours Blue x  U = Neighbours BlueU x"
        using x  U by (auto simp: BlueU_def U_def Neighbours_def)
      have ulb_ins: "U_lower_bound_ratio (card (insert x W)) = U_lower_bound_ratio m * (1+ξ) * γ'"
        using x  VW finite W by (simp add: U_lower_bound_ratio_def γ'_def m_def)
      have "n * U_lower_bound_ratio (card (insert x W))  = n * U_lower_bound_ratio m * (1+ξ) * γ'"
        by (simp add: ulb_ins)
      also have "  real (m + card U) * (1+ξ) * γ'"
        using mult_right_mono [OF cardU, of "(1+ξ) * γ'"] 0 < η 0 < γ' η_def by argo
      also have "  m + card U * (1+ξ) * γ'"
        using mult_left_mono [OF γ'_le1, of m] by (simp add: algebra_simps)
      also have "  Suc m + (γ' + η) * (UBB.gorder - Suc 0)"
        using * x  VW finite W cardU_gt γ1516
        apply (simp add: U_lower_bound_ratio_def ξ_def η_def)
        by (simp add: algebra_simps)
      also have "  Suc m + card (V   (Neighbours Blue ` insert x W))"
        using * NB_Int_U finV by (simp add: U_def Int_ac)
      also have " = real (card (insert x W) + card (V   (Neighbours Blue ` insert x W)))"
        using x finite W VUU by (auto simp: U_def m_def)
      finally show "n * U_lower_bound_ratio (card(insert x W)) - card(insert x W)
                    card (V   (Neighbours Blue ` insert x W))" 
        by simp
    qed
    ultimately show False
      using max49 by blast
  qed
  then have gd_RedU_ge: "UBB.graph_density RedU  1 - γ' - η" by force

  ―‹Bhavik's gamma'\_le\_gamma\_iff›
  have γ'γ2: "γ' < γ2  (real k * real l) + (real l * real l) < (real k * real m) + (real l * (real m * 2))"
    using m < l
    apply (simp add: γ'_def γ_def eval_nat_numeral divide_simps; simp add: algebra_simps)
    by (metis k>0 mult_less_cancel_left_pos of_nat_0_less_iff distrib_left)
  also have "   (l * (k+l)) / (k + 2 * l) < m"
    using m < l by (simp add: field_simps)
  finally have γ'γ2_iff: "γ' < γ2  (l * (k+l)) / (k + 2 * l) < m" .
  ―‹in both cases below, we find a blue clique of size @{term"l-m"}
  have extend_Blue_clique: "K'. size_clique l K' Blue" 
    if "K  U" "size_clique (l-m) K Blue" for K
  proof -
    have K: "card K = l-m" "clique K Blue"
      using that by (auto simp: size_clique_def)
    define K' where "K'  K  W"
    have "card K' = l"
      unfolding K'_def
    proof (subst card_Un_disjnt)
      show "finite K" "finite W"
        using UBB.finV K  U finite_subset finite W by blast+
      show "disjnt K W"
        using disjnt U W K  U disjnt_subset1 by blast
      show "card K + card W = l"
        using K m < l m_def by auto
    qed
    moreover have "clique K' Blue"
      using clique K Blue clique_W K  U
      unfolding K'_def size_clique_def U_def 
      by (force simp: in_Neighbours_iff insert_commute intro: Ramsey.clique_Un)
    ultimately show ?thesis
      unfolding K'_def size_clique_def using K  U U  V W  V by auto
  qed

  show False
  proof (cases "γ' < γ2")
    case True
    with γ'γ2 have YKK: "γ*k  m" 
      using 0<k m < l 
      apply (simp add: γ_def field_simps)
      by (smt (verit, best) distrib_left mult_left_mono of_nat_0_le_iff)
    have ln1ξ: "ln (1+ξ) * 20  1"
      unfolding ξ_def by (approximation 10)
    with YKK have §: "m * ln (1+ξ)  δ * k"
      unfolding δ_def using zero_le_one mult_mono by fastforce
    have powerm: "(1+ξ)^m  exp (δ * k)"
      using exp_mono [OF §]
      by (smt (verit) η_def 0 < η 0 < γ' exp_ln_iff exp_of_nat_mult zero_le_mult_iff)
    have "n * (1+ξ)^m  (k+l choose l)"
      by (smt (verit, best) mult_left_mono nexp_gt of_nat_0_le_iff powerm)
    then have **: "n * U_lower_bound_ratio m  (k+l-m choose (l-m))"
      using m<l prod_gt0 kl_choose by (auto simp: U_lower_m field_simps)

    have m_le_choose: "m  (k+l-m-1 choose (l-m))"
    proof (cases "m=0")
      case False
      have "m  (k+l-m-1 choose 1)"
        using lk m<l by simp
      also have "  (k+l-m-1 choose (l-m))"
        using False lk m<l by (intro binomial_mono) auto
      finally have m_le_choose: "m  (k+l-m-1 choose (l-m))" .
      then show ?thesis .
    qed auto
    have "RN k (l-m)  k + (l-m) - 2 choose (k - 1)"
      by (rule RN_le_choose_strong)
    also have "  (k+l-m-1 choose k)"
      using lk m<l choose_reduce_nat by simp
    also have " = (k+l-m-1 choose (l-m-1))"
      using m<l by (simp add: binomial_symmetric [of k])
    also have " = (k+l-m choose (l-m)) - (k+l-m-1 choose (l-m))"
      using lk m<l choose_reduce_nat by simp
    also have "  (k+l-m choose (l-m)) - m"
      using m_le_choose by linarith
    finally have "RN k (l-m)  (k+l-m choose (l-m)) - m" .
    then have "card U  RN k (l-m)"
      using 49 ** VUU by (force simp: is_good_clique_def U_def m_def)
    with Red_Blue_RN no_Red_K U  V
    obtain K where "K  U" "size_clique (l-m) K Blue" by meson
    then show False
      using no_Blue_K extend_Blue_clique by blast
  next
    case False 
    have YMK: "γ-γ'  m/k"
      using m<l 
      apply (simp add: γ_def γ'_def divide_simps)
      apply (simp add: algebra_simps)
      by (smt (verit) mult_left_mono mult_right_mono nat_less_real_le of_nat_0_le_iff)

    define δ' where "δ'  γ'/20"
    have no_RedU_K: "¬ (K. UBB.size_clique k K RedU)"
      unfolding UBB.size_clique_def RedU_def
      by (metis Int_subset_iff VUU all_edges_subset_iff_clique no_Red_K size_clique_def)
    have "(K. UBB.size_clique k K RedU)  (K. UBB.size_clique (l-m) K BlueU)"
    proof (rule ccontr)
      assume neg: "¬ ((K. UBB.size_clique k K RedU)  (K. UBB.size_clique (l-m) K BlueU))"
      interpret UBB_NC: No_Cliques U "E  Pow U" p0_min RedU BlueU "l-m" k
      proof
        show "BlueU = E  Pow U  RedU"
          using BlueU_eq EU_def by fastforce
      qed (use neg EU_def RedU  EU no_RedU_K lk in auto)
      show False
      proof (intro UBB_NC.Far_9_2)
        have "exp (δ*k) * exp (-δ'*k) = exp (γ*k/20 - γ'*k/20)"
          unfolding δ_def δ'_def by (simp add: mult_exp_exp) 
        also have "  exp (m/20)"
          using YMK 0 < k by (simp add: left_diff_distrib divide_simps)
        also have "  (1+ξ)^m"
        proof -
          have "ln (16 / 15) * 20  (1::real)"
            by (approximation 5)
          from mult_left_mono [OF this] 
          show ?thesis
            by (simp add: ξ_def powr_def mult_ac flip: powr_realpow)
        qed
        finally have expexp: "exp (δ*k) * exp (-δ'*k)  (1+ξ) ^ m" .

        have "exp (-δ'*k) * (k + (l-m) choose (l-m)) = exp (-δ'*k) * PM * (k+l choose l)"
          using m < l kl_choose by force
        also have " < (n/2) * exp (δ*k) * exp (-δ'*k) * PM"
          using n2exp_gt prod_gt0 by auto 
        also have "  (n/2) * (1+ξ) ^ m * PM"
          using expexp less_eq_real_def prod_gt0 by fastforce
        also have "  n * U_lower_bound_ratio m - m"  ―‹where I was stuck: the "minus m"›
          using PM_def U_MINUS_M U_lower_bound_ratio_def m < l by fastforce
        finally have "exp (-δ'*k) * (k + (l-m) choose (l-m))  n * U_lower_bound_ratio m - m"
          by linarith 
        also have "  UBB.nV"
          using cardU by linarith
        finally have "exp (-δ'*k) * (k + (l-m) choose (l-m))  UBB.nV" .
        then show "exp (- ((l-m) / (k + real (l-m)) / 20) * k) * (k + (l-m) choose (l-m))  UBB.nV"
          using m < l by (simp add: δ'_def γ'_def) argo
      next
        show "1 - real (l-m) / (real k + real (l-m)) - η  UBB.graph_density RedU"
          using gd_RedU_ge γ'  γ m < l unfolding γ_def γ'_def
          by (smt (verit) less_or_eq_imp_le of_nat_add of_nat_diff)
        have "p0_min  1 - γ - η"
          using γ'  γ γ p0_min_91 by (auto simp: η_def ξ_def)
        also have "  1 - (l-m) / (real k + real (l-m)) - η"
          using γ'  γ m<l by (simp add: γ_def γ'_def algebra_simps)
        finally show "p0_min  1 - (l-m) / (real k + real (l-m)) - η" .
      next
        have "m  l * (k + real l) / (k + 2 * real l)"
          using False γ'γ2_iff by auto 
        also have "  l * (1 - (10/11)*γ)"
          using γ l>0 by (simp add: γ_def field_split_simps)
        finally have "m  real l * (1 - (10/11)*γ)" 
          by force
        then have "real l - real m  (10/11) * γ * l"
          by (simp add: algebra_simps)
        then have "Big_Far_9_2 γ' (l-m)"
          using False big γ'  γ γ m<l
          by (simp add: Big_Far_9_1_def)
        then show "Big_Far_9_2 ((l-m) / (real k + real (l-m))) (l-m)"
          by (simp add: γ'_def m < l add_diff_eq less_or_eq_imp_le)
        show "(l-m) / (real k + real (l-m))  1/10"
          using γ γ_def m < l by fastforce
        show "0  η"
          using 0 < η by linarith
        show "η  (l-m) / (real k + real (l-m)) / 15"
          using mult_right_mono [OF γ'  γ, of ξ]
          by (simp add: η_def γ'_def m < l ξ_def add_diff_eq less_or_eq_imp_le mult.commute)
      qed
    qed
    with no_RedU_K obtain K where "K  U" "UBB.size_clique (l-m) K BlueU"
      by (meson UBB.size_clique_def)
    then show False
      using no_Blue_K extend_Blue_clique VUU
      unfolding UBB.size_clique_def size_clique_def BlueU_def
      by (metis Int_subset_iff all_edges_subset_iff_clique) 
  qed
qed

end (*context P0_min*)

end