Theory SM.SM_POR

theory SM_POR
imports SM_Sticky
begin

  context transition_system_concurrent begin
    lemma pac_en_blocked':
      assumes A: "s  nodes" "path w s" "pac p  {a. en a s}  set w = {}"
      assumes IS: "s' a. pac p  {a. en a s} = pac p  {a. en a s'};
        psen p s = psen p s'; en a s'; apac p  
        pac p  {b. en b (ex a s')} = pac p  {a. en a s'}  psen p (ex a s') = psen p s'"
      shows "pac p  set w = {}"
    proof (rule words_fin_blocked[OF _ A(2,3)])
      fix w
      assume "path w s" "pac p  set w = {}"
      hence "pac p  {a. en a s} = pac p  {a. en a (target w s)}  psen p s = psen p (fold ex w s)"
      proof (induction w rule: rev_induct)
        case (snoc a w) 
        from snoc have 
          "pac p  {a. en a s} = pac p  {a. en a (target w s)}"
          "psen p s = psen p (fold ex w s)"
          by auto
        with IS[OF this] snoc.prems show ?case by auto 
      qed simp
      thus "pac p  {a. en a (target w s)}  pac p  {a. en a s}" by blast
    qed
  
  end

  context cprog begin
    definition is_ample_static :: "cmdc  bool" where
      "is_ample_static c  a c'. cfgc c a c' 
        read_globals a = {}  write_globals a = {}"

  end      

  context visible_prog 
  begin
    lemma None_ga_en_conv[simp]: 
      "Nonega_en gc  ga_en gc = {None}"
      by (auto simp: ga_en_def stutter_extend_en_def)

      
    lemma genabled_no_global_read_indep_other_pids:
      assumes "read_globals a = {}" 
      assumes "pid'pid"
      shows "(pid,c,a, c')ga_gen (ga_gex (pid',cac') gc) 
         (pid,c,a, c')ga_gen gc"
      using assms 
      apply (auto 
        simp: ga_gen_def ga_gex_def ex_pres_en
        split: prod.splits)
      done    


  end

  definition pid_pac :: "pid  global_action option set" where
    "pid_pac pid  Collect (λSome (pid',_)  pid'=pid | None  True)"

  lemma pid_pac_None[simp]: "None  pid_pac pid"
    by (auto simp: pid_pac_def)


  context visible_prog
  begin  

    definition pid_procs :: "pid_global_config  pid set" where
      "pid_procs gc  {0..<length (pid_global_config.processes gc)}"

    definition pid_psen :: "pid  pid_global_config  global_action option set"
      where "pid_psen pid gc  insert None 
        (Some`{(pid,c,a,c') | c a c'. c = cmd_of_pid gc pid  cfgc c a c'})"

    sublocale jsys: transition_system_concurrent
      ga_ex "λ a p. a  ga_en p" "λ p. p = pid_init_gc"
      pid_procs pid_pac pid_psen
    
      apply unfold_locales
      
      apply (auto simp: pid_procs_def) []

      apply (auto 
        simp: pid_pac_def pid_psen_def ga_en_def ga_gen_def
        simp: stutter_extend_en_def
        split: option.splits
        ) []
      
      apply (auto 
        simp: pid_pac_def pid_psen_def ga_en_def ga_gen_def
        simp: stutter_extend_en_def ga_ex_def ga_gex_def
        split: option.splits if_split_asm prod.splits
        ) []
      done

  end

  locale ample_prog = sticky_prog +
    fixes ga_ample :: "pid_global_config  global_action option set"
    assumes ga_ample_approx: 
    "gc  (g_E ga_automaton)* `` g_V0 ga_automaton; ga_ample gc  ga_en gc  
      ga_ample gc  sticky_ga = {}
     ga_ample gc  {}
     (pid. 
        ga_ample gc = ga_en gc  pid_pac pid 
       is_ample_static (cmd_of_pid gc pid))"

  begin

    lemma pid_enabled_ample:
      assumes REACH[simp, intro!]: "gc  ga.E* `` ga.V0"
      shows "jsys.ample_set gc (ga_ample gc)"
    proof (cases "ga_ample gc = ga_en gc")
      case True thus ?thesis using jsys.ample_en by auto
    next
      case False
      from ga_ample_approx[OF REACH False] obtain pid where 
        AMPLE_SS: "ga_ample gc  ga_en gc"
      and NE: "ga_ample gc  {}"  
      and NS: "ga_ample gc  sticky_ga = {}"
      and AMPLE_FMT: "ga_ample gc = pid_pac pid  ga_en gc"
      and A_STATIC: "is_ample_static (cmd_of_pid gc pid)"
        by blast
      hence aux1: "ga_ample gc = ga_ample gc  ga_en gc" by blast
  
      from False NE AMPLE_SS have NN: "None  ga_en gc" by auto

      
      from A_STATIC have LOC: "
        c a c'. Some (pid, c,a,c')  pid_psen pid gc 
           read_globals a = {}  write_globals a = {}"
        unfolding is_ample_static_def pid_psen_def 
        by auto
      from A_STATIC have LOC': "
        c a c'. Some (pid, c,a,c')  pid_pac pid  ga_en gc 
           read_globals a = {}  write_globals a = {}"
        unfolding is_ample_static_def pid_pac_def ga_en_def 
        by (auto split: prod.splits simp:  ga_gen_def)

      from reachable_alt[symmetric] REACH 
      have REACH': "gc  jsys.nodes" by simp  

      have INV': 
        "c a c'. Some (pid,c,a,c')ga_en gc 
         Some (pid,c,a,c')  jsys.visible"
        using NS sticky_ga_approx_visible
        apply (clarsimp simp: AMPLE_FMT pid_pac_def split: option.splits) 
        apply blast
        done

      { 
        fix ga gc'
        assume en_eq: "pid_pac pid  ga_en gc = pid_pac pid  ga_en gc'"
        assume psen_eq: "pid_psen pid gc = pid_psen pid gc'"
        assume ga_en: "ga  ga_en gc'" 
        assume ga_not_pid: "ga  pid_pac pid"
        
        from en_eq NN have [simp]: "None  ga_en gc'"
          using pid_pac_None
          by blast

        with ga_en have "gaNone" by metis
        then obtain pid' c a c' where [simp]: "ga = Some (pid',c,a,c')"
          by (cases ga) auto
  
        from ga_not_pid have [simp]: "pid'pid" by (auto simp: pid_pac_def)
        
        have [simp]: "cac. Some (pid,cac)  ga_en gc' 
           Some (pid,cac)  ga_en gc"
          using en_eq unfolding pid_pac_def
            by (auto split: option.splits)
        hence pid_gen_gc'_gc: "cac. (pid,cac)  ga_gen gc' 
           (pid,cac)  ga_gen gc"
          unfolding ga_en_def
          by simp
  
        have "cmd_of_pid (ga_gex (pid', c, a, c') gc') pid 
          = cmd_of_pid gc' pid"
          by (auto simp: ga_gex_def split: prod.splits)
        hence G1: "pid_psen pid (ga_ex ga gc') = pid_psen pid gc'"
          by (auto simp: pid_psen_def ga_gex_def ga_ex_def
            split: prod.splits)
  
        have pid_ge_ex_invar: "cac. 
          (pid,cac)ga_gen (ga_ex (Some (pid', c, a, c')) gc') 
          (pid,cac)ga_gen gc'"
          apply (clarsimp simp: ga_en_def ga_ex_def) 
        proof
          fix c'' a'' c'''
          assume A: "(pid, c'', a'', c''')  ga_gen (ga_gex (pid', c, a, c') gc')"
          hence "Some (pid, c'', a'', c''')  pid_psen pid (ga_gex (pid', c, a, c') gc')"
            by (auto simp: pid_psen_def ga_gen_def)
          hence "Some (pid, c'', a'', c''')  pid_psen pid gc" using G1 psen_eq
            by (simp add: ga_ex_def)
          from LOC[OF this]
            have "read_globals a'' = {}" by simp
          from genabled_no_global_read_indep_other_pids[OF this pid'pid] A
          show "((pid, c'', a'', c''')  ga_gen gc')" ..
        next
          fix c'' a'' c'''
          assume A: "((pid, c'', a'', c''')  ga_gen gc')"
          hence "Some (pid, c'', a'', c''')  pid_psen pid gc'"
            by (auto simp: pid_psen_def ga_gen_def)
          hence "Some (pid, c'', a'', c''')  pid_psen pid gc" using psen_eq
            by (simp)
          from LOC[OF this] have "read_globals a'' = {}" by simp
          from genabled_no_global_read_indep_other_pids[OF this pid'pid] A
          show "(pid, c'', a'', c''')  ga_gen (ga_gex (pid', c, a, c') gc')" ..
        qed
  
        have [simp]: 
          "ga_gen (ga_ex (Some (pid', c, a, c')) gc')  {}"
          "ga_gen gc'  {}"
        proof -
          from NN NE obtain cac2 where "Some (pid,cac2)  ga_en gc"
            unfolding AMPLE_FMT
            apply (clarsimp simp: ex_in_conv[symmetric])
            using NN
            apply (auto simp: pid_pac_def split: option.splits)
            done
          hence "(pid,cac2)  ga_gen gc" by (auto simp: ga_en_def)
          hence 1: "(pid,cac2)  ga_gen gc'"
            by (simp add: pid_gen_gc'_gc)
          thus "ga_gen gc'  {}" by blast
          from 1 have "(pid,cac2)  ga_gen (ga_ex (Some (pid', c, a, c')) gc')"
            by (simp add: pid_ge_ex_invar pid_gen_gc'_gc)
          thus "ga_gen (ga_ex (Some (pid', c, a, c')) gc')  {}" by blast  
        qed
        
        have G2: "pid_pac pid  ga_en (ga_ex ga gc') =
             pid_pac pid  ga_en gc'"
          apply (auto simp: pid_pac_def split: option.splits)
          apply (auto simp add: ga_en_def stutter_extend_en_def
              pid_ge_ex_invar
              split: if_split_asm) [2]
          done
        note G1 G2
      } note aux=this

      show ?thesis
        apply (subst AMPLE_FMT)
        apply (rule jsys.restrict_ample_set[unfolded Collect_mem_eq])
        apply (simp add: reachable_alt del: ga_automaton_simps)
        using NE AMPLE_FMT apply blast
        using NS AMPLE_FMT apply blast
        apply safe []
        apply (rename_tac ga1 ga2)
        apply (case_tac "(ga1,ga2)" rule: ind.cases) 
        using NN apply (simp_all) [4]
        apply (simp_all add: pid_pac_def LOC' INV') []
        
        apply (rule jsys.pac_en_blocked'[OF REACH'])
        unfolding Collect_mem_eq
        apply assumption+
        apply (rule conjI)
        apply (rule aux, assumption+)
        apply (rule aux, assumption+)
        done
    qed
  
    sublocale jsys: ample_abstract
      ga_ex "λ a p. a  ga_en p" "λ p. p = pid_init_gc" 
      pid_interp_gc ind "jsys.scut¯¯" "λ a p. a  ga_ample p"
      apply unfold_locales
      unfolding Collect_mem_eq
      apply (rule pid_enabled_ample)
      apply (simp add: reachable_alt)
      done

    definition "ample_rel  rel_of_enex (ga_ample, ga_ex)"
    definition "ample_succ  succ_of_enex (ga_ample, ga_ex)"

    definition reduced_automaton
      where "reduced_automaton =
         g_V = UNIV, g_E = ample_rel, g_V0 = {pid_init_gc}, sa_L = pid_interp_gc "

    lemma reduced_automaton_simps[simp]:
      "g_V reduced_automaton = UNIV"
      "g_E reduced_automaton = ample_rel"
      "g_V0 reduced_automaton = {pid_init_gc}"
      "sa_L reduced_automaton = pid_interp_gc"
      unfolding reduced_automaton_def by auto

    sublocale ample: sa reduced_automaton by unfold_locales auto

    lemma jsys_R_lang_eq: "snth ` jsys.R.language = Collect ample.accept"
      apply (subst system_complete_language_eq_lsystem_accept)
      using ample.sa_axioms
      unfolding reduced_automaton_def ample_rel_def
      apply simp
      apply (auto simp: ample_rel_def sngp_sym_conv)
      done

    lemma ample_accept_subset: "ample.accept w  lv.sa.accept w"
    proof -
      assume "ample.accept w"
      hence "w  snth ` jsys.R.language" by (simp add: jsys_R_lang_eq)
      hence "w  snth ` jsys.language" using jsys.reduction_language_subset by auto
      with jsys_lang_eq show "lv.sa.accept w" by auto
    qed

    lemma ample_accept_stuttering:
      assumes A: "lv.sa.accept w" 
      obtains w' where "ww'" "ample.accept w'"
    proof -
      from A have "w  snth ` jsys.language" by (simp add: jsys_lang_eq)
      then obtain w' where "w  w'" "w'  snth ` jsys.R.language"
        by (auto elim!: jsys.reduction_language_stuttering)
      hence "ample.accept w'" by (simp add: jsys_R_lang_eq)
      thus ?thesis using ww' by (blast intro: that)
    qed
  end


end