Theory SLA_Criterion

(*Certified Infinite Descent Criteria in Isabelle/HOL *)
(*Authors: Jamie Wright, Liron Cohen, Reuben Rowe and Andrei Popescu*)

subsubsection "Slope-language Criterion"
theory SLA_Criterion
  imports "../Sloped_Graphs"
          "../Buchi_Preliminaries"
begin

context Sloped_Graph 
begin

abbreviation q0 where "q0 ≡ None"
fun RR':: "'node × 'node ⇒ 'pos × 'pos × slope ⇒ bool"  where "RR' (nd,nd') = (λ(ps, ps', s). RR (nd,ps) (nd',ps') s)"


fun ndOf where "ndOf ((nd,ps),(nd',ps'),s) = nd"
fun nd'Of where "nd'Of ((nd,ps),(nd',ps'),s) = nd'"

term "{Some nd'| nd. edge nd nd'}"
(*PATH AUTOMATON*)
fun Δsl :: "('pos × 'pos × slope ⇒ bool) ⇒ 'node option ⇒ 'node option set" where
  "Δsl t (Some nd) = {Some nd'| nd'. {nd, nd'} ⊆ Node ∧ edge nd nd' ∧ t = RR'(nd,nd') }"|
  "Δsl t q0 = {Some nd'| nd nd'. {nd, nd'} ⊆ Node ∧ edge nd nd' ∧ t = RR'(nd,nd')}"

lemma Δsl_intro_Some:
  assumes "edge s s'" 
    and "{s, s'} ⊆ Node"
    and "tr = RR'(s,s')"
  shows "Some s' ∈ Δsl tr (Some s)"
  using assms by auto

lemma Δsl_intro_q0:
  assumes  "edge s s'" 
    and "{s, s'} ⊆ Node"
    and "tr = RR'(s,s')"
  shows "Some s' ∈ Δsl tr q0"
  using assms by auto

lemma Δsl_elim:
  assumes "x ∈ Δsl t z"
  obtains nd nd' where
    "x = Some nd'" "nd ∈ Node" "nd' ∈ Node" "edge nd nd'" "t = RR' (nd, nd')"
    "z = q0 ∨ the z = nd"
  using assms by (cases z, auto)

lemma Δsl_q0_not_q0[simp]: "¬ (q0 ∈ Δsl x q0)" by auto

lemma Δsl_some:"r' ∈ Δsl x r ⟹ ∃y. r' = Some y" by(cases r, auto) 

(*Sanity check with the Δsl in the paper, 
  the sets of transitions as before*)
lemma "Δsl l s = 
       {Some v'| v v'. s = q0 ∧ (edge v v') ∧ {v, v'} ⊆ Node ∧ l = RR'(v,v')} ∪
       {Some v'| v'. s ≠ q0 ∧ edge (the s) v' ∧ {(the s), v'} ⊆ Node ∧ l = RR'((the s),v')}"
  unfolding Δsl.simps by(cases s, auto)

definition PautR :: "('pos × 'pos × slope ⇒ bool, 'node option) nba" where
  "PautR = nba 
    {RR' (nd, nd')| nd nd'. edge nd nd'}
    {q0}
    Δsl
    (λs. the s ∈ Node)"

lemmas PautR_defs = PautR_def Δsl.simps
lemma PautR_alpha[simp]:"nba.alphabet PautR = {RR' (nd, nd')| nd nd'. edge nd nd'}" unfolding PautR_def by auto
lemma PautR_accept[simp]:"nba.accepting PautR = (λs. the s ∈ Node)" unfolding PautR_def by auto
lemma PautR_init[simp]: "nba.initial PautR = {q0}" unfolding PautR_def by auto
lemma PautR_initp[intro]:"p ∈ nba.initial PautR ⟷ p = q0" by auto
lemma PautR_trans[simp]:"nba.transition PautR a b = Δsl a b" unfolding PautR_def by auto

lemmas PautR_trans' = PautR_trans Δsl.simps
lemmas PautR_run_def = nba.run_alt_def_snth PautR_trans PautR_alpha nba.target_alt_def  nba.states_alt_def


lemma PautR_lang:"NBA.language PautR = {Ri. ∃nds. ipath nds ∧ (∀i. Ri !! i = RR' (nds !! i, nds !! Suc i))}" 
proof(safe)
  fix x 
  assume "x ∈ NBA.language PautR"
  then obtain r where run:"NBA.run PautR (x ||| r) None"  and accept:"infs (λs. the s ∈ Node) r" apply-by(erule nba.language_elim, auto)


  (*We leave q0 immediately and never transition back during the run*)
  have q0'_notReachable:"⋀k. r !! k ≠ q0"
      subgoal for k apply(induct k)
        subgoal using runE_0[OF run] apply-by(clarsimp)
        subgoal for k using runE_Suc[OF run, of k] by auto . .

  have x_prop:"⋀k. k>0 ⟹ ∃nd nd'. x !! k = RR' (nd, nd') ∧ edge nd nd' ∧ the(r!!k) = nd'  ∧ the(r!!(k-1)) = nd" 
    subgoal for k  
      using runE_Suc[OF run, of k, unfolded PautR_trans]
      apply-apply(drule runE_Suc'[OF run, of k, unfolded PautR_trans])
      apply(erule Δsl_elim)+
      using q0'_notReachable[of] by auto . 


  have q0'_notLast:"⋀k. k>0 ⟹ last (stake k r) ≠ q0" subgoal for k
     using q0'_notReachable[of "k-1"] last_conv_nth[of "stake k r"] by auto .
  
  hence i_eq_iff:"⋀i. (if i = 0 then None else last (stake i r)) = None ⟷ i = 0" by simp

  obtain s where s_edge:"edge s (the (r !! 0))" and s_node:"s ∈Node" and s_x:"x !! 0 = RR'(s, the (r !! 0))"
    using runE_0[OF run] by auto

  show "∃nds. local.ipath nds ∧ (∀i. x !! i = RR' (nds !! i, nds !! Suc i))"
  proof(rule exI[of _ "s ## smap the r"], unfold ipath_def PautR_initp PautR_accept, safe)
    fix i

    have "alw (holdsS Node) (smap the r)" unfolding alw_holdsS_iff_snth apply-apply(rule allI)
      subgoal for i apply(induct i)
        subgoal using runE_0[OF run] by auto 
        subgoal for i using runE_Suc[OF run, of i, unfolded PautR_trans] apply-by(erule Δsl_elim, auto) . . 

    thus "alw (holdsS Node) (s ## smap the r)"
      using s_node unfolding alw_holdsS_iff_snth by (metis not0_implies_Suc snth.simps(1) snth_Stream stream.sel(1))

 

    have alwEdge:"alw (holds2 edge) (smap the r)" unfolding alw_holds2_iff_snth apply-apply(rule allI)
      subgoal for i using runE_Suc[OF run, of i, unfolded PautR_trans] 
                          runE_Suc[OF run, of "Suc i", unfolded PautR_trans]
          apply-apply(erule Δsl_elim)+
          using q0'_notReachable by auto .
          
    thus "alw (holds2 edge) (s ## smap the r)"
      using s_edge unfolding alw_holds2_iff_snth apply-apply(rule allI)
      subgoal for i apply(cases i, simp)
        subgoal for n by (erule allE[of _ n], auto) . . 

    show "x !! i = RR' ((s ## smap the r) !! i, (s ## smap the r) !! Suc i)" 
      using s_x x_prop[of i] by(cases i, auto)
  qed
next
  fix x nds
  assume ipath:"ipath nds" and
         Rel:"∀i. x !! i = RR' (nds !! i, nds !! Suc i)"
  obtain nd1 nd2 where nds:"nds = nd1 ## nd2" by (cases nds)
  have Rel':"⋀i. x !! i = RR' (nds !! i, nds !! Suc i) ∧ edge (nds !! i) (nds !! Suc i)" 
    using Rel RR'.simps ipath unfolding alw_holds2_iff_snth ipath_def by auto

  have nds_in_Node:"sset nds ⊆ Node" by (metis ipath sset_ipath)
  hence stl_nds_in_Node:"sset (stl nds) ⊆ Node" using nds by auto

  show "x ∈ NBA.language PautR"
  proof(rule nba.language[of None PautR x "smap Some (stl nds)"])

    show "q0 ∈ nba.initial PautR" by auto

    show "NBA.run PautR (x ||| smap Some (stl nds)) q0"
    proof(unfold PautR_run_def fst_nth_zip snd_nth_zip, intro allI conjI, safe)
      fix k
      show " ∃nd nd'. x !! k = RR' (nd, nd') ∧ edge nd nd'" using Rel' by auto
      show "smap Some (stl nds) !! k ∈ Δsl (x !! k) (last (None # map snd (stake k (x ||| smap Some (stl nds)))))"
      proof(induct k)
        case 0
        have last:"(last (None # map snd (stake 0 (x ||| smap Some (stl nds))))) = None" by auto
        show ?case unfolding snth_smap last
          apply(rule Δsl_intro_q0[of "shd nds" ])
          subgoal using Rel'[of 0] by auto
          subgoal using nds_in_Node stl_nds_in_Node by auto
          subgoal using Rel'[of 0] by auto .
     next
        case (Suc k)
        then show ?case unfolding last_stake_szip snth_smap
          apply-apply(erule Δsl_elim,rule Δsl_intro_Some) 
          using Rel'[of "Suc k"]  ipath ipath_iff_snth ipath_stl nds_in_Node by auto
      qed
    qed


    have ruleInfs:"infs (nba.accepting PautR) (smap Some (stl nds)) ⟹infs (nba.accepting PautR) (q0 ## smap Some (stl nds))"
      using alw_ev_shift[of _ "[None]"] by auto

    show "infs (nba.accepting PautR) (q0 ## smap Some (stl nds))"
      apply(rule ruleInfs,rule infs_all)
      using stl_nds_in_Node by auto
  qed
qed

lemma PautR_lang_in:"x ∈ NBA.language PautR ⟷ (∃nds. ipath nds ∧ (∀i. x !! i = RR' (nds !! i, nds !! Suc i)))"
  unfolding PautR_lang by auto



(*What the states should be, per the paper:*)
definition Q'sl::"('pos × slope) set" where 
"Q'sl ≡ {(p, s)| p s. p ∈ (⋃v∈Node. PosOf v)}"
abbreviation "Σ ≡ {RR' (nd, nd')| nd nd'. edge nd nd'}"
(*TRACE AUTO*)
fun Δsl' :: "('pos × 'pos × slope ⇒ bool) ⇒ ('pos × slope) option ⇒ ('pos × slope) option set" where
  "Δsl' R' (Some (p,s)) = {Some (p',s')| p' s'. (p,s) ∈ Q'sl ∧ R' ∈ Σ ∧ R' (p, p', s')}"|
  "Δsl' R' q0 = (if R' ∈ Σ then {q0} ∪ {Some (p',s')| p' s'. (p',s') ∈ Q'sl} else {})"

(*intros*)
lemma Δsl'_intro_Some:
  assumes "(p, s) ∈ Q'sl" "R' ∈ Σ" "R' (p, p', s')"
  shows "Some (p', s') ∈ Δsl' R' (Some (p, s))"
  using assms by auto

lemma Δsl'_intro_q0:
  assumes "R' ∈ Σ" "(p', s') ∈ Q'sl"
  shows "Some (p', s') ∈ Δsl' R' q0"
  using assms by auto

lemma Δsl'_q0_included:
  assumes "R' ∈ Σ"
  shows "q0 ∈ Δsl' R' q0"
  using assms by auto

lemma Δsl'_intro:
  assumes "ns ∈ Σ"
  assumes "rk ≠ q0 ⟹ (∃ p' s'. rk' = Some (p', s') ∧ the rk ∈ Q'sl ∧ ns (fst(the rk), p', s'))"
  assumes "rk = q0 ⟹ (rk' = q0 ∨ (∃p' s'. rk' = Some (p', s') ∧ (p', s') ∈ Q'sl))"
  shows "rk' ∈ Δsl' ns rk"
  using assms apply (cases rk) by force+



(*elims*)
lemma Δsl'_elim:
  assumes "x ∈ Δsl' R' z"
  obtains (SomeCase) p s p' s' where 
    "z = Some (p, s)" "x = Some (p', s')" "(p, s) ∈ Q'sl" "R' ∈ Σ" "R' (p, p', s')"
  | (q0Case) p' s' where 
    "z = q0" "R' ∈ Σ" "(p', s') ∈ Q'sl" "x = Some (p', s')"
  | (q0Self) "z = q0" "R' ∈ Σ" "x = q0"
  using assms by (cases z,(auto split: if_splits)+)

(*If we transition from a state which is not q0, then we can never return*)
lemma q0_notReachable:"q ≠ q0 ⟹ v' ∈ Δsl' v q ⟹ v' ≠ q0" by(cases v', cases q, auto)





definition Fsl::"('pos × slope) option ⇒ bool" where 
"Fsl ≡ λps. ∃p. ps = Some (p, Decr) ∧ (p, Decr) ∈ Q'sl"


definition TautR :: "('pos × 'pos × slope ⇒ bool, ('pos × slope) option) nba" where
  "TautR = nba 
    {RR' (nd, nd')| nd nd'. edge nd nd'}
    {q0}
    Δsl'
    Fsl"

lemma RR_reduce:"(∀n≥Suc 0. RR (r1 !! n, Ps !! n) (stl r1 !! n, stl Ps !! n) (stl Ss !! n)) ⟷
       (∀n. RR (stl r1 !! n, stl Ps !! n) (stl(stl r1) !! n, stl(stl Ps) !! n) (stl(stl Ss) !! n))"
  apply standard
subgoal by auto
  subgoal apply(rule allI)
    subgoal for n by(cases n, auto) . .


(*lemma kk:"⋀k. k>0 ⟹ r !! (k - Suc 0) = last (stake k r)" subgoal for k using last_conv_nth[of "stake k r"] by auto .
*)

lemma TautR_alpha[simp]:"nba.alphabet TautR = {RR' (nd, nd')| nd nd'. edge nd nd'}" unfolding TautR_def by auto
lemma TautR_accept[simp]:"nba.accepting TautR = (λps. ∃p. ps = Some (p, Decr) ∧ (p, Decr) ∈ Q'sl)" unfolding TautR_def Fsl_def by auto
lemma TautR_init[simp]: "nba.initial TautR = {q0}" unfolding TautR_def by auto
lemma TautR_initp[intro]:"p ∈ nba.initial TautR ⟷ p = q0" by auto
lemma TautR_trans[simp]:"nba.transition TautR a b = Δsl' a b" unfolding TautR_def by auto

lemmas run_def' = nba.run_alt_def_snth fst_nth_zip snd_nth_zip TautR_trans TautR_alpha nba.target_alt_def  nba.states_alt_def


(**converting a stream of nodes to it's Ri sequence**)
fun Rst where "Rst nds = smap (λi. RR' (nds !! i, nds !! Suc i)) nats"

lemma stl_shift:"(stl nds !! i,stl (stl nds) !! i) = (nds !! Suc i,(stl nds) !! Suc i)" by auto

lemma smap_shifted_eq:
        "smap (λi. RR' (nds !! i,stl nds !! i)) (fromN (Suc 0)) = 
         smap (λi. RR' (stl nds !! i,stl (stl nds) !! i)) nats"
  unfolding stl_shift
  apply(rule ssubst[of "smap (λi. RR' (nds !! Suc i, stl nds !! Suc i)) nats" 
                       "smap (λj (ps, ps', y). RR (stl nds !! (j - Suc 0), ps) (stl (stl nds) !! (j - Suc 0), ps') y) (fromN (Suc 0))"])
  subgoal using stream_smap_fromN[of "smap (λi. RR' (stl nds !! i, stl (stl nds) !! i)) nats" "Suc 0"] by auto
  apply(rule stream.map_cong0)
  subgoal for z using stl_Suc[of z nds] stl_Suc[of "z" "stl nds"] by force .

lemma Rst_correct:"x = Rst nds ⟷ (∀i. x !! i = RR' (nds !! i, nds !! Suc i))"
  apply(safe)
  subgoal for i by(cases i, auto)
  subgoal 
    apply (coinduction arbitrary: x nds, intro conjI)
    subgoal by (erule allE[of _ 0], auto)
    subgoal for x_hd x_tl nd_hd nd_tl x nds 
      apply(rule exI2[of _ x_tl "stl nds"], safe)
      subgoal using smap_shifted_eq by auto 
      subgoal for i by(erule allE[of _ "Suc i"], auto) . . . 


lemma Rst_r:"⋀k. Rst nds !! k = RR' (nds !! k, nds !! Suc k)"using Rst_correct by auto

(***)
(*For any ipath nds, we have that for i∈N RR(nds!i, nds!Suc i) ∈ Lang TautR iff nds is descending *)

lemma list_swap:"k>0 ⟹ (p ## smap (λr. fst (the r)) r) !! k = fst (the (r !! (k-1))) " by (cases k, auto)
lemma TautR_lang_in:"ipath nds ⟹ Rst nds ∈ NBA.language TautR ⟷ (∃Ps. descentIpath nds Ps)"
proof(safe)
  assume ipath:"ipath nds"

  have k_edge:"⋀k. edge (nds !! k) (stl nds !! k)" using ipath unfolding ipath_def alw_holds2_iff_snth by auto

  show "Rst nds ∈ NBA.language TautR ⟹ ∃Ps. descentIpath nds Ps"

  proof -
    assume "Rst nds ∈ NBA.language TautR"
    then obtain r where run:"NBA.run TautR (Rst nds ||| r) None"  and accept:"infs (λps. ∃p. ps = Some (p, Decr) ∧ (p, Decr) ∈ Q'sl) r" apply-by(erule nba.language_elim, auto)

    hence run':"⋀k. Rst nds !! k = RR' (nds !! k, nds !! Suc k) ∧ edge (nds !! k) (nds !! Suc k) ∧
        r !! k ∈ Δsl' (Rst nds !! k) (if k = 0 then None else last (stake k r))"
      using k_edge unfolding PautR_run_def by auto


  (*If we reach a point k where Decr occurs, then no future state j with j≥k can be q0*)
  have q0'_Decr:"⋀p k j. 0<k ⟹ r !! k = Some (p, Decr) ⟹ k ≤ j ⟹ r !! j ≠ q0"
    subgoal for p k j proof(induct "j - k" arbitrary: j)
      case 0
      then show ?case by auto
    next
      case (Suc xa)
      hence Suc':"⋀ j. 0 < k ⟹ xa = j - k ⟹ k ≤ j ⟹ r !! j ≠ q0" by auto
      obtain n where n:"j = Suc n" "xa = n - k" "k ≤ n" using Suc by(cases j,auto)
      show ?case 
        using Suc'[of n,OF Suc(3) n(2,3)] unfolding n
        using runE_Suc[OF run, of n] q0_notReachable[of "r !! n" "r !! Suc n"] by auto
    qed .

    have accept_from_notNone:"⋀n. ∃k≥n. ∃p. r !! k = Some (p, Decr) ∧ Some (p, Decr) ∈ Δsl' (Rst nds !! k) (last (stake k r)) ∧ (last (stake k r)) ≠ None"
      subgoal for n
      using accept unfolding infs_snth
      apply-apply(erule allE[of _ "Suc n"], safe)
      subgoal for k p       using accept unfolding infs_snth
        apply-apply(erule allE[of _ "Suc k"], safe)
        subgoal for k' p' apply(intro exI[of _ k'] conjI exI[of _ p'])
          subgoal by auto
          subgoal by auto
          subgoal using run'[of k'] by auto
          subgoal using q0'_Decr[of k p "k'-1"] last_stake_i[of k' r] by auto . . . .


  obtain Ps where Ps:"Ps = fst (the (shd r)) ## smap (λr. fst (the r)) r" by auto

  have PsK:"⋀k. k>0 ⟹ Ps !! k = fst(the (r !!(k - Suc 0)))" subgoal for k unfolding Ps by(drule list_swap[of k "(fst (the (shd r)))" r], simp) .

  show "∃Ps. descentIpath nds Ps"
  apply(rule exI[of _ Ps], unfold descentIpath_iff_snth2, intro conjI)
  subgoal using accept_from_notNone[of "Suc 0"] apply safe
  subgoal for k p' a b apply(rule exI[of _ k], intro allI impI)
  subgoal for j proof(induct "j - k" arbitrary: j)
    case 0
    then have k:"k>0"  by auto
    hence last:"(last (stake k r)) = (r !! (k - 1))" using last_stake_i by auto
    also have j:"j>0" using 0 by auto
    show ?case using 0 unfolding last apply-apply(erule Δsl'_elim)
      using PsK[OF j] PsK[of "Suc j"] by auto
  next
    case (Suc x)
    hence jk:"j ≠ 0" "k ≠ 0" "j > 0" "k > 0" "0 < Suc j" by auto
    then obtain n where j:"j = Suc n" by (cases j, auto)
    then have n_gr:"n > 0" "k ≤ n" using Suc by auto
    also have k_le:"k ≤ j - 1" using n_gr j by auto
    have nth_stake_szip:"r !! j ∈ Δsl' (Rst nds !! j) (r !! (j-1))" using run'[of "j", unfolded last_stake_i[OF jk(3)]] jk by auto
    obtain a' b' where r_j_min:"(r !! (j-1)) = Some(a',b')" using q0'_Decr[of k p' "j-1", OF jk(4) Suc(4) k_le]  by auto
    show ?case
      subgoal using nth_stake_szip apply-apply(erule Δsl'_elim)
        subgoal for p s p' s' unfolding Rst_r PsK[OF jk(3)] PsK[OF jk(5)] by (cases s', auto)
        subgoal using r_j_min by auto
        subgoal using r_j_min by auto . .  
  qed . .
  apply(rule allI)
  subgoal for i using accept_from_notNone[of "Suc(Suc i)"] apply clarify
    subgoal for k p apply(rule exI[of _ "k"], intro conjI)
      subgoal by auto
      using Suc_diff_1[of k] last_stake_i[of k r] PsK[of k] PsK[of "k-1"]
      unfolding Rst_r Ps apply-apply(erule Δsl'_elim)
      by (auto,metis fst_eqD option.sel)  . . 
  qed
(*Converse*)
  fix Ps  

  {assume iDPath:"descentIpath nds Ps"
   have ev:"ev (alw (holds2 (λ(nd, P) (nd', P'). RR (nd, P) (nd', P') Main ∨ RR (nd, P) (nd', P') Decr))) (nds ||| Ps)"and
      alw:"alw (ev (holds2 (λ(nd, P) (nd', P'). RR (nd, P) (nd', P') Decr))) (nds||| Ps)"
     using iDPath[unfolded descentIpath_def2] by auto

   also have wf:"wfLabS nds Ps" using descentIpath_wfLabS[OF iDPath] by auto

   have hh:"⋀x y z i. (stl x!!i, stl y!!i, stl z!!i) ∈sset (x ||| y ||| z)" 
      by (metis snth_sset snth_szip stream.set_sel(2) szip.sel(2))
   define Fsl where "Fsl = (λx' Ps' i. (if RR (x' !! i, Ps' !! i) (stl x' !! i, stl Ps' !! i) Decr then Decr else Main))"
   define Ss where "Ss = (λx Ps. Main ## fToStream (Fsl x Ps))"
   note Ss_defs = Ss_def Fsl_def fToStream_def

   have Ss_i:"⋀k m. m < Suc k ⟹ (Ss (sdrop (Suc m) nds) (sdrop (Suc m) Ps) !! (Suc k - m)) = Fsl nds Ps (Suc k)" using Suc_diff_le unfolding Ss_defs by auto

   obtain m where m:"(⋀n. n≥m ⟹ (holds2 (λ(nd, P) (nd', P'). RR (nd, P) (nd', P') Main ∨ RR (nd, P) (nd', P') Decr)) (sdrop n (nds ||| Ps)))"
     using ev  unfolding ev_alw_iff_sdrop by auto

   have "⋀n. n≥m ⟹ (Rst nds !! n) (Ps !! n, Ps !! Suc n, Main) ∨ (Rst nds !! n) (Ps !! n, Ps !! Suc n, Decr)"
     subgoal for n by(drule m[of n], simp) .

  obtain i where i:"∀j≥i. Ps !! j ∈ PosOf (nds !! j)" using wf unfolding wfLabS_iff_snth by auto

  define m' where "m' = i + m" 
  hence m':"(⋀n. n≥m' ⟶ Ps !! n ∈ PosOf (nds !! n) ∧ ((Rst nds !! n) (Ps !! n, Ps !! Suc n, Main) ∨ (Rst nds !! n) (Ps !! n, Ps !! Suc n, Decr)))"
    using i m by auto

  have alw_dropm:"alw (ev (holds2 (λ(nd, P) (nd', P'). RR (nd, P) (nd', P') Decr))) (sdrop (Suc m') (nds ||| Ps))"
    using alw unfolding alw_ev_sdrop by auto


  define r where "r = replicate m' q0 @- smap Some ((sdrop (Suc m') Ps) ||| (Ss (sdrop (Suc m') nds) (sdrop (Suc m') Ps)))"

  have x_node':"⋀i. nds !! i ∈ Node" using ipath unfolding ipath_def alw_holdsS_iff_snth by auto

  have r_eq_q0':"⋀n. Suc n ≤ m' ⟷ r!!n = q0" 
    apply standard unfolding r_def
    subgoal using replicate_within_i by auto
    subgoal for n apply(rule ccontr, unfold not_le replicate_beyond_i) using x_node'[of "n"]  by auto .


  have r_neq_q0':"⋀n. Suc n > m' ⟷ r!!n = Some (Ps !! Suc n, Ss (sdrop (Suc m') nds) (sdrop (Suc m') Ps) !! (n-m'))" 
    apply standard
    subgoal unfolding r_def using replicate_beyond_i by auto 
    subgoal for n using r_eq_q0'[of n] by auto .


  have Rst_all:"⋀k. (Rst nds !!k) ∈ Σ" using k_edge unfolding Rst_r by auto

  have Psk_node:"⋀k. Ps !! k ∈ PosOf (nds !! k) ⟹ ∃x∈Node. Ps !! k ∈ PosOf x"
    using x_node' by auto
  have m'_inQ'sl:"⋀k x. k≥ m' ⟹ (Ps !! k, x) ∈ Q'sl"
    unfolding Q'sl_def using Psk_node  m' by auto


  have m_eq:"⋀k m. Suc k ≤ m ⟹ m < Suc (Suc k) ⟹ m = Suc k" by auto
  have Psn_gr:"⋀n. Suc n > m' ⟹ Ps !! (Suc n) = fst (the (r !! n))" using r_neq_q0' by auto
  have Ssn_gr:"⋀n. Suc n > m' ⟹ snd (the (r !! n)) = Ss (sdrop (Suc m') nds) (sdrop (Suc m') Ps) !! (n-m')" using r_neq_q0' by auto


  show"Rst nds ∈ NBA.language TautR" 
  proof(rule nba.language[of q0 TautR  _ r], unfold TautR_accept TautR_initp, safe)
    show "NBA.run TautR (Rst nds ||| r) q0" 
    proof(unfold run_def', intro allI conjI) 
      fix k 
      show "Rst nds !! k ∈ Σ" using Rst_all by auto
  
      show "r !! k ∈ Δsl' (Rst nds !! k) (last (None # map snd (stake k (Rst nds ||| r))))"
      proof(induct k)
        case 0
        have l:"(last (None # map snd (stake 0 (Rst nds ||| r))))  = None" by auto
        show ?case unfolding l 
          apply(cases m')
          subgoal apply(rule ssubst[of "r !!0" "Some (Ps !! (Suc 0), Ss (sdrop (Suc m') nds) (sdrop (Suc m') Ps) !! 0)"])
            subgoal  using r_neq_q0'[of 0] by auto
            subgoal apply(rule Δsl'_intro_q0)
              subgoal using Rst_all[of 0] by auto
              subgoal using m'_inQ'sl[of "Suc 0"] by auto . . 
          subgoal apply(rule ssubst[of "r !!0" None]) 
            subgoal using r_eq_q0'[of 0] by auto
            apply(rule Δsl'_q0_included) using Rst_all[of 0] by auto .
      next
        case (Suc k)
        then show ?case unfolding last_stake_szip apply-apply(erule Δsl'_elim)
         (*Δsl' 3*)       
          subgoal for p s p' s'  apply(rule Δsl'_intro)
            subgoal using Rst_all[of "Suc k"] by auto
            subgoal apply(intro exI2[of _ "Ps !! Suc (Suc k)" "Ss (sdrop (Suc m') nds) (sdrop (Suc m') Ps) !! (Suc k - m')"] conjI)
              subgoal using r_eq_q0'[of k] r_neq_q0'[of "Suc k"] by auto
              subgoal using Psn_gr[of k] r_eq_q0'[of k] m'_inQ'sl[of "Suc k"] by auto
              subgoal using  m'[of "Suc k"] r_eq_q0'[of k] Ss_i Psn_gr unfolding Fsl_def by auto .
            subgoal by auto .
          (*Δsl' 2*)   
          subgoal for p s apply(rule Δsl'_intro)
            subgoal using Rst_all[of "Suc k"] by auto
            subgoal apply(rule exI[of _ "Ps !! Suc (Suc k)"], intro exI[of _ "Ss (sdrop (Suc m') nds) (sdrop (Suc m') Ps) !! (Suc k - m')"] conjI)
              subgoal using r_eq_q0'[of k] r_neq_q0'[of "Suc k"] by auto
              subgoal by auto
              subgoal using  m'[of "Suc k"] r_eq_q0'[of k] Ss_i Psn_gr unfolding Fsl_def by auto .
            subgoal by auto .
          (*Δsl' 1*)   
          subgoal apply(rule Δsl'_intro)
            subgoal using Rst_all[of "Suc k"] by auto
            subgoal by auto
            subgoal using le_less_linear[of "Suc (Suc k)" m'] apply-apply(erule disjE)
              subgoal using r_eq_q0'[of "Suc k"] by auto 
              subgoal using r_neq_q0'[of "Suc k"] m'_inQ'sl[of "Suc (Suc k)"] by auto . . .
      qed
    qed

    show "infs (λps. ∃p. ps = Some (p, Decr) ∧ (p, Decr) ∈ Q'sl) r"
      unfolding r_def alw_ev_shift infs_snth apply(clarify)
      subgoal for n using alw_dropm unfolding alw_ev_holds2_iff_snth
        apply-apply(erule allE[of _ "n + i"], clarify)
        subgoal for j x y xa ya apply(intro exI[of _ "Suc j"] conjI)
          subgoal by auto
          subgoal apply(intro exI[of _ ya] conjI)
            subgoal unfolding Ss_defs by auto
            subgoal using i RR_PosOfD' unfolding Q'sl_def by fastforce . . . .
  qed}
qed

(*Trivial auxillary results required*)
lemma alpha_subseq_PTautR: "nba.alphabet PautR ⊆ nba.alphabet TautR" by simp
(*PATH AUTO FINITE NODES*)

lemma PautR_subseq_rule:"(⋀r. ∀x∈Node. last (map snd r) ≠ Some x ⟹
         r ≠ [] ⟹ NBA.path PautR r None ⟹ last (map snd r) = None) ⟹
(⋃p∈{p. p ∈ nba.initial PautR}. {last (p # map snd r) |r. NBA.path PautR r p})
    ⊆ {r. r = None ∨ (∃x∈Node. r = Some x)}" by auto


lemma PautR_node_subseq:"NBA.nodes PautR ⊆ {r. r = None ∨ (∃x∈ Node. r = Some x)}" 
  unfolding nba.nodes_alt_def nba.reachable_alt_def nba.target_alt_def nba.states_alt_def 
  apply(rule PautR_subseq_rule)
  subgoal premises p for r using p(3,1-2) apply(induct rule: nba.path.induct)
    subgoal by auto
    subgoal for a p by (cases p,  auto simp: RR_PosOfD' split: if_splits) . . 


lemma finite_Nodes_PautR:"finite (NBA.nodes PautR)" 
  apply(rule rev_finite_subset[OF _ PautR_node_subseq]) using finite_Node_opt by auto 

(*TRACE AUTO FINITE NODES*)

lemma TautR_subseq_rule:"(⋀r.  ∀a. (∀x∈Node. a ∉ PosOf x) ∨ (∀b. last (map snd r) ≠ Some (a, b)) ⟹
         r ≠ [] ⟹ NBA.path TautR r None ⟹ last (map snd r) = None)
  ⟹ (⋃p∈{p. p ∈ nba.initial TautR}. {last (p # map snd r) |r. NBA.path TautR r p})
    ⊆ {r. r = None ∨ (∃x∈{(p, s)| p s. p ∈ (⋃v∈Node. PosOf v)}. r = Some x)}" by auto


(*Theorem 5.4*)
theorem SLA_Criterion:"InfiniteDescent ⟷ NBA.language PautR ⊆ NBA.language TautR"
  apply standard
  subgoal unfolding subset_iff PautR_lang_in InfiniteDescent_def apply clarify
    subgoal for Ri nds apply(erule allE[of _ nds], safe)
      by(drule TautR_lang_in,unfold Rst_correct[of Ri nds,symmetric], auto) . 
  subgoal unfolding InfiniteDescent_def apply(clarify)
    subgoal for nds 
      apply(unfold subset_iff PautR_lang_in)
      by(erule allE[of _ "Rst nds"], unfold TautR_lang_in, auto) . .

end
end