Theory Splitting_Methods

(* Author: Maximilian Schäffeler *)

theory Splitting_Methods
  imports
    Value_Iteration
    Policy_Iteration
begin

section ‹Value Iteration using Splitting Methods›

subsection ‹Regular Splittings for Matrices and Bounded Linear Functions›

definition "is_splitting_blin X Q R 
  X = Q - R  invertibleL Q  nonneg_blinfun (invL Q)  nonneg_blinfun R"

lemma is_splitting_blinD[dest]: 
  assumes "is_splitting_blin X Q R"
  shows "X = Q - R" "invertibleL Q" "nonneg_blinfun (invL Q)" "nonneg_blinfun R"
  using is_splitting_blin_def assms by auto

lemma is_splitting_blinI[intro]: 
  assumes "X = Q - R" "invertibleL Q" "nonneg_blinfun (invL Q)" "nonneg_blinfun R"
  shows "is_splitting_blin X Q R"
  using is_splitting_blin_def assms by auto

subsection ‹Splitting Methods for MDPs›

locale MDP_QR = MDP_att_ℒ A K r l 
  for A :: "'s::countable  'a::countable set" 
    and K :: "('s × 'a)  's pmf"
    and r l +
  fixes Q R :: "('s  'a)  ('s b real) L ('s b real)"
  assumes is_splitting: "d. d  DD  is_splitting_blin (id_blinfun - l *R 𝒫1 (mk_dec_det d)) (Q d) (R d)"
  and QR_contraction: "(dDD. norm (invL (Q d) oL R d)) < 1"
  and QR_bdd: "bdd_above ((λd. norm (invL (Q d) oL R d)) ` DD)"
  and Q_bdd: "bounded ((λd. norm (invL (Q d))) ` DD)"
  and arg_max_ex_split: "d. s. is_arg_max (λd. invL (Q d) (r_decb (mk_dec_det d) + R d v) s) (λd. d  DD) d"
begin

lemma inv_Q_mono: "d  DD  u  v  (invL (Q d)) u  (invL (Q d)) v"
  using is_splitting 
  by (auto intro!: nonneg_blinfun_mono)

lemma splitting_eq: "d  DD  Q d - R d = (id_blinfun - l *R 𝒫1 (mk_dec_det d))"
  using is_splitting
  by fastforce

lemma Q_nonneg: "d  DD  0  v  0  invL (Q d) v"
  using is_splitting nonneg_blinfun_nonneg 
  by auto

lemma Q_invertible: "d  DD  invertibleL (Q d)"
  using is_splitting
  by auto

lemma R_nonneg: "d  DD  0  v  0  R d v"
  using is_splitting_blinD[OF is_splitting]
  by (fastforce simp: nonneg_blinfun_nonneg intro: nonneg_blinfun_mono)

lemma R_mono: "d  DD  u  v  (R d) u  (R d) v"
  using R_nonneg[of d "v - u"]
  by (auto simp: blinfun.bilinear_simps)

lemma QR_nonneg: "d  DD  0  v  0  (invL (Q d) oL R d) v"
  by (simp add: Q_nonneg R_nonneg)

lemma QR_mono: "d  DD  u  v  (invL (Q d) oL R d) u  (invL (Q d) oL R d) v"
  using QR_nonneg[of d "v - u"]
  by (auto simp: blinfun.bilinear_simps)

lemma norm_QR_less_one: "d  DD  norm (invL (Q d) oL R d) < 1"
  using QR_bdd
  by (auto intro: cSUP_lessD[OF _ QR_contraction])

lemma splitting: "d  DD  id_blinfun - l *R 𝒫1 (mk_dec_det d) = Q d - R d"
  using is_splitting
  by auto

subsection ‹Discount Factor @{term "QR_disc"}
abbreviation "QR_disc  (d  DD. norm (invL (Q d) oL R d))"

lemma QR_le_QR_disc: "d  DD  norm (invL (Q d) oL (R d))  QR_disc"
  using QR_bdd
  by (auto intro!: cSUP_upper)

lemma a_nonneg: "0  QR_disc"
  using QR_contraction norm_ge_zero ex_dec_det QR_bdd
  by (fastforce intro!: cSUP_upper2)

subsection ‹Bellman-Operator›
abbreviation "L_split d v  invL (Q d) (r_decb (mk_dec_det d) + R d v)"

definition "ℒ_split v s = (d  DD. L_split d v s)"

lemma ℒ_split_bfun_aux:
  assumes "d  DD"
  shows "norm (L_split d v)  (d  DD. norm (invL (Q d))) * rM + norm v"
proof -
  have "norm (L_split d v)  norm (invL (Q d) (r_decb (mk_dec_det d))) + norm (invL (Q d) (R d v))"
    by (simp add: blinfun.add_right norm_triangle_ineq)
  also have "  norm (invL (Q d) (r_decb (mk_dec_det d))) + norm (invL (Q d) oL R d) * norm v"    
    by (auto simp: blinfun_apply_blinfun_compose[symmetric] norm_blinfun simp del: blinfun_apply_blinfun_compose)
  also have "  norm (invL (Q d) (r_decb (mk_dec_det d))) + norm v"
    using norm_QR_less_one assms
    by (fastforce intro!: mult_left_le_one_le)
  also have "  norm (invL (Q d)) * rM + norm v"
    by (auto intro!: order.trans[OF norm_blinfun] mult_left_mono simp:  norm_r_dec_le)
  also have "  (d  DD. norm (invL (Q d))) * rM + norm v"
    using Q_bdd bounded_imp_bdd_above
    by (auto intro!: mult_right_mono cSUP_upper assms simp: rM_nonneg)
  finally show ?thesis.
qed

lemma L_split_le: "d  DD  L_split d v s  (d  DD. norm (invL (Q d))) * rM + norm v"
  using le_norm_bfun order.trans[OF le_norm_bfun ℒ_split_bfun_aux]
  by auto

lift_definition b_split :: "('s b real)  ('s b real)" is ℒ_split 
  unfolding ℒ_split_def bfun_def
  using order.trans[OF abs_le_norm_bfun ℒ_split_bfun_aux] ex_dec_det
  by (fastforce intro!: boundedI cSup_abs_le)

lemma b_split_def': "b_split v s = (dDD. L_split d v s)"
  unfolding b_split.rep_eq ℒ_split_def
  by auto

lemma b_split_contraction: "dist (b_split v) (b_split u)  QR_disc * dist v u"
proof -
  have
    "b_split v s - b_split u s  QR_disc * norm (v - u)" if h: "b_split u s  b_split v s" for u v s
  proof -
    obtain d where d: "is_arg_max (λd. invL (Q d) (r_decb (mk_dec_det d) + R d v) s) (λd. d  DD) d"
      using arg_max_ex_split by blast
    hence *: "invL (Q d) (r_decb (mk_dec_det d) + R d u) s  b_split u s"
      by (fastforce simp: b_split_def' is_arg_max_linorder intro!: cSUP_upper2 L_split_le)
    have "invL (Q d) (r_decb (mk_dec_det d) + R d v) s = b_split v s"
      by (auto simp: b_split_def' arg_max_SUP[OF d])
    hence "b_split v s - b_split u s = invL (Q d) (r_decb (mk_dec_det d) + R d v) s - b_split u s"
      by auto
    also have "  (invL (Q d) oL R d) (v - u) s"
      using * by (auto simp: blinfun.bilinear_simps)
    also have "  norm ((invL (Q d) oL R d)) * norm (v - u)"
      by (fastforce intro: order.trans[OF le_norm_bfun norm_blinfun])
    also have "  QR_disc * norm (v - u)"
      using QR_contraction d QR_bdd
      by (auto simp: is_arg_max_linorder intro!: mult_right_mono cSUP_upper2)
    finally show ?thesis.
  qed
  hence "¦(b_split v - b_split u) s¦  QR_disc * dist v u" for s
    by (cases "b_split v s  b_split u s") (fastforce simp: dist_norm norm_minus_commute)+
  thus ?thesis
    by (auto intro!: cSUP_least simp: dist_bfun.rep_eq dist_real_def)
qed

lemma b_lim:
  "∃!v. b_split v = v"
  "(λn. (b_split ^^ n) v)  (THE v. b_split v = v)"
  using banach'[of b_split] a_nonneg QR_contraction b_split_contraction
  unfolding is_contraction_def
  by auto

lemma b_split_tendsto_opt: "(λn. (b_split ^^ n) v)  νb_opt"
proof -
  obtain L where l_fix: "b_split L = L"
    using b_lim(1) by auto
  have "νb (mk_stationary_det d)  L" if d: "d  DD" for d
  proof -
    let ?QR = "invL (Q d) oL R d"
    have "invL (Q d) (r_decb (mk_dec_det d) + R d L)  b_split L"
      unfolding less_eq_bfun_def b_split_def'
      using d L_split_le by (auto intro!: bdd_aboveI cSUP_upper2)
    hence "invL (Q d) (r_decb (mk_dec_det d) + R d L)  L"
      using l_fix by auto
    hence aux: "invL (Q d) (r_decb (mk_dec_det d))  (id_blinfun - ?QR) L"
      using that by (auto simp: blinfun.bilinear_simps le_diff_eq)
    have inv_eq: "invL (id_blinfun - ?QR) = (i. ?QR ^^ i)"
      using QR_contraction d norm_QR_less_one
      by (auto intro!: invL_inf_sum)
    have summable_QR:"summable (λi. norm (?QR ^^ i))"
      using QR_contraction QR_bdd d 
      by (auto simp: a_nonneg
          intro!: summable_comparison_test'[of "λi. QR_disc^i" 0 "λn. norm ((invL (Q d) oL R d) ^^n)"]
            cSUP_upper2 power_mono order.trans[OF norm_blinfunpow_le])
    have "summable (λi. (?QR ^^ i) v s)" for v s 
      by (rule summable_comparison_test'[where g = "λi. norm (?QR ^^ i) * norm v"])
        (auto intro!: summable_QR summable_norm_cancel order.trans[OF abs_le_norm_bfun] order.trans[OF norm_blinfun] summable_mult2)
    moreover have "0  v  0  (i<n. (?QR ^^ i) v s)" for n v s
      using blinfunpow_nonneg[OF QR_nonneg[OF d]]
      by (induction n) (auto simp add: less_eq_bfun_def)
    ultimately have "0  v  0  (i. ((?QR ^^ i) v s)) " for v s
      by (auto intro!: summable_LIMSEQ LIMSEQ_le)
    hence "0  v  0  (i. ((?QR ^^ i))) v s" for v s
      using bounded_linear_apply_bfun summable_QR summable_comparison_test' 
      by (subst bounded_linear.suminf[where f = "(λi. apply_bfun (blinfun_apply i v) s)"])
        (fastforce intro: bounded_linear_compose[of "λs. apply_bfun s _"])+
    hence "0  v  0  invL (id_blinfun - ?QR) v" for v
      by (simp add: inv_eq less_eq_bfun_def)
    hence "(invL (id_blinfun - ?QR)) ((invL (Q d)) (r_decb (mk_dec_det d)))
     (invL (id_blinfun - ?QR)) ((id_blinfun - ?QR) L)"
      by (metis aux blinfun.diff_right diff_ge_0_iff_ge)
    hence "(invL (id_blinfun - ?QR) oL invL (Q d)) (r_decb (mk_dec_det d))  L"
      using invertibleL_inf_sum[OF norm_QR_less_one[OF that]] by auto
    hence "(invL (Q d oL (id_blinfun - ?QR))) (r_decb (mk_dec_det d))  L"
      using d norm_QR_less_one
      by (auto simp: invL_compose[OF Q_invertible invertibleL_inf_sum])
    hence "(invL (Q d - R d)) (r_decb (mk_dec_det d))  L"
      using Q_invertible d
      by (auto simp: blinfun_compose_diff_right blinfun_compose_assoc[symmetric])
    thus "νb (mk_stationary_det d)  L"
      by (auto simp: ν_stationary splitting[OF that, symmetric] invL_inf_sum blincomp_scaleR_right)
  qed
  hence opt_le: "νb_opt  L"
    by (metis ν_conserving_def conserving_imp_opt' ex_improving_det)
  obtain d where d: "is_arg_max (λd. invL (Q d) (r_decb (mk_dec_det d) + R d L) s) (λd. d  DD) d" for s
    using arg_max_ex_split by blast
  hence "d  DD"
    unfolding is_arg_max_linorder by auto
  have "L = invL (Q d) (r_decb (mk_dec_det d) + R d L)"
    by (subst l_fix[symmetric]) (fastforce simp: b_split_def' arg_max_SUP[OF d])
  hence "Q d L = r_decb (mk_dec_det d) + R d L"
    by (metis Q_invertible d  DD inv_app2')
  hence "(id_blinfun - l *R 𝒫1 (mk_dec_det d)) L = r_decb (mk_dec_det d)"
    using splitting[OF d  DD] by (simp add: blinfun.diff_left)
  hence "L = invL ((id_blinfun - l *R 𝒫1 (mk_dec_det d))) (r_decb (mk_dec_det d))"
    using invertibleL_inf_sum[OF norm_𝒫1_l_less] inv_app1' by metis
  hence "L = νb (mk_stationary_det d)"
    by (auto simp: invL_inf_sum ν_stationary blincomp_scaleR_right)
  hence "νb_opt = L"
    using opt_le d  DD is_markovian_def
    by (auto intro: order.antisym[OF _ νb_le_opt])
  thus ?thesis
    using b_lim l_fix the1_equality[OF b_lim(1)] by auto
qed

lemma b_split_fix[simp]: "b_split νb_opt = νb_opt"
  using b_lim b_split_tendsto_opt the_equality limI
  by (metis (mono_tags, lifting))

lemma dist_ℒb_split_opt_eps:
  assumes "eps > 0" "2 * QR_disc * dist v (b_split v) < eps * (1-QR_disc)"
  shows "dist (b_split v) νb_opt < eps / 2"
proof -
  have "(1 - QR_disc) * dist v νb_opt  dist v (b_split v)"
    using dist_triangle b_split_contraction[of v "νb_opt"]
    by (fastforce simp: algebra_simps intro: order.trans[OF _ add_left_mono[of "dist (b_split v) νb_opt"]])
  hence "dist v νb_opt  dist v (b_split v) / (1 - QR_disc)"
    using QR_contraction
    by (simp add: mult.commute pos_le_divide_eq)
  hence "2 * QR_disc * dist v νb_opt  2 * QR_disc * (dist v (b_split v) / (1 - QR_disc))"
    using b_split_contraction assms mult_le_cancel_left_pos[of "2 * QR_disc"] a_nonneg
    by (fastforce intro!: mult_left_mono[of _ _ "2 * QR_disc"])
  hence "2 * QR_disc * dist v νb_opt < eps"
    using a_nonneg QR_contraction
    by (auto simp: assms(2) pos_divide_less_eq intro: order.strict_trans1)
  hence "dist v νb_opt * QR_disc < eps / 2"
    by argo
  thus "dist (b_split v) νb_opt < eps / 2"
    using b_split_contraction[of v νb_opt] 
    by (auto simp: algebra_simps)
qed

lemma L_split_fix:
  assumes "d  DD"
  shows "L_split d (νb (mk_stationary_det d)) = νb (mk_stationary_det d)"
proof -
  let ?d = "mk_dec_det d"
  let ?p = "mk_stationary_det d"
  have "(Q d - R d) (νb ?p) = r_decb ?d"
    using L_ν_fix[of "mk_dec_det d"]
    by (simp add: L_def splitting[OF assms, symmetric] blinfun.bilinear_simps diff_eq_eq)
  thus ?thesis
    using assms
    by (auto simp: blinfun.bilinear_simps diff_eq_eq invL_cancel_iff[OF Q_invertible])
qed

lemma L_split_contraction:
  assumes "d  DD"
  shows "dist (L_split d v) (L_split d u)  QR_disc * dist v u"
proof -
  have aux: "L_split d v s - L_split d u s  QR_disc * dist v u" if lea: "(L_split d u s)  (L_split d v s)" for v s u
  proof -
    have "L_split d v s - L_split d u s = (invL (Q d) oL (R d)) (v - u) s"
      by (auto simp: blinfun.bilinear_simps)
    also have "  norm ((invL (Q d) oL (R d)) (v - u))"
      by (simp add: le_norm_bfun)
    also have "  norm ((invL (Q d) oL (R d))) * dist v u"
      by (auto simp only: dist_norm norm_blinfun)
    also have "  QR_disc * dist v u"
      using assms QR_le_QR_disc
      by (auto intro!: mult_right_mono)
    finally show ?thesis
      by auto
  qed
  have "dist (L_split d v s) (L_split d u s)  QR_disc * dist v u" for v s u
    using aux aux[of v _ u]
    by (cases "L_split d v s  L_split d u s") (auto simp: dist_real_def dist_commute)
  thus "dist (L_split d v) (L_split d u)  QR_disc * dist v u"
    by (simp add: dist_bound)
qed



lemma argmax_policy_error_bound:
  assumes am: "s. is_arg_max (λd. L (mk_dec_det d) (b v) s) (λd. d  DD) d"
  shows "(1 - l) * dist (νb (mk_stationary_det d)) (b v)  l * dist (b v) v"
proof -
  have "dist (νb (mk_stationary_det d)) (b v) = dist (L (mk_dec_det d) (νb (mk_stationary_det d))) (b v)"
    using L_ν_fix by presburger
  also have "  dist (L (mk_dec_det d) (νb (mk_stationary_det d))) (b (b v)) + dist (b (b v)) (b v)"
    using dist_triangle by blast
  also have " = dist (L (mk_dec_det d) (νb (mk_stationary_det d))) (L (mk_dec_det d) (b v)) + dist (b (b v)) (b v)"
    using b_eq_SUP_det using arg_max_SUP[OF assms, symmetric]
    by (auto simp: dist_bfun_def)
  also have "  l * dist (νb (mk_stationary_det d)) (b v) + l * dist (b v) v"
    by (meson add_mono contraction_L contraction_ℒ)
  finally show ?thesis
    by (auto simp: algebra_simps)
qed

lemma find_policy_QR_error_bound:
  assumes "eps > 0" "2 * QR_disc * dist v (b_split v) < eps * (1-QR_disc)"
  assumes am: "s. is_arg_max (λd. L_split d (b_split v) s) (λd. d  DD) d"
  shows "dist (νb (mk_stationary_det d)) νb_opt < eps"
proof -
  let ?p = "mk_stationary_det d"
  have L_eq_ℒb: "L_split d (b_split v) = b_split (b_split v)"
    by (auto simp: b_split_def' arg_max_SUP[OF am])
  have "dist (νb ?p) (b_split v) = dist (L_split d (νb ?p)) (b_split v)"
    using am
    by (auto simp: is_arg_max_linorder L_split_fix)
  also have "  dist (L_split d (νb ?p)) (b_split (b_split v)) + dist (b_split (b_split v)) (b_split v)"
    by (auto intro: dist_triangle)
  also have " = dist (L_split d (νb ?p)) (L_split d (b_split v)) + dist (b_split (b_split v)) (b_split v)"
    by (auto simp: L_eq_ℒb)
  also have "  QR_disc * dist (νb ?p) (b_split v) + QR_disc * dist (b_split v) v"
    using b_split_contraction L_split_contraction am unfolding is_arg_max_def
    by (auto intro!: add_mono)
  finally have aux: "dist (νb ?p) (b_split v)  QR_disc * dist (νb ?p) (b_split v) + QR_disc * dist (b_split v) v" .
  hence "dist (νb ?p) (b_split v) - QR_disc * dist (νb ?p) (b_split v)  QR_disc * dist (b_split v) v"
    by auto
  hence "dist (νb ?p) (b_split v) * (1 - QR_disc)  QR_disc * dist (b_split v) v"
    by argo
  hence  "2 * dist (νb ?p) (b_split v) * (1-QR_disc)  2 * (QR_disc * dist (b_split v) v)"
    using mult_left_mono 
    by auto
  hence "2 * dist (νb ?p) (b_split v) * (1 - QR_disc)  eps * (1 - QR_disc)"
    using assms
    by (auto intro!: mult_left_mono simp: dist_commute pos_divide_le_eq)
  hence "2 * dist (νb ?p) (b_split v)  eps"
    using QR_contraction mult_right_le_imp_le
    by auto
  moreover have "2 * dist (b_split v) νb_opt < eps"
    using dist_ℒb_split_opt_eps assms
    by fastforce
  ultimately show ?thesis 
    using dist_triangle[of "νb ?p" νb_opt "b_split v"]
    by auto
qed

end
context MDP_att_ℒ
begin


lemma inv_one_sub_Q':
  fixes f :: "'c :: banach L 'c"
  assumes onorm_le: "norm (id_blinfun - f) < 1"
  shows "invL f = (i. (id_blinfun - f)^^i)"
  by (metis invL_I inv_one_sub_Q assms)

lemma blinfun_le_trans: "blinfun_le X Y  blinfun_le Y Z  blinfun_le X Z"
  unfolding blinfun_le_def nonneg_blinfun_def
  by (fastforce simp: blinfun.diff_left)

lemma blinfun_leI[intro]: "(v. v  0  blinfun_apply C v  blinfun_apply D v)  blinfun_le C D"
  unfolding blinfun_le_def nonneg_blinfun_def
  by (auto simp: algebra_simps blinfun.diff_left)
  
lemma blinfun_pow_mono: "nonneg_blinfun (C :: ('c b real) L ('c b real))  blinfun_le C D  blinfun_le (C ^^ n) (D ^^ n)"
proof (induction n)
  case 0
  then show ?case by (simp add: blinfun_le_def nonneg_blinfun_def)
next
  case (Suc n)
  have *: "v. 0  v  blinfun_apply (D ^^ n) (blinfun_apply C v)  blinfun_apply (D ^^ n) (blinfun_apply D v)" 
    by (metis (no_types, opaque_lifting) Suc.prems(1) Suc.prems(2) blinfun_apply_mono blinfunpow_nonneg le_left_mono nonneg_blinfun_def nonneg_blinfun_mono)
  thus ?case
    using blinfun_apply_mono Suc
    by (intro blinfun_leI) (auto simp: blinfunpow_assoc blinfunpow_nonneg nonneg_blinfun_def simp del: blinfunpow.simps intro!: blinfun_apply_mono order.trans[OF _ *])
qed

lemma blinfun_le_iff: "blinfun_le X Y  (v  0. X v  Y v)"
  unfolding blinfun_le_def nonneg_blinfun_def
  by (auto simp: blinfun.diff_left)

text ‹An important theorem: allows to compare the rate of convergence for different splittings›
lemma norm_splitting_le:
  assumes "is_splitting_blin (id_blinfun - l *R 𝒫1 d) Q1 R1"
    and "is_splitting_blin (id_blinfun - l *R 𝒫1 d) Q2 R2"
    and "blinfun_le R2 R1"
    and "blinfun_le R1 (l *R 𝒫1 d)"
  shows "norm (invL Q2 oL R2)  norm (invL Q1 oL R1)"
proof -
  have 
    inv_Q: "invL Q = (i. (id_blinfun - Q)^^i)" "norm (id_blinfun - Q) < 1" and
    splitting_eq: "id_blinfun - Q = l *R 𝒫1 d - R" and
    nonneg_Q: "nonneg_blinfun (id_blinfun - Q)"
    if "blinfun_le R (l *R 𝒫1 d)"
      and "is_splitting_blin (id_blinfun - l *R 𝒫1 d) Q R" for Q R
  proof -
    show splitting_eq: "id_blinfun - Q = l *R 𝒫1 d - R"
      using that unfolding is_splitting_blin_def
      by (auto simp: algebra_simps)
    have R_nonneg: "nonneg_blinfun R"
      using that by blast
    show nonneg_Q:  "nonneg_blinfun (id_blinfun - Q)"
      using that by (simp add: blinfun_le_def splitting_eq)
    moreover have "blinfun_le (id_blinfun - Q) (l *R 𝒫1 d)"
      using R_nonneg by (simp add: splitting_eq blinfun_le_def)
    ultimately have "norm (id_blinfun - Q)  norm (l *R 𝒫1 d)"
      using blinfun_le_def matrix_le_norm_mono by fast
    thus "norm (id_blinfun - Q) < 1"
      using norm_𝒫1_l_less by (simp add: order.strict_trans1)
    thus "invL Q = (i. (id_blinfun - Q) ^^ i)"
      using invL_inf_sum by fastforce
  qed

  have i1: "invL Q1 = (i. (id_blinfun - Q1) ^^ i)" "norm (id_blinfun - Q1) < 1" 
    and i2: "invL Q2 = (i. (id_blinfun - Q2) ^^ i)" "norm (id_blinfun - Q2) < 1"
    using assms by (auto intro: blinfun_le_trans inv_Q[of R2 Q2] inv_Q[of R1 Q1])

  have Q1_le_Q2: "blinfun_le (id_blinfun - Q1) (id_blinfun - Q2)"
    using assms unfolding is_splitting_blin_def blinfun_le_def eq_diff_eq
    by fastforce

  have "(invL Q1) = ((i. (id_blinfun - Q1) ^^ i))"
    using i1 by auto
  also have " =  ((i. ((id_blinfun - Q1) ^^ i)))"
    using summable_inv_Q i1(2) 
    by auto
  have "blinfun_le ((i. ((id_blinfun - Q1) ^^ i))) (i. ((id_blinfun - Q2) ^^ i))"
  proof -
    have le_n: "n v. 0  v  (i<n. ((id_blinfun - Q1) ^^ i) v)  (i<n. ((id_blinfun - Q2) ^^ i) v)" 
      using nonneg_Q blinfun_pow_mono[OF _ Q1_le_Q2] assms
      by (auto intro!: sum_mono simp: blinfun_le_iff)
    hence le_n_elem: "n v. 0  v  (i<n. ((id_blinfun - Q1) ^^ i) v s)  (i<n. ((id_blinfun - Q2) ^^ i) v s)" for s
      unfolding less_eq_bfun_def
      by (simp add: sum_apply_bfun)
    have tt: "(λn. (i<n. ((id_blinfun - Q1) ^^ i) v s))  (i. ((id_blinfun - Q1) ^^ i)) v s"
              "(λn. (i<n. ((id_blinfun - Q2) ^^ i) v s))  (i. ((id_blinfun - Q2) ^^ i)) v s" for v s
      unfolding blinfun.sum_left[symmetric] sum_apply_bfun[symmetric]
      using summable_inv_Q[OF i1(2)] summable_inv_Q[OF i2(2)]
      by (fastforce intro: bfun_tendsto_apply_bfun tendsto_blinfun_apply summable_LIMSEQ)+
    show ?thesis                        
      unfolding blinfun_le_iff less_eq_bfun_def
      using le_n_elem
      by (auto simp add: less_eq_bfunI intro: Topological_Spaces.lim_mono[OF _ tt(1) tt(2)])
  qed
  also have " = (invL Q2)"
    using summable_inv_Q i2(2) i2 by auto
  finally have Q1_le_Q2: "blinfun_le (invL Q1) (invL Q2)".

  have *: "nonneg_blinfun ((invL Q1) oL R1)" "nonneg_blinfun ((invL Q2) oL R2)"
    using assms is_splitting_blin_def
    by (metis blinfun_apply_blinfun_compose nonneg_blinfun_def)+
  have "0  (id_blinfun - l *R 𝒫1 d) 1"
    using less_imp_le[OF disc_lt_one]
    by (auto simp: blinfun.diff_left less_eq_bfun_def blinfun.scaleR_left)
  hence "(invL Q1) ((id_blinfun - l *R 𝒫1 d) 1)  (invL Q2) ((id_blinfun - l *R 𝒫1 d) 1)"
    using Q1_le_Q2
    by (simp add: blinfun_le_iff)
  hence "(invL Q1) ((Q1 - R1) 1)  (invL Q2) ((Q2 - R2) 1)"
    by (metis (no_types, opaque_lifting) assms(1) assms(2) is_splitting_blin_def)
  hence "(invL Q1 oL Q1) 1 - (invL Q1 oL R1) 1  (invL Q2 oL Q2) 1 - (invL Q2 oL R2) 1"
    by (auto simp: blinfun.add_left blinfun.diff_right blinfun.diff_left)
  hence "(invL Q2 oL R2) 1  (invL Q1 oL R1) 1"
    using assms unfolding is_splitting_blin_def by auto
  moreover have "0  (invL Q2 oL R2) 1"
    using * assms(2) by (fastforce simp: less_eq_bfunI intro!: nonneg_blinfun_nonneg)
  ultimately have "norm ((invL Q2 oL R2) 1)  norm ((invL Q1 oL R1) 1)"
    by (auto simp: less_eq_bfun_def norm_bfun_def' intro!: abs_le_norm_bfun abs_ge_self cSUP_mono bdd_above.I2 intro: order.trans)
  thus "norm ((invL Q2 oL R2))  norm ((invL Q1 oL R1))"
    by (simp add: * norm_nonneg_blinfun_one)
qed

end


end