Theory Stuttering_Extension

theory Stuttering_Extension
imports Simulation Step_Conv
begin

  definition stutter_extend_edges :: "'v set ⇒ 'v digraph ⇒ 'v digraph"
    where "stutter_extend_edges V E ≡ E ∪ {(v, v) |v. v ∈ V ∧ v ∉ Domain E}"

  lemma stutter_extend_edgesI_edge:
    assumes "(u, v) ∈ E"
    shows "(u, v) ∈ stutter_extend_edges V E"
    using assms unfolding stutter_extend_edges_def by auto
  lemma stutter_extend_edgesI_stutter:
    assumes "v ∈ V" "v ∉ Domain E"
    shows "(v, v) ∈ stutter_extend_edges V E"
    using assms unfolding stutter_extend_edges_def by auto
  lemma stutter_extend_edgesE:
    assumes "(u, v) ∈ stutter_extend_edges V E"
    obtains (edge) "(u, v) ∈ E" | (stutter) "u ∈ V" "u ∉ Domain E" "u = v"
    using assms unfolding stutter_extend_edges_def by auto

  lemma stutter_extend_wf: "E ⊆ V × V ⟹ stutter_extend_edges V E ⊆ V × V"
    unfolding stutter_extend_edges_def by auto

  lemma stutter_extend_edges_rtrancl[simp]: "(stutter_extend_edges V E)* = E*"
    unfolding stutter_extend_edges_def by (auto intro: in_rtrancl_UnI elim: rtrancl_induct)

  lemma stutter_extend_domain: "V ⊆ Domain (stutter_extend_edges V E)"
    unfolding stutter_extend_edges_def by auto

  definition stutter_extend :: "('v, _) graph_rec_scheme ⇒ ('v, _) graph_rec_scheme"
    where "stutter_extend G ≡
    ⦇
      g_V = g_V G,
      g_E = stutter_extend_edges (g_V G) (g_E G),
      g_V0 = g_V0 G,
      … = graph_rec.more G
    ⦈"

  lemma stutter_extend_simps[simp]:
    "g_V (stutter_extend G) = g_V G"
    "g_E (stutter_extend G) = stutter_extend_edges (g_V G) (g_E G)"
    "g_V0 (stutter_extend G) = g_V0 G"
    unfolding stutter_extend_def by auto

  lemma stutter_extend_simps_sa[simp]:
    "sa_L (stutter_extend G) = sa_L G"
    unfolding stutter_extend_def
    by (metis graph_rec.select_convs(4) sa_rec.select_convs(1) sa_rec.surjective)

  lemma (in graph) stutter_extend_graph: "graph (stutter_extend G)"
    using V0_ss E_ss by (unfold_locales, auto intro!: stutter_extend_wf)
  lemma (in sa) stutter_extend_sa: "sa (stutter_extend G)"
  proof -
    interpret graph "stutter_extend G" using stutter_extend_graph by this
    show ?thesis by unfold_locales
  qed

  lemma (in bisimulation) stutter_extend: "bisimulation R (stutter_extend A) (stutter_extend B)"
  proof -
    interpret ea: graph "stutter_extend A" by (rule a.stutter_extend_graph)
    interpret eb: graph "stutter_extend B" by (rule b.stutter_extend_graph)
    show ?thesis
    proof
      fix a b
      assume "a ∈ g_V (stutter_extend A)" "(a, b) ∈ R"
      thus "b ∈ g_V (stutter_extend B)" using s1.nodes_sim by simp
    next
      fix a
      assume "a ∈ g_V0 (stutter_extend A)"
      thus "∃ b. b ∈ g_V0 (stutter_extend B) ∧ (a, b) ∈ R" using s1.init_sim by simp
    next
      fix a a' b
      assume "(a, a') ∈ g_E (stutter_extend A)" "(a, b) ∈ R"
      thus "∃ b'. (b, b') ∈ g_E (stutter_extend B) ∧ (a', b') ∈ R"
        apply simp
        using s1.nodes_sim s1.step_sim s2.stuck_sim 
        by (blast
          intro: stutter_extend_edgesI_edge stutter_extend_edgesI_stutter
          elim: stutter_extend_edgesE)
    next
      fix b a
      assume "b ∈ g_V (stutter_extend B)" "(b, a) ∈ R¯"
      thus "a ∈ g_V (stutter_extend A)" using s2.nodes_sim by simp
    next
      fix b
      assume "b ∈ g_V0 (stutter_extend B)"
      thus "∃ a. a ∈ g_V0 (stutter_extend A) ∧ (b, a) ∈ R¯" using s2.init_sim by simp
    next
      fix b b' a
      assume "(b, b') ∈ g_E (stutter_extend B)" "(b, a) ∈ R¯"
      thus "∃ a'. (a, a') ∈ g_E (stutter_extend A) ∧ (b', a') ∈ R¯"
        apply simp
        using s2.nodes_sim s2.step_sim s1.stuck_sim
        by (blast
          intro: stutter_extend_edgesI_edge stutter_extend_edgesI_stutter
          elim: stutter_extend_edgesE)
    qed
  qed

  lemma (in lbisimulation) lstutter_extend: "lbisimulation R (stutter_extend A) (stutter_extend B)"
  proof -
    interpret se: bisimulation R "stutter_extend A" "stutter_extend B" by (rule stutter_extend)
    show ?thesis by (unfold_locales, auto simp: s1.labeling_consistent)
  qed

  definition stutter_extend_en :: "('s⇒'a set) ⇒ ('s ⇒ 'a option set)" where
    "stutter_extend_en en ≡ λs. let as = en s in if as={} then {None} else Some`as"
  
  definition stutter_extend_ex :: "('a ⇒ 's ⇒ 's) ⇒ ('a option ⇒ 's ⇒ 's)" where
    "stutter_extend_ex ex ≡ λNone ⇒ id | Some a ⇒ ex a"

  abbreviation stutter_extend_enex 
    :: "('s⇒'a set) × ('a ⇒ 's ⇒ 's) ⇒ ('s ⇒ 'a option set) × ('a option ⇒ 's ⇒ 's)"
  where
   "stutter_extend_enex ≡ map_prod stutter_extend_en stutter_extend_ex"
  
  lemma stutter_extend_pred_of_enex_conv:
    "stutter_extend_edges UNIV (rel_of_enex enex) = rel_of_enex (stutter_extend_enex enex)"
    unfolding rel_of_enex_def stutter_extend_edges_def
    apply (auto simp: stutter_extend_en_def stutter_extend_ex_def split: prod.splits)
    apply force
    apply blast
    done
  
  lemma stutter_extend_en_Some_eq[simp]:
    "Some a ∈ stutter_extend_en en gc ⟷ a ∈ en gc"
    "stutter_extend_ex ex (Some a) gc = ex a gc"
    unfolding stutter_extend_en_def stutter_extend_ex_def by auto
  
  lemma stutter_extend_ex_None_eq[simp]:
    "stutter_extend_ex ex None = id"
    unfolding stutter_extend_ex_def by auto

end