Theory Affine_Arithmetic_Misc

theory Affine_Arithmetic_Misc
  imports "HOL-ODE-Numerics.ODE_Numerics"
begin

section ‹Branch-And-Bound Arithmetic›

primrec prove_nonneg::"(nat * nat * string) list  nat  nat  slp  real aform list list  bool" where
  "prove_nonneg prnt 0 p slp X = (let _ = if prnt  [] then print (STR ''# depth limit exceeded⏎'') else () in False)"
| "prove_nonneg prnt (Suc i) p slp XXS =
    (case XXS of []  True | (X#XS) 
      let RS = approx_slp_outer p 1 slp X
      in if RSNone  Inf_aform' p (hd (the RS))  0
        then
          let _ = if prnt  [] then print (STR ''# Success⏎'') else ();
             _ = if prnt  [] then print (String.implode ((shows ''# '' o shows_box_of_aforms_hr X) ''⏎'')) else ();
             _ = fold (λ(a, b, c) _. print (String.implode (shows_segments_of_aform a b X c ''⏎''))) prnt ()
          in prove_nonneg prnt i p slp XS
        else let _ = if prnt  [] then print (STR ''# Split⏎'') else () in case split_aforms_largest_uncond X of (a, b) 
          prove_nonneg prnt i p slp (a#b#XS))"

lemma prove_nonneg_simps[simp]:
  "prove_nonneg prnt 0 p slp X = False"
  "prove_nonneg prnt (Suc i) p slp XXS =
    (case XXS of []  True | (X#XS) 
      let RS = approx_slp_outer p 1 slp X
      in if RSNone  Inf_aform' p (hd (the RS))  0
        then prove_nonneg prnt i p slp XS
        else case split_aforms_largest_uncond X of (a, b)  prove_nonneg prnt i p slp (a#b#XS))"
  by (auto simp: Let_def split: if_splits option.splits list.splits)

lemmas [simp del] = prove_nonneg.simps

lemma split_aforms_lemma:
  fixes xs::"real list"
  assumes "split_aforms XS i = (YS, ZS)"
  assumes "xs  Joints XS"
  shows "xs  Joints YS  Joints ZS"
  using set_rev_mp[OF assms(2) Joints_map_split_aform[of XS i]] assms(1)
  by (auto simp: split_aforms_def o_def)

lemma prove_nonneg_empty[simp]: "prove_nonneg prnt (Suc i) p slp []"
  by simp

lemma prove_nonneg_fuel_mono:
  "prove_nonneg prnt (Suc i) p (slp_of_fas [fa]) YSS"
  if "prove_nonneg prnt i p (slp_of_fas [fa]) YSS"
  using that
proof (induction i arbitrary: YSS)
  case 0
  then show ?case by simp
next
  case (Suc i)
  from Suc.prems show ?case
    supply [simp del] = prove_nonneg_simps
    apply (subst prove_nonneg_simps)
    apply (auto simp: Let_def split: if_splits option.splits list.splits)
    subgoal apply (rule Suc.IH)
      apply (subst (asm) prove_nonneg_simps)
      by (auto simp: Let_def split: if_splits option.splits list.splits)
    subgoal apply (rule Suc.IH)
      apply (subst (asm) prove_nonneg.simps)
      by (auto simp: Let_def split: if_splits option.splits list.splits)
    subgoal apply (rule Suc.IH)
      apply (subst (asm) prove_nonneg.simps)
      by (auto simp: Let_def split: if_splits option.splits list.splits)
    done
qed

lemma prove_nonneg_mono:
  "prove_nonneg prnt i p (slp_of_fas [fa]) YSS" if "prove_nonneg prnt i p (slp_of_fas [fa]) (YS # YSS)"
  using that
proof (induction i arbitrary: YS YSS)
  case 0
  then show ?case by auto
next
  case (Suc i)
  from Suc.prems show ?case
    supply [simp del] = prove_nonneg_simps
    apply (subst (asm) prove_nonneg_simps)
    apply (auto simp: Let_def split: if_splits option.splits list.splits)
    subgoal by (rule prove_nonneg_fuel_mono)
    subgoal for x y apply (rule prove_nonneg_fuel_mono)
      apply (rule Suc.IH[of y])
      by (rule Suc.IH[of x])
    subgoal for x y apply (rule prove_nonneg_fuel_mono)
      apply (rule Suc.IH[of y])
      by (rule Suc.IH[of x])
    done
qed

lemma prove_nonneg:
  assumes "prove_nonneg prnt i p (slp_of_fas [fa]) XSS"
  shows "XS  set XSS. xs  Joints XS. interpret_floatarith fa xs  0"
  using assms
proof (induction i arbitrary: XSS)
  case 0
  then show ?case
    by (auto )
next
  case (Suc i)
  show ?case
  proof (cases XSS)
    case Nil then show ?thesis by auto
  next
    case (Cons YS YSS)
    show ?thesis
      unfolding Cons
      apply auto
      subgoal for xs using Suc.prems
        apply (auto simp: Cons Let_def split: if_splits option.splits)
        subgoal for ys
          apply (drule approx_slp_outer_plain)
             apply (rule refl)
            apply force
           apply assumption
          apply simp
          apply (frule Joints_imp_length_eq[where XS=ys])
          apply (auto simp: Suc_length_conv)
          by (smt Inf_aform'_Affine_le)
        subgoal
          apply (simp add: split_aforms_largest_uncond_def split: prod.splits)
          apply (drule Suc.IH)
          apply (drule split_aforms_lemma, assumption)
          by auto
        subgoal
          apply (simp add: split_aforms_largest_uncond_def split: prod.splits)
          apply (drule Suc.IH)
          apply (drule split_aforms_lemma, assumption)
          by auto
        done
      subgoal for XS xs using Suc.prems
        apply (auto simp: Cons Let_def split: if_splits option.splits)
        subgoal for ys by (rule Suc.IH[rule_format], assumption, assumption, assumption)
        subgoal for ys
          apply (drule prove_nonneg_mono)
          apply (drule prove_nonneg_mono)
          by (rule Suc.IH[rule_format], assumption, assumption, assumption)
        subgoal for ys
          apply (drule prove_nonneg_mono)
          apply (drule prove_nonneg_mono)
          by (rule Suc.IH[rule_format], assumption, assumption, assumption)
        done
      done
  qed
qed

end