Theory Location_Addition

theory Location_Addition
imports Cooperation_Program
theory Location_Addition
  imports
    Cooperation_Program
begin
  
datatype ('f,'v,'t,'l,'tr) location_addition_info = Location_Addition_Info 'l 'l 'tr "('f,'v,'t,'l) transition_rule"

fun change_target :: "'l ⇒ ('f,'v,'t,'l) transition_rule ⇒ ('f,'v,'t,'l) transition_rule" where
  "change_target l (Transition src tgt φ) = Transition src l φ" 

fun change_source :: "'l ⇒ ('f,'v,'t,'l) transition_rule ⇒ ('f,'v,'t,'l) transition_rule" where
  "change_source l (Transition src tgt φ) = Transition l tgt φ" 
  
lemma if_sharp_change_target[simp]: "is_sharp_transition (change_target l tau) = is_sharp_transition tau" by (cases tau, auto)
lemma if_sharp_change_source[simp]: "is_sharp_transition (change_source l tau) = is_sharp l" by (cases tau, auto)

context lts
begin

lemma transition_rule_change_target[simp]: "transition_rule (change_target l tau) = transition_rule tau" 
  by (cases tau, auto)

lemma transition_rule_change_source[simp]: "transition_rule (change_source l tau) = transition_rule tau" 
  by (cases tau, auto)
    
context
  fixes P P'
  assumes SN: "cooperation_SN P'"
  and flat_id: "flat_transitions_of P' = flat_transitions_of P"
  and init_id: "lts.initial P' = lts.initial P" 
    "⋀ l. l ∈ lts.initial P ⟹ assertion P l = assertion P' l"
  and lc: "⋀ l. l ∈ nodes_lts P ⟹ assertion P' l = assertion P l" 
begin
lemma add_new_sharp_location_in_out:  
  assumes sharp_new: "⋀ τ. τ ∈ sharp_transitions_of P - sharp_transitions_of P' ⟹ 
    ∃ τ' l. τ' ∈ sharp_transitions_of P' ∧ skip_transition τ' ∧ 
      ((change_target l τ ∈ sharp_transitions_of P' 
        ∧ source τ' = l ∧ target τ' = target τ 
        ∧ assertion P' l = assertion P (target τ)) 
    ∨ (change_source l τ ∈ sharp_transitions_of P' 
        ∧ source τ' = source τ ∧ target τ' = l 
        ∧ assertion P' l = assertion P (source τ)))" 
  shows "cooperation_SN P" 
proof -
  interpret P': indexed_rewriting "transition_step_lts P'" .
  from init_id have init: "initial_states P' = initial_states P" unfolding initial_states_def  by auto
  show ?thesis
  proof (rule cooperation_SN_on_trancl_image[OF _ _ SN[unfolded init flat_id]])
    fix τ
    assume mem: "τ ∈ sharp_transitions_of P"
    with lc[of "source τ"] lc[of "target τ"]
    have lc: "assertion P' (source τ) = assertion P (source τ)" 
      "assertion P' (target τ) = assertion P (target τ)" 
      unfolding nodes_lts_def by auto
    show "∃ps. ps ≠ {} ∧ ps ⊆ {τ ∈ transition_rules P'. is_sharp_transition τ} ∧ transition_step_lts P τ ⊆ indexed_rewriting.traverse (transition_step_lts P') ps"
    proof(cases "τ ∈ sharp_transitions_of P'")
      case True
      have "transition_step_lts P τ ⊆ P'.traverse {τ}" 
      proof
        fix a b
        assume "(a,b) ∈ transition_step_lts P τ" 
        then have "(a,b) ∈ transition_step_lts P' τ" using lc
          by (cases a; cases b; cases τ, auto)
        then show "(a,b) ∈ P'.traverse {τ}" 
          by (intro P'.mem_traverseI[of "λ i. if i = 0 then a else b" _ 1], auto intro: indexed_rewriting.traversed.intros)
      qed
      then show ?thesis
        by (intro exI[of _ "{τ}"], insert mem True, auto)
    next
      case False
      with mem sharp_new[of τ] obtain τ2 l where 
          t2: "τ2 ∈ sharp_transitions_of P'" 
           "skip_transition τ2" 
        and choice: "change_target l τ ∈ sharp_transitions_of P' ∧ source τ2 = l ∧ target τ2 = target τ
          ∧ assertion P' l = assertion P (target τ) ∨
            change_source l τ ∈ sharp_transitions_of P' ∧ source τ2 = source τ ∧ target τ2 = l
          ∧ assertion P' l = assertion P (source τ)
            " (is "?one ∨ ?two") by auto
      from choice
      show ?thesis
      proof 
        assume *: ?one
        let ?t1 = "change_target l τ" 
        have "transition_step_lts P τ ⊆ P'.traverse {τ2, ?t1}" 
        proof
          fix a b
          assume ab: "(a,b) ∈ transition_step_lts P τ" 
          obtain la sa where a: "a = State sa la" by (cases a, auto)
          obtain lb sb where b: "b = State sb lb" by (cases b, auto)
          let ?c = "State sb l" 
          from ab * t2 have 1: "(a, ?c) ∈ transition_step_lts P' ?t1" and 
            t2'': "target τ2 = lb" and sb: "assignment sb" 
            unfolding a b using lc by (cases τ, auto)                       
          from * have src: "source τ2 = l" by simp
          have 2: "(?c, b) ∈ transition_step_lts P' τ2" unfolding b 
            by (rule skip_transition_step[OF t2(2) sb, unfolded src t2''], 
              insert lc * a b ab, cases τ, auto)
          show "(a,b) ∈ P'.traverse {τ2, ?t1}" by 
            (intro P'.mem_traverseI[of "λ i. if i = 0 then a else if i = 1 then ?c else b" _ "Suc (Suc 0)"], 
            force+, intro P'.traversed.intros, insert 1 2, auto)        
        qed
        with * t2 show ?thesis by (intro exI[of _ "{τ2, ?t1}"], auto)
      next
        assume *: ?two
        let ?t1 = "change_source l τ" 
        have "transition_step_lts P τ ⊆ P'.traverse {?t1, τ2}" 
        proof
          fix a b
          assume ab: "(a,b) ∈ transition_step_lts P τ" 
          obtain la sa where a: "a = State sa la" by (cases a, auto)
          obtain lb sb where b: "b = State sb lb" by (cases b, auto)
          let ?c = "State sa l" 
          from ab * have 1: "(?c, b) ∈ transition_step_lts P' ?t1" and t2'': "source ?t1 = l" "source τ = la" and sa: "assignment sa" 
            unfolding a b using lc * by (cases τ, auto)
          from * have src: "source τ2 = source τ" by simp
          have 2: "(a, ?c) ∈ transition_step_lts P' τ2" unfolding a
            by (insert skip_transition_step[OF t2(2) sa, unfolded src t2'']
              lc * a b ab, cases τ, auto)
          show "(a,b) ∈ P'.traverse {?t1, τ2}" by 
            (intro P'.mem_traverseI[of "λ i. if i = 0 then a else if i = 1 then ?c else b" _ "Suc (Suc 0)"], 
            force+, intro P'.traversed.intros, insert 1 2, auto)        
        qed
        with * t2 show ?thesis by (intro exI[of _ "{ ?t1, τ2}"], auto)
      qed
    qed
  next
    fix τ
    assume mem: "τ ∈ flat_transitions_of P"
    with lc[of "source τ"] lc[of "target τ"]
    have lc: "assertion P' (source τ) = assertion P (source τ)" 
      "assertion P' (target τ) = assertion P (target τ)" 
      unfolding nodes_lts_def by auto
    then show "transition_step_lts P τ = transition_step_lts P' τ" by (cases τ, auto)
  qed
qed

  
lemma add_new_sharp_location_incoming:  
  assumes sharp_new: "⋀ τ. τ ∈ sharp_transitions_of P - sharp_transitions_of P' ⟹ 
    ∃ τ' l. change_target l τ ∈ sharp_transitions_of P' ∧ τ' ∈ sharp_transitions_of P' 
        ∧ skip_transition τ' 
        ∧ source τ' = l ∧ target τ' = target τ 
        ∧ assertion P' l = assertion P (target τ)" 
  shows "cooperation_SN P" 
  by (rule add_new_sharp_location_in_out, insert sharp_new, blast)
    
lemma add_new_sharp_location_outgoing:  
  assumes sharp_new: "⋀ τ. τ ∈ sharp_transitions_of P - sharp_transitions_of P' ⟹ 
    ∃ τ' l. change_source l τ ∈ sharp_transitions_of P' ∧ τ' ∈ sharp_transitions_of P' 
        ∧ skip_transition τ'       
        ∧ source τ' = source τ ∧ target τ' = l 
        ∧ assertion P' l = assertion P (source τ)" 
  shows "cooperation_SN P" 
  by (rule add_new_sharp_location_in_out, insert sharp_new, blast)
end
end

context pre_lts_checker
begin
fun location_addition_incoming where
  "location_addition_incoming P (Location_Addition_Info new old skip_ID skip) = (do {
      check (new ∉ set (nodes_lts_impl P)) (showsl_lit (STR ''location-id '') o showsl new o showsl_lit (STR '' is not fresh''));
      check (is_sharp new) (showsl_lit (STR ''new location '') o showsl new o showsl_lit (STR '' must be sharp location'')); 
      check (is_sharp old) (showsl_lit (STR ''copied location '') o showsl old o showsl_lit (STR '' must be sharp location'')); 
      check (transition_rule skip) (showsl_lit (STR ''new transition '') o showsl skip_ID o showsl_lit (STR '' seems to be ill-formed''));
      check_skip_transition skip <+? (λ s. showsl_lit (STR ''new transition '') o showsl skip_ID o showsl_lit (STR '' must be skip transition⏎'') o s); 
      check (source skip = new ∧ target skip = old) (showsl_lit (STR ''new skip transition '') o showsl skip_ID o showsl_lit (STR '' must be from '')
        o showsl new o showsl_lit (STR '' to '') o showsl old);
      let trans = lts_impl.transitions_impl P;
      let (sharp, flat) = partition (λ tau. is_sharp_transition (snd tau)) trans;
      let (sharp_modify, sharp_keep) = partition (λ tau. target (snd tau) = old) sharp;
      let Q = Lts_Impl (lts_impl.initial P) ((skip_ID, skip) # 
         flat @ sharp_keep @ map (λ tau. (fst tau, change_target new (snd tau))) sharp_modify)
         ((new, assertion_of P old) # assertion_impl P);
      check_allm (λ l. check (assertion_of P l =
        assertion_of Q l) (showsl_lit (STR ''location condition of initial state '') o showsl l o showsl_lit (STR '' has been changed''))) (lts_impl.initial P);
      return Q
    })" 

fun location_addition_outgoing where
  "location_addition_outgoing P (Location_Addition_Info old new skip_ID skip) = (do {
      check (new ∉ set (nodes_lts_impl P)) (showsl_lit (STR ''location-id '') o showsl new o showsl_lit (STR '' is not fresh''));
      check (is_sharp new) (showsl_lit (STR ''new location '') o showsl new o showsl_lit (STR '' must be sharp location'')); 
      check (is_sharp old) (showsl_lit (STR ''copied location '') o showsl old o showsl_lit (STR '' must be sharp location'')); 
      check (transition_rule skip) (showsl_lit (STR ''new transition '') o showsl skip_ID o showsl_lit (STR '' seems to be ill-formed''));
      check_skip_transition skip <+? (λ s. showsl_lit (STR ''new transition '') o showsl skip_ID o showsl_lit (STR '' must be skip transition⏎'') o s); 
      check (source skip = old ∧ target skip = new) (showsl_lit (STR ''new skip transition '') o showsl skip_ID o showsl_lit (STR '' must be from '')
        o showsl old o showsl_lit (STR '' to '') o showsl new);
      let trans = lts_impl.transitions_impl P;
      let (sharp, flat) = partition (λ tau. is_sharp_transition (snd tau)) trans;
      let (sharp_modify, sharp_keep) = partition (λ tau. source (snd tau) = old) sharp;
      let Q = Lts_Impl (lts_impl.initial P) ((skip_ID, skip) # 
         flat @ sharp_keep @ map (λ tau. (fst tau, change_source new (snd tau))) sharp_modify)
         ((new, assertion_of P old) # assertion_impl P); 
      check_allm (λ l. check (assertion_of P l =
        assertion_of Q l) (showsl_lit (STR ''location condition of initial state '') o showsl l o showsl_lit (STR '' has been changed''))) (lts_impl.initial P);
      return Q
    })" 
  
definition location_addition where
  "location_addition P info = (case info of Location_Addition_Info src tgt _ _ ⇒ if
     src ∉ set (nodes_lts_impl P) 
    then location_addition_incoming P info 
    else location_addition_outgoing P info)"
  
end

declare pre_lts_checker.location_addition_incoming.simps[code]
declare pre_lts_checker.location_addition_outgoing.simps[code]
declare pre_lts_checker.location_addition_def[code]

lemma filter_mset_union:
  shows "filter_mset f M + filter_mset g M = filter_mset (λx. f x ∨ g x) M + filter_mset (λx. f x ∧ g x) M"
  by(fold count_inject, auto)

lemma mset_filter_union:
  "mset (filter f xs) + mset (filter g xs) = mset (filter (λx. f x ∨ g x) xs) + mset (filter (λx. f x ∧ g x) xs)"
proof-
  have "mset (filter f xs) + mset (filter g xs) = filter_mset f (mset xs) + filter_mset g (mset xs)" by (simp add: mset_filter)
  also have "... = filter_mset (λx. f x ∨ g x) (mset xs) + filter_mset (λx. f x ∧ g x) (mset xs)"
    by (rule filter_mset_union)
  finally show ?thesis by (simp add: mset_filter)
qed

context lts_checker
begin

lemma location_addition_incoming: assumes SN: "cooperation_SN_impl Q"
  and la: "location_addition_incoming P info = return Q"
shows "cooperation_SN_impl P"
proof (cases info)
  case (Location_Addition_Info new old skip_ID skip)
  note la = la[unfolded this]
  note la = la[simplified, unfolded Let_def o_def, simplified]
  from la have Q: "Q = Lts_Impl (lts_impl.initial P)
   ((skip_ID, skip) #
    [tau←transitions_impl P . ¬ is_sharp_transition (snd tau)] @
    [x←transitions_impl P . is_sharp_transition (snd x) ∧ target (snd x) ≠ old] @
    map (λtau. (fst tau, change_target new (snd tau))) [x←transitions_impl P . is_sharp_transition (snd x) ∧ target (snd x) = old])
    ( (new, assertion_of P old) # assertion_impl P)" by auto
  from la have "isOK(check_skip_transition skip)" by auto
  from check_skip_transition[OF this] la
  have skip: "skip_transition skip" "transition_rule skip" by auto
  from la have sharp_skip: "skip ∈ sharp_transitions_of (lts_of Q)" by (cases skip; auto)
  then have flat_skip: "is_sharp_transition skip" by (cases skip; cases "source skip", auto)
  show ?thesis
  proof (intro cooperation_SN_implI)
    assume P: "lts_impl P"
    then have impl: "lts_impl Q"
    proof (intro lts_implI)
      show "(tr, τ) ∈ set (transitions_impl Q) ⟹ transition_rule τ" for tr τ
        using P skip(2) by (auto elim!: lts_implE simp: Q)
      show "(l, φ) ∈ set (assertion_impl Q) ⟹ formula φ " for l φ
        using P by (auto elim!: lts_implE simp: Q assertion_of_def intro: map_of_defaultI)
    qed
    show "cooperation_SN (lts_of P)"
    proof (rule add_new_sharp_location_incoming)
      show "cooperation_SN (lts_of Q)" using SN impl by (elim cooperation_SN_implE)
      show "lts.initial (lts_of Q) = lts.initial (lts_of P)" by (auto simp: Q)
      show "flat_transitions_of (lts_of Q) = flat_transitions_of (lts_of P)" by (auto simp: flat_skip Q)
      show "l ∈ lts.initial (lts_of P) ⟹ assertion (lts_of P) l = assertion (lts_of Q) l" for l using la by auto
      fix τ
      assume "τ ∈ sharp_transitions_of (lts_of P) - sharp_transitions_of (lts_of Q)" 
      then have tau: "target τ = old" "change_target new τ ∈ sharp_transitions_of (lts_of Q)" unfolding Q by auto
      have lc: "assertion (lts_of Q) new = assertion (lts_of P) old" 
        unfolding Q 
        by (auto simp: assertion_of_def map_of_default_def lookup_default_def lookup_of_alist)
      show "∃τ' l. change_target l τ ∈ sharp_transitions_of (lts_of Q) ∧
                τ' ∈ sharp_transitions_of (lts_of Q) ∧ skip_transition τ' ∧ source τ' = l ∧ target τ' = target τ
             ∧ assertion (lts_of Q) l = assertion (lts_of P) (target τ)" 
        by (intro exI conjI, rule tau(2), rule sharp_skip, rule skip, unfold tau, insert la lc, auto)
    next
      fix l 
      assume "l ∈ nodes_lts (lts_of P)" 
      with la have "l ≠ new" by auto
      then show "assertion (lts_of Q) l = assertion (lts_of P) l"
        by (auto simp: Q map_of_default_def lookup_default_def assertion_of_def lookup_of_alist)
    qed
  qed
qed

lemma location_addition_outgoing: assumes SN: "cooperation_SN_impl Q"
  and la: "location_addition_outgoing P info = return Q"
shows "cooperation_SN_impl P"
proof (cases info)
  case (Location_Addition_Info old new skip_ID skip) 
  note la = la[unfolded this]
  note la = la[simplified, unfolded Let_def o_def, simplified]
  from la have Q: "Q = Lts_Impl (lts_impl.initial P)
   ((skip_ID, skip) #
    [tau←transitions_impl P . ¬ is_sharp_transition (snd tau)] @
    [x←transitions_impl P . is_sharp_transition (snd x) ∧ source (snd x) ≠ old] @
    map (λtau. (fst tau, change_source new (snd tau))) [x←transitions_impl P . is_sharp_transition (snd x) ∧ source (snd x) = old])
    ( (new, assertion_of P old) # assertion_impl P)" by auto
  from la have "isOK(check_skip_transition skip)" by auto
  from check_skip_transition[OF this] la
  have skip: "skip_transition skip" "transition_rule skip" by auto
  from la have sharp_skip: "skip ∈ sharp_transitions_of (lts_of Q)" by (cases skip; auto)
  then have flat_skip: "is_sharp_transition skip" by (cases skip; cases "source skip", auto)
  show ?thesis
  proof
    assume P: "lts_impl P"
    then have impl: "lts_impl Q"
    proof (intro lts_implI)
      show "(tr, τ) ∈ set (transitions_impl Q) ⟹ transition_rule τ" for tr τ
        using P skip(2) by (auto elim!: lts_implE simp: Q)
      show "(l, φ) ∈ set (assertion_impl Q) ⟹ formula φ " for l φ
        using P by (auto elim!: lts_implE simp: Q assertion_of_def intro: map_of_defaultI)
    qed
    show "cooperation_SN (lts_of P)"
    proof (rule add_new_sharp_location_outgoing)
      show "cooperation_SN (lts_of Q)" using impl SN by auto
      show "lts.initial (lts_of Q) = lts.initial (lts_of P)" by (auto simp: Q)
      from la have sharp_new: "is_sharp new" by auto
      then show "flat_transitions_of (lts_of Q) = flat_transitions_of (lts_of P)" by (auto simp: flat_skip Q)
      show "l ∈ lts.initial (lts_of P) ⟹ assertion (lts_of P) l = assertion (lts_of Q) l" for l using la by auto
      fix τ
      assume "τ ∈ sharp_transitions_of (lts_of P) - sharp_transitions_of (lts_of Q)" 
      with sharp_new have tau: "source τ = old" "change_source new τ ∈ sharp_transitions_of (lts_of Q)" unfolding Q by auto
      have lc: "assertion (lts_of Q) new = assertion (lts_of P) old" 
        unfolding Q 
        by (auto simp: assertion_of_def map_of_default_def lookup_default_def lookup_of_alist)
      show "∃τ' l. change_source l τ ∈ sharp_transitions_of (lts_of Q) ∧
                τ' ∈ sharp_transitions_of (lts_of Q) ∧ skip_transition τ' ∧ source τ' = source τ ∧ target τ' = l
             ∧ assertion (lts_of Q) l = assertion (lts_of P) (source τ)" 
        by (intro exI conjI, rule tau(2), rule sharp_skip, rule skip, unfold tau, insert la lc, auto)
    next
      fix l 
      assume "l ∈ nodes_lts (lts_of P)" 
      with la have "l ≠ new" by auto
      then show "assertion (lts_of Q) l = assertion (lts_of P) l"
        by (auto simp: Q map_of_default_def lookup_default_def assertion_of_def lookup_of_alist)
    qed
  qed
qed

lemma location_addition: assumes SN: "cooperation_SN_impl Q"
  and la: "location_addition P info = return Q"
shows "cooperation_SN_impl P"
proof (cases info)
  case (Location_Addition_Info src)
  from la[unfolded location_addition_def this location_addition_info.simps, folded this]
    location_addition_incoming location_addition_outgoing SN
  show ?thesis by (auto split: if_splits)
qed

end

end