Theory SM.Gen_Scheduler_Refine
theory Gen_Scheduler_Refine
imports "../RefPoint/Gen_Scheduler"
begin
  locale Gen_Scheduler' = cs: LTS cstep 
    for cstep :: "'c ⇒ 'a ⇒ 'c ⇒ bool" +
    fixes en :: "('ls×'gs) ⇒ 'a ⇒ bool"
    fixes ex :: "('ls×'gs) ⇒ 'a ⇒ ('ls×'gs)"
  begin
    
    definition gstep_succ 
      :: "('c,'ls,'gs)global_config ⇒ ('c,'ls,'gs)global_config set" 
      where
      "gstep_succ gc ≡ do {
        
        let lcs = global_config.processes gc;
        (lc,lcs') ← {(lc,lcs'). lcs = {#lc#} + lcs'};
        
        let gs = global_config.state gc;
        let ls = local_config.state lc;
  
        
        let cmd = local_config.command lc;
        (a,cmd') ← {(a,cmd'). cstep cmd a cmd'};
  
        case en (ls,gs) a of
          False ⇒ {}   
        | True ⇒ {do { 
            
            let (ls,gs) = ex (ls,gs) a;
            
            ⦇ 
              global_config.processes = {# 
                ⦇ local_config.command = cmd', local_config.state = ls⦈ 
              #} + lcs',
              global_config.state = gs  
            ⦈
          }}
      }"
    abbreviation "gstep ≡ rel_of_succ gstep_succ"
 
    text ‹For the final step function, we apply stutter extension›
    definition "step ≡ stutter_extend_edges UNIV gstep"
    lemma gstep_succE[cases set: gstep_succ, case_names succ]: 
      assumes "gc' ∈ gstep_succ gc"
      obtains lc lcs c' a ls' gs'
        where
        "processes gc = {#lc#} + lcs"
        "cstep (command lc) a c'"
        "en (local_config.state lc, global_config.state gc) a"
        "ex (local_config.state lc, global_config.state gc) a = (ls',gs')"
        "gc' = ⦇
          global_config.processes 
            = {#⦇ local_config.command = c', local_config.state = ls' ⦈#} + lcs,
          global_config.state 
            = gs'
        ⦈"
      using assms
      unfolding gstep_succ_def
      by (auto
        split: option.splits bool.splits Option.bind_splits prod.splits
        simp: all_conj_distrib
        elim!: neq_Some_bool_cases)
    lemma gstep_succI:
      assumes "processes gc = {#lc#} + lcs"
      assumes "cstep (command lc) a c'"
      assumes "en (local_config.state lc, global_config.state gc) a"
      assumes "ex (local_config.state lc, global_config.state gc) a = (ls',gs')"
      shows "⦇
          global_config.processes 
            = {#⦇ local_config.command = c', local_config.state = ls' ⦈#} + lcs,
          global_config.state 
            = gs'
        ⦈ ∈ gstep_succ gc"
      using assms unfolding gstep_succ_def
      by (fastforce)
  end    
  locale Gen_Scheduler'_linit = 
    Gen_Scheduler' cstep en ex
    for cstep :: "'c ⇒ 'a ⇒ 'c ⇒ bool"
    and en :: "('ls×'gs) ⇒ 'a ⇒ bool"
    and ex :: "('ls×'gs) ⇒ 'a ⇒ ('ls×'gs)" +
    fixes init :: "('c,'ls,'gs) global_config set"
    fixes label :: "('c,'ls,'gs) global_config ⇒ 'l"
  begin
    definition system_automaton' :: "(('c,'ls,'gs) global_config, 'l) sa_rec"
      where "system_automaton' ≡ ⦇ g_V = UNIV, g_E = gstep, g_V0 = init, sa_L = label ⦈"
    lemma system_automaton'_simps[simp]:
      "g_V system_automaton' = UNIV"
      "g_E system_automaton' = gstep"
      "g_V0 system_automaton' = init"
      "sa_L system_automaton' = label"
      unfolding system_automaton'_def by simp+
    definition system_automaton :: "(('c,'ls,'gs) global_config, 'l) sa_rec"
      where "system_automaton ≡ ⦇ g_V = UNIV, g_E = step, g_V0 = init, sa_L = label ⦈"
    lemma system_automaton_simps[simp]:
      "g_V system_automaton = UNIV"
      "g_E system_automaton = step"
      "g_V0 system_automaton = init"
      "sa_L system_automaton = label"
      unfolding system_automaton_def by simp+
    lemma system_automaton_alt_def: "system_automaton = stutter_extend system_automaton'"
      unfolding step_def system_automaton'_def system_automaton_def stutter_extend_def by simp
    sublocale sa': sa system_automaton' by unfold_locales auto
    sublocale sa: sa system_automaton unfolding system_automaton_alt_def by (rule sa'.stutter_extend_sa)
  end
  locale sched_typing = 
    s1: Gen_Scheduler cstep1 en1 ex1 +
    s2: Gen_Scheduler' cstep2 en2 ex2
    for cstep1 :: "'c ⇒ 'a+'b ⇒ 'c ⇒ bool"
    and en1 :: "('ls×'gs) ⇒ 'a ⇀ bool"
    and ex1 :: "('ls×'gs) ⇒ 'a ⇀ ('ls×'gs)"
    and cstep2 :: "'c ⇒ 'a ⇒ 'c ⇒ bool"
    and en2 :: "('ls×'gs) ⇒ 'a ⇒ bool"
    and ex2 :: "('ls×'gs) ⇒ 'a ⇒ ('ls×'gs)" 
    +
    fixes wf_local :: "'c ⇒ 'ls ⇒ 'gs ⇒ bool"
    assumes wf_cstep: "wf_local c ls gs 
      ⟹ cstep1 c aa c' ⟷ (∃a. aa=Inl a ∧ cstep2 c a c')"
    assumes wf_en: "⟦wf_local c ls gs; cstep1 c (Inl a) c'⟧ 
      ⟹ en1 (ls,gs) a = Some (en2 (ls,gs) a)"  
    assumes wf_ex: "⟦wf_local c ls gs; cstep1 c (Inl a) c'; en1 (ls,gs) a = Some True⟧
      ⟹ ex1 (ls,gs) a = Some (ex2 (ls,gs) a)"
    assumes wf_pres_this: "⟦ 
      wf_local c ls gs; cstep1 c (Inl a) c'; 
      en1 (ls,gs) a = Some True; ex1 (ls,gs) a = Some (ls',gs') ⟧ 
      ⟹ wf_local c' ls' gs'"  
    assumes wf_pres_other: "⟦ 
      wf_local c ls gs; cstep1 c (Inl a) c'; 
      en1 (ls,gs) a = Some True; ex1 (ls,gs) a = Some (ls',gs');
      wf_local co lso gs
    ⟧ 
      ⟹ wf_local co lso gs'"  
  begin
    definition wf_gglobal :: "('c,'ls,'gs) global_config ⇒ bool" where
      "wf_gglobal gc ≡ ∀lc. lc∈#global_config.processes gc
        ⟶ wf_local 
              (local_config.command lc) 
              (local_config.state lc) 
              (global_config.state gc)"
        
    primrec wf_global where
      "wf_global None = False"
    | "wf_global (Some gc) = wf_gglobal gc"          
    lemma wf_cstep_revI: 
      "⟦wf_local c ls gs; cstep2 c a c'⟧ ⟹ cstep1 c (Inl a) c'"
      using wf_cstep by auto
    lemma wf_en_revI: 
      "⟦wf_local c ls gs; cstep1 c (Inl a) c'; en2 (ls,gs) a ⟧ ⟹ en1 (ls,gs) a = Some True"
      using wf_en by auto
    lemma wf_ex_revI: 
      "⟦wf_local c ls gs; cstep1 c (Inl a) c'; en2 (ls,gs) a; ex2 (ls,gs) a = fs' ⟧ 
      ⟹ ex1 (ls,gs) a = Some fs'"
      using wf_en wf_ex by auto
    lemma wf_pres_step: "⟦wf_global gc; (gc, gc') ∈ s1.step⟧ ⟹ wf_global gc'"
      apply (cases gc, simp_all)
      unfolding s1.step_def s1.gstep_def
      apply (erule stutter_extend_edgesE)
        apply (clarsimp)
        apply (erule s1.gstep_succE)
        apply (auto 
          simp: wf_gglobal_def all_conj_distrib
          simp: wf_cstep
          ) []
        apply (auto 
          simp: wf_gglobal_def all_conj_distrib
          simp: wf_en wf_cstep
          ) []
        apply (auto 
          simp: wf_gglobal_def all_conj_distrib
          simp: wf_en wf_ex wf_cstep
          ) []
        apply (auto 
          simp: wf_gglobal_def all_conj_distrib
          intro: wf_pres_this wf_pres_other
          ) []
        
        apply clarsimp
      done
    lemma wf_gstep_eq: "wf_gglobal gc ⟹
      s1.gstep_succ gc = Some`s2.gstep_succ gc"
      apply safe
        apply (erule s1.gstep_succE, simp_all add: inj_image_mem_iff) []
        apply (auto 
          simp: wf_gglobal_def all_conj_distrib
          simp: wf_en wf_ex wf_cstep
          ) [3]
        apply (clarsimp
          simp: wf_gglobal_def all_conj_distrib
          simp: wf_en wf_ex wf_cstep
          ) []
        apply (auto intro!: s2.gstep_succI)
        apply (erule s2.gstep_succE, 
          clarsimp_all simp: wf_gglobal_def all_conj_distrib) []
        apply (rule s1.gstep_succ_succ, assumption)
        apply (rule wf_cstep_revI, assumption+)
        apply (rule wf_en_revI, assumption+, auto simp: wf_cstep) []
        apply (rule wf_ex_revI, assumption+, auto simp: wf_cstep) []
      done
      
    lemma wf_gstep_revI: 
      "⟦wf_gglobal gc; gc'∈s2.gstep_succ gc⟧ 
      ⟹ Some gc' ∈ s1.gstep_succ gc"
      by (auto simp: wf_gstep_eq)
    lemma wf_step_eq: "wf_global gco ⟹ 
      (gco, gco') ∈ s1.step 
      ⟷ (∃gc gc'. gco=Some gc ∧ gco'=Some gc' ∧ (gc, gc') ∈ s2.step)"
      apply (cases gco, simp_all)
      unfolding s1.step_def s2.step_def s1.gstep_def
      apply safe
      apply (erule stutter_extend_edgesE)
        apply (auto simp: wf_gstep_eq intro!: stutter_extend_edgesI_edge) []
        apply clarsimp
        apply (rule stutter_extend_edgesI_stutter, clarsimp)
        apply (auto dest!: wf_gstep_revI) []
      apply (erule stutter_extend_edgesE)
        apply (auto simp: wf_gstep_eq intro!: stutter_extend_edgesI_edge) []
        apply clarsimp
        apply (rule stutter_extend_edgesI_stutter, clarsimp)
        apply (force simp: wf_gstep_eq) []
      done
    lemma wf_pres_step2: "⟦ wf_gglobal gc; (gc, gc') ∈ s2.step ⟧ ⟹ wf_gglobal gc'"
      using wf_pres_step[of "Some gc" "Some gc'"]
      by (simp add: wf_step_eq)
  end
  locale sched_typing_init = 
    sched_typing cstep1 en1 ex1 cstep2 en2 ex2 wf_local +
    s1: Gen_Scheduler_linit cstep1 en1 ex1 ginit glabel +
    s2: Gen_Scheduler'_linit cstep2 en2 ex2 ginit glabel
    for cstep1 :: "'c ⇒ 'a+'b ⇒ 'c ⇒ bool"
    and en1 :: "('ls×'gs) ⇒ 'a ⇀ bool"
    and ex1 :: "('ls×'gs) ⇒ 'a ⇀ ('ls×'gs)"
    and cstep2 :: "'c ⇒ 'a ⇒ 'c ⇒ bool"
    and en2 :: "('ls×'gs) ⇒ 'a ⇒ bool"
    and ex2 :: "('ls×'gs) ⇒ 'a ⇒ ('ls×'gs)" 
    and ginit :: "('c,'ls,'gs) global_config set"
    and glabel :: "('c,'ls,'gs) global_config ⇒ 'l"
    and wf_local :: "'c ⇒ 'ls ⇒ 'gs ⇒ bool" +
    assumes wf_init: "gc ∈ ginit ⟹ wf_gglobal gc"
  begin
    sublocale bisim: lbisimulation "br Some wf_gglobal"
      s2.system_automaton
      s1.system_automaton
      apply unfold_locales
      apply (auto simp: build_rel_def wf_init wf_step_eq wf_pres_step2 simp: s1.init_conv)
      done
    lemma accept_eq: "s2.sa.accept = s1.sa.accept"
      using bisim.accept_bisim .
    lemma is_run_conv: "s1.sa.g.is_run r ⟷ (∃r'. r=Some o r' ∧ s2.sa.g.is_run r')"  
      using bisim.br_run_conv[OF refl] .
  end
end