Theory Labeled_Transition_System

(* Authors: Tassilo Lemke, Tobias Nipkow *)

section‹Labeled Transition System›

text ‹This theory could be unified with AFP/Labeled_Transition_Systems›

theory Labeled_Transition_System
  imports Main
begin

text ‹Labeled Transition Systems are sets of triples of type @{typ "'s × 'a × 's"}.›

type_synonym ('s, 'l) lts = "('s × 'l × 's) set"

text‹The following lemma ensure that Isabelle can evaluate set comprehensions over triples.›
lemma Collect_triple_code[code_unfold]:
  "{(x,y,z)  A. P x y z} = {p  A. P (fst p) (fst (snd p)) (snd (snd p))}"
  by fastforce

subsection‹Step Relations›

text‹
  A step from a state q› over a single symbol c› is the set of all q'›, such that (q, c, q') ∈ T›:
›

definition step_lts :: "('s, 'l) lts  'l  's  's set" where
  "step_lts T c s = (λ(q, c, q'). q') ` {(q, c', q')  T. c = c'  q = s}"

text‹
  A step of a single symbol c› from a set of states S› is the union of @{const step_lts} over S›:
›

definition Step_lts :: "('s, 'l) lts  'l  's set  's set" where
  "Step_lts T c S = (step_lts T c ` S)"

text‹
  Repeated steps of a word w› consisting of multiple letters is achieved using a standard @{term fold}:
›

definition Steps_lts :: "('s, 'l) lts  'l list  's set  's set" where
  "Steps_lts T w s = fold (Step_lts T) w s"

text‹Often, merely a single starting-state is of relevance:›

abbreviation steps_lts :: "('s, 'l) lts  'l list  's  's set" where
  "steps_lts T w s  Steps_lts T w {s}"

lemmas steps_lts_defs = step_lts_def Step_lts_def Steps_lts_def

text‹
  We now prove some key properties of this step relation:
›

lemma Step_union: "Step_lts T w (S1  S2) = Step_lts T w S1  Step_lts T w S2"
  unfolding Step_lts_def by blast

lemma Steps_lts_mono: "s1  s2  Steps_lts T w s1  Steps_lts T w s2"
proof (induction w arbitrary: s1 s2)
  case Nil thus ?case by (simp add: Steps_lts_def)
next
  case (Cons w ws)

  define s1' where [simp]: "s1'  Step_lts T w s1"
  define s2' where [simp]: "s2'  Step_lts T w s2"
  
  have "s1'  s2'"
    by (simp add: Step_lts_def, use s1  s2 in blast)
  then have "Steps_lts T ws s1'  Steps_lts T ws s2'"
    by (elim Cons.IH)
  moreover have "Steps_lts T (w#ws) s1 = Steps_lts T ws s1'"
    by (simp add: Steps_lts_def)
  moreover have "Steps_lts T (w#ws) s2 = Steps_lts T ws s2'"
    by (simp add: Steps_lts_def)
  ultimately show ?case
    by simp
qed

lemma Steps_lts_mono2:
  assumes "T1  T2" and "q1  q2"
  shows "Steps_lts T1 w q1  Steps_lts T2 w q2"
using assms(2) proof (induction w arbitrary: q1 q2)
  case Nil thus ?case by (simp add: Steps_lts_def)
next
  case (Cons w ws)
  have "Step_lts T1 w q1  Step_lts T2 w q2"
    unfolding steps_lts_defs using assms(1) Cons(2) by blast
  then have "Steps_lts T1 ws (Step_lts T1 w q1)  Steps_lts T1 ws (Step_lts T2 w q2)"
    by (rule Steps_lts_mono)
  then have "Steps_lts T1 ws (Step_lts T1 w q1)  Steps_lts T2 ws (Step_lts T2 w q2)"
    using Cons(1) by blast
  then show ?case
    by (simp add: Steps_lts_def)
qed

lemma steps_lts_mono: "T1  T2  steps_lts T1 w q  steps_lts T2 w q"
  using Steps_lts_mono2[of T1 T2 "{q}" "{q}" w] by simp

lemma steps_lts_mono': "T1  T2  q'  steps_lts T1 w q  q'  steps_lts T2 w q"
proof -
  assume "T1  T2"
  then have "steps_lts T1 w q  steps_lts T2 w q"
    by (rule steps_lts_mono)
  then show "q'  steps_lts T1 w q  q'  steps_lts T2 w q"
    by blast
qed

lemma steps_lts_union: "q'  steps_lts T w q  q'  steps_lts (T  T') w q"
proof -
  have "T  (T  T')"
    by simp
  then show "q'  steps_lts T w q  q'  steps_lts (T  T') w q"
    by (rule steps_lts_mono')
qed

lemma Steps_lts_path:
  assumes "qf  Steps_lts T w s"
  shows "q0  s. qf  steps_lts T w q0"
proof (insert assms; induction w arbitrary: s)
  case Nil thus ?case by (simp add: Steps_lts_def)
next
  case (Cons w ws)
  then have "qf  Steps_lts T ws (Step_lts T w s)"
    by (simp add: Steps_lts_def)
  moreover obtain q0 where "q0  (Step_lts T w s)" and "qf  steps_lts T ws q0"
    using Cons.IH calculation by blast
  ultimately obtain q' where "q0  step_lts T w q'" and "q'  s"
    unfolding steps_lts_defs by blast

  note q0  step_lts T w q' and qf  steps_lts T ws q0
  then have "qf  Steps_lts T ws (step_lts T w q')"
    using Steps_lts_mono[of "{q0}"] by blast
  moreover have "Steps_lts T ws (step_lts T w q') = steps_lts T (w#ws) q'"
    by (simp add: steps_lts_defs)
  ultimately show ?case
    using q'  s by blast
qed

lemma Steps_lts_split:
  assumes "qf  Steps_lts T (w1@w2) Q0"
  shows "q'. q'  Steps_lts T w1 Q0  qf  steps_lts T w2 q'"
proof -
  define Qf where [simp]: "Qf = Steps_lts T (w1@w2) Q0"
  define Q' where [simp]: "Q' = Steps_lts T w1 Q0"
  have "Qf = Steps_lts T w2 Q'"
    by (simp add: Steps_lts_def)
  then obtain q' where "q'  Q'" and "qf  steps_lts T w2 q'"
    using assms Steps_lts_path by force
  moreover have "q'  Steps_lts T w1 Q0"
    using calculation by simp
  ultimately show ?thesis
    by blast
qed

lemma Steps_lts_join:
  assumes "q'  Steps_lts T w1 Q0" and "qf  steps_lts T w2 q'"
  shows "qf  Steps_lts T (w1@w2) Q0"
proof -
  define Q' where [simp]: "Q' = Steps_lts T w1 Q0"
  define Qf where [simp]: "Qf = Steps_lts T w2 Q'"

  have "{q'}  Q'"
    using assms(1) by simp
  then have "Steps_lts T w2 {q'}  Steps_lts T w2 Q'"
    using Steps_lts_mono by blast
  then have "qf  Steps_lts T w2 Q'"
    using assms(2) by fastforce
  moreover have "Qf = Steps_lts T (w1@w2) Q0"
    by (simp add: Steps_lts_def)
  ultimately show ?thesis
    by simp
qed

lemma Steps_lts_split3:
  assumes "qf  Steps_lts T (w1@w2@w3) Q0"
  shows "q' q''. q'  Steps_lts T w1 Q0  q''  steps_lts T w2 q'  qf  steps_lts T w3 q''"
proof -
  obtain q' where "q'  Steps_lts T (w1@w2) Q0  qf  steps_lts T w3 q'"
    using assms Steps_lts_split[where w1 = "w1@w2"] by fastforce
  moreover then obtain q'' where "q''  Steps_lts T w1 Q0  q'  steps_lts T w2 q''"
    using Steps_lts_split by fast
  ultimately show ?thesis
    by blast
qed

lemma Steps_lts_join3:
  assumes "q'  steps_lts T w1 q0" and "q''  steps_lts T w2 q'" and "qf  steps_lts T w3 q''"
  shows "qf  steps_lts T (w1@w2@w3) q0"
proof -
  have "qf  steps_lts T (w2@w3) q'"
    using assms(2) assms(3) Steps_lts_join by fast
  moreover then have "qf  steps_lts T (w1@w2@w3) q0"
    using assms(1) Steps_lts_join by fast
  ultimately show ?thesis
    by blast
qed

lemma Steps_lts_noState: "Steps_lts T w {} = {}"
proof (induction w)
  case Nil
  then show ?case
    by (simp add: Steps_lts_def)
next
  case (Cons w ws)
  moreover have "Steps_lts T [w] {} = {}"
    by (simp add: steps_lts_defs)
  ultimately show ?case
    by (simp add: Steps_lts_def)
qed


subsection‹Reachable States›

definition reachable_from :: "('s, 'l) lts  's  's set" where
  "reachable_from T q  {q'. w. q'  steps_lts T w q}"

lemma reachable_from_computable: "reachable_from T q  {q}  (snd ` snd ` T)"
proof
  fix q'
  assume "q'  reachable_from T q"
  then obtain w where w_def: "q'  steps_lts T w q"
    unfolding reachable_from_def by blast
  then consider "w = []" | "ws c. w = ws@[c]"
    by (meson rev_exhaust)
  then show "q'  {q}  (snd ` snd ` T)"
  proof (cases)
    case 1
    then show ?thesis
      using w_def Steps_lts_def by force
  next
    case 2
    then obtain ws c where "w = ws@[c]"
      by blast
    then obtain q1 where "q1  steps_lts T ws q" and "q'  steps_lts T [c] q1"
      using Steps_lts_split w_def by fast
    then have "(q1, c, q')  T"
      by (auto simp: steps_lts_defs)
    then show ?thesis
      by force
  qed
qed

lemma reachable_from_trans[trans]:
  assumes "q1  reachable_from T q0" and "q2  reachable_from T q1"
  shows "q2  reachable_from T q0"
  using assms Steps_lts_join unfolding reachable_from_def by fast

lemma reachable_add_trans:
  assumes "(q1, _, q2)  T'. w. q2  steps_lts T w q1"
  shows "reachable_from T q = reachable_from (T  T') q"
proof (standard; standard)
  fix q'
  assume "q'  reachable_from T q"
  then show "q'  reachable_from (T  T') q"
    unfolding reachable_from_def using steps_lts_union by fast
next
  fix q'
  assume "q'  reachable_from (T  T') q"
  then obtain w where "q'  steps_lts (T  T') w q"
    unfolding reachable_from_def by blast
  then have "w'. q'  steps_lts T w' q"
  proof (induction w arbitrary: q)
    case Nil
    then have "q = q'" and "q  steps_lts T [] q"
      unfolding Steps_lts_def by simp+
    then show ?case
      by blast
  next
    case (Cons c w)
    then obtain q1 where "q'  steps_lts (T  T') w q1" and "q1  steps_lts (T  T') [c] q"
      using Steps_lts_split[where w1="[c]" and w2=w] by force
    then obtain w' where w'_def: "q'  steps_lts T w' q1"
      using Cons by blast

    have "q1  step_lts (T  T') c q"
      using q1  steps_lts (T  T') [c] q by (simp add: steps_lts_defs)
    then consider "q1  step_lts T c q" | "q1  step_lts T' c q"
      unfolding step_lts_def by blast
    then show ?case
    proof (cases)
      case 1
      then have "q1  steps_lts T [c] q"
        by (simp add: steps_lts_defs)
      then have "q'  steps_lts T (c#w') q"
        using w'_def Steps_lts_join by force
      then show ?thesis
        by blast
    next
      case 2
      then have "(q, c, q1)  T'"
        by (auto simp: step_lts_def)
      then obtain w'' where "q1  steps_lts T w'' q"
        using assms by blast
      then have "q'  steps_lts T (w''@w') q"
        using w'_def Steps_lts_join by fast
      then show ?thesis
        by blast
    qed
  qed
  then show "q'  reachable_from T q"
    by (simp add: reachable_from_def)
qed


definition states_lts :: "('s,'a)lts  's set" where
"states_lts T = ((p,a,q)T. {p,q})"

lemma Step_states_lts: "states_lts T  Q  Q0  Q  Step_lts T a Q0  Q"
  unfolding Step_lts_def step_lts_def states_lts_def by auto

lemma Steps_states_lts: assumes "states_lts T  Q" shows "Q0  Q  Steps_lts T u Q0  Q"
  unfolding Steps_lts_def
  apply(induction u arbitrary: Q0)
   apply simp
  using assms by (simp add: Step_states_lts)

corollary steps_states_lts: " states_lts T  Q; q  Q   steps_lts T u q  Q"
  using Steps_states_lts[of T Q "{q}"] by blast

lemma states_lts_Un: "states_lts (T  T') = states_lts T  states_lts T'"
  unfolding states_lts_def by auto


subsection‹Language›

abbreviation accepts_lts :: "('s, 'l) lts  's  's set  'l list  bool" where
  "accepts_lts T s F w  (steps_lts T w s  F  {})"

abbreviation Lang_lts :: "('s, 'l) lts  's  's set  ('l list) set" where
  "Lang_lts T S F  { w. accepts_lts T S F w }"

(* unused
lemma Lang_lts_trans:
  assumes "s' ∈ steps_lts T w1 s" and "w2 ∈ Lang_lts T s' F"
  shows "(w1@w2) ∈ Lang_lts T s F"
proof -
  obtain qf where "qf ∈ steps_lts T w2 s'" and "qf ∈ F"
    using assms(2) by blast
  moreover have "qf ∈ steps_lts T (w1@w2) s"
    using assms(1) ‹qf ∈ steps_lts T w2 s'› by (rule Steps_lts_join)
  ultimately show ?thesis
    using ‹qf ∈ F› by blast
qed

lemma Lang_lts_split:
  assumes "(w1@w2) ∈ Lang_lts T q F"
  obtains q' where "q' ∈ steps_lts T w1 q" and "w2 ∈ Lang_lts T q' F"
proof -
  obtain qf where "qf ∈ steps_lts T (w1@w2) q" and "qf ∈ F"
    using assms by blast
  then obtain q' where "q' ∈ steps_lts T w1 q" and "qf ∈ steps_lts T w2 q'"
    using Steps_lts_split by fast
  moreover then have "w2 ∈ Lang_lts T q' F"
    using ‹qf ∈ F› by blast
  ultimately show ?thesis
    using that by blast
qed

lemma Lang_steps_lts_mono: "T1 ⊆ T2 ⟹ Lang_lts T1 s f ⊆ Lang_lts T2 s f"
  using steps_lts_mono[of T1 T2] by fast
*)

end