Theory Networks

theory Networks
  imports Timed_Automata.Timed_Automata Munta_Base.Normalized_Zone_Semantics_Impl
    Munta_Base.Reordering_Quantifiers Munta_Base.TA_Syntax_Bundles
begin

unbundle no_library_syntax

section ‹Networks of Timed Automata›

subsection ‹Syntax and Operational Semantics›

text ‹Input, output and internal transitions›

datatype 'a act = In 'a | Out 'a | Sil 'a

datatype 'b label = Del | Act 'b | Syn 'b 'b

type_synonym
  ('a, 'b, 'c, 't, 's) nta = "('a act * 'b, 'c, 't, 's) ta list"

inductive step_n ::
  "('a, 'b, 'c, 't, 's) nta  's list  ('c, ('t::time)) cval  'b label
   's list  ('c, 't) cval  bool"
("_ N _, _ →⇘_ _,_" [61,61,61,61,61,61] 61)
where
  step_n_t:
    " p  {..<length N}. N!p  L!p, u →⇗dL!p, u  d; d  0
     N N L, u →⇘DelL, u  d" |
  step_n_i:
    "
      N!p  l ⟶⇗g,(Sil a, b),rl'; u  g;  p  {..<length N}. u'  inv_of (N!p) (L'!p);
      L!p = l; p < length L; L' = L[p := l']; u' = [r0]u
     
     N N L, u →⇘Act bL', u'" |
  step_n_s:
    "N!p  l1 ⟶⇗g1,(In a, b1),r1l1'; N!q  l2 ⟶⇗g2,(Out a, b2),r2l2'; u  g1; u  g2;
       p  {..<length N}. u'  inv_of (N!p) (L'!p);
      L!p = l1; L!q = l2; p < length L; q < length L; p  q;
      L' = L[p := l1', q := l2']; u' = [(r1 @ r2)0]u
       N N L, u →⇘Syn b1 b2L', u'"

inductive_cases[elim!]: "N N L, u →⇘aL', u'"

inductive steps_n ::
  "('a, 'b, 'c, 't, 's) nta  's list  ('c, ('t::time)) cval
   's list  ('c, 't) cval  bool"
("_ N _, _ →* _,_" [61,61,61] 61)
where
  refl: "N N l, Z →* l, Z" |
  step: "N N l, Z →* l', Z'  N N l', Z' →⇘_l'', Z''
         N N l, Z →* l'', Z''"

declare steps_n.intros[intro]

lemma stepI2:
  "N N l, Z →* l'', Z''" if "N N l', Z' →* l'', Z''" "N N l, Z →⇘bl', Z'"
  using that
  apply induction
   apply (rule steps_n.step)
    apply (rule refl)
   apply assumption
  apply simp
  by (rule steps_n.step; assumption)

lemma step_n_t_I:
  " p  {..<length N}. u  inv_of (N!p) (L!p);  p  {..<length N}. u  d  inv_of (N!p) (L!p);
    d  0
     N N L, u →⇘DelL, u  d"
by (auto intro: step_n_t)

subsection ‹Product Automaton›

abbreviation state_set :: "('a, 'c, 'time, 's) transition set  's set" where
  "state_set T  fst ` T  (snd o snd o snd o snd) ` T"

lemma guard_concat:
  assumes " g  set xs. u  g"
  shows "u  concat xs"
  using assms by (induction xs) (auto simp: clock_val_def)

lemma guard_append:
  assumes "u  g1" "u  g2"
  shows "u  g1 @ g2"
  using assms by (auto simp: clock_val_def)

lemma concat_guard:
  assumes "u  concat xs" "g  set xs"
  shows "u  g"
using assms by (auto simp: list_all_iff clock_val_def)

lemma guard_consE:
  assumes "u  ac # cc"
  obtains "u a ac" "u  cc"
  using assms unfolding clock_val_def by auto

lemma guard_consI:
  assumes "u a ac" "u  cc"
  shows "u  ac # cc"
  using assms unfolding clock_val_def by auto

lemma collect_clock_pairs_append_cases:
  assumes "x  collect_clock_pairs (g1 @ g2)"
  shows "x  collect_clock_pairs g1  x  collect_clock_pairs g2"
    using assms unfolding collect_clock_pairs_def by auto

lemma list_update_nth_split:
  assumes "j < length xs"
  shows "P (xs[i := x] ! j) = ((i = j  P x)  (i  j  P (xs ! j)))"
    using assms by (cases "i = j") auto

locale Product_TA_Defs =
  fixes N :: "('a, 'b, 'c, 't, 's) nta"
begin

  abbreviation "T  map trans_of N"
  abbreviation "I  map inv_of N"

  definition "states = {L. length L = length T  ( p  {..<length T}. L!p  state_set (T!p))}"

  definition
    "product_trans_i =
      {(L,g,(a,Act b),r,L[p:=l']) | L p g a b r l'.
      L  states  (L!p, g, (Sil a, b), r, l')  T!p  p < length L}"

  definition
    "product_trans_s =
      {(L,g1 @ g2,(a,Syn b1 b2),r1 @ r2,L[p:=l1',q:=l2']) | L p q g1 g2 a b1 b2 r1 r2 l1' l2'.
        L  states  (L!p, g1, (In a, b1), r1, l1')  T!p  (L!q, g2, (Out a, b2), r2, l2')  T!q
         p < length L  q < length L  p  q
      }"

  definition
    "product_trans  product_trans_i  product_trans_s"

lemma product_state_set_subs:
  assumes "q < length N" "l  state_set product_trans"
  shows "l ! q  state_set (T ! q)"
  using assms
  unfolding product_trans_def product_trans_i_def product_trans_s_def states_def
  apply safe
     apply (solves auto)
    apply (solves auto)
  apply simp
   apply (subst list_update_nth_split; force)
  apply simp
  apply (subst list_update_nth_split)
   apply simp
  apply safe
   apply (subst (asm) (2) list_update_nth_split; force)
  apply (subst list_update_nth_split)
   apply simp
  by (subst (asm) (2) list_update_nth_split; force) ― ‹slow: 13s›

  definition
    "product_invariant L 
    concat (map (λ p. if p < length I then (I!p) (L!p) else []) [0..<length L])"

  definition product_ta :: "('a × 'b label, 'c, 't, 's list) ta" where
    "product_ta  (product_trans, product_invariant)"

  lemma collect_clki_product_invariant:
    "Timed_Automata.collect_clki product_invariant =  (Timed_Automata.collect_clki ` set I)"
    unfolding Timed_Automata.collect_clki_def product_invariant_def
    apply (simp add: image_Union)
    apply safe
    subgoal
      unfolding collect_clock_pairs_def by fastforce
    apply clarsimp
    subgoal premises prems for a b aa ba x
    proof -
      let ?L = "map (λ _. x) [0..<length N]"
      let ?x = "collect_clock_pairs
        (concat
        (map (λp. if p < length N then (I ! p) (?L ! p) else [])
        [0..<length ?L]))"
      show ?thesis
        apply (intro exI[where x = ?x] conjI)
         apply (rule exI; rule HOL.refl)
        apply simp
        using prems unfolding collect_clock_pairs_def by (fastforce dest: mem_nth)
    qed
    done

  lemma states_length:
    assumes "L  states"
    shows "length L = length N"
    using assms unfolding states_def by auto

  lemma collect_clkt_product_trans_subs:
    "Timed_Automata.collect_clkt product_trans   (Timed_Automata.collect_clkt ` set T)"
    unfolding
      Timed_Automata.collect_clkt_def product_trans_def product_trans_i_def product_trans_s_def
    by (fastforce dest: collect_clock_pairs_append_cases states_length)

  lemma collect_clkvt_product_trans_subs:
    "collect_clkvt product_trans   (collect_clkvt ` set T)"
    unfolding collect_clkvt_def product_trans_def product_trans_i_def product_trans_s_def
    by (fastforce dest: states_length)

  lemma statesI_aux:
    fixes L
    assumes L: "L  states"
    assumes
      "p < length T"
      "(l, g, a, r, l')  T ! p"
    shows "(L[p := l])  states"
    unfolding states_def apply clarsimp
    using L apply (simp add: states_def)
    apply safe
    apply (subst list_update_nth_split)
    using assms by (fastforce simp: states_def)+

  lemma product_trans_s_alt_def:
    "product_trans_s =
      {(L, g, (a, Syn b1 b2), r, L') | L g a b1 b2 r L'.  p q g1 g2 r1 r2 l1' l2'.
      L  states  p < length L  q < length L  p  q 
      g = g1 @ g2  r = r1 @ r2  L' = L[p:=l1', q:=l2']
         (L!p, g1, (In a, b1), r1, l1')  T!p  (L!q, g2, (Out a, b2), r2, l2')  T!q
      }"
    unfolding product_trans_s_def by (safe; metis)

  context
    assumes states_not_empty: "states  {}"
    assumes trans_complete:
      " p < length T.  t1  T ! p. case t1 of (l1, g1, (In a, b1), r1, l1')
        q < length T. p  q  ( l2 g2 b2 r2 l2'. (l2, g2, (Out a, b2), r2, l2')  T ! q) |
      (l1, g1, (Out a, b1), r1, l1')
        q < length T. p  q  ( l2 g2 b2 r2 l2'. (l2, g2, (In a, b2), r2, l2')  T ! q) | _  True"
  begin

  lemma collect_clkt_product_trans_sups:
    "Timed_Automata.collect_clkt product_trans   (Timed_Automata.collect_clkt ` set T)"
  proof
    fix x assume "x   (Timed_Automata.collect_clkt ` set T)"
    then obtain trans l1 g1 a' b1 r1 l1' where x:
      "trans  set T" "(l1, g1, (a', b1), r1, l1')  trans" "x  collect_clock_pairs g1"
      unfolding Timed_Automata.collect_clkt_def by force
    then obtain p where p:
        "p < length T" "T ! p = trans"
      by (auto dest!: mem_nth)
    from states_not_empty obtain L where L: "L  states" by auto
    have "length T = length L" by (auto simp: states_length[OF L  states])
    show "x  Timed_Automata.collect_clkt product_trans"
    proof (cases a')
      case a': (In a)
      with x p trans_complete obtain q l2 g2 b2 r2 l2' where trans2:
        "q < length T" "(l2, g2, (Out a, b2), r2, l2')  T ! q" "p  q"
        by atomize_elim fastforce
      have "L[p := l1, q := l2]  states" (is "?L  _")
        using L p(1) x(1,2) trans2 unfolding p(2)[symmetric] by (auto intro!: statesI_aux)
      moreover have "?L ! p = l1" "?L ! q = l2"
        using p  q p < length T q < length T L  states by (auto dest: states_length)
      moreover note t = calculation
      have "(?L, g1 @ g2, (a, Syn b1 b2), r1 @ r2, ?L[p := l1', q := l2'])  product_trans_s"
        unfolding product_trans_s_alt_def
        apply clarsimp
        using t p(1) x(1,2) trans2 unfolding p(2)[symmetric] a' length T = length L
        by metis
      moreover have "x  collect_clock_pairs (g1 @ g2)"
        using x(3) by (auto simp: collect_clock_pairs_def)
      ultimately show ?thesis unfolding Timed_Automata.collect_clkt_def product_trans_def by force
    next
      case a': (Out a)
      with x p trans_complete obtain q l2 g2 b2 r2 l2' where trans2:
        "q < length T" "(l2, g2, (In a, b2), r2, l2')  T ! q" "p  q"
        by atomize_elim fastforce
      have "L[q := l2, p := l1]  states" (is "?L  _")
        using L p(1) x(1,2) trans2 unfolding p(2)[symmetric] by (auto intro!: statesI_aux)
      moreover have "?L ! p = l1" "?L ! q = l2"
        using p  q p < length T q < length T L  states by (auto dest: states_length)
      moreover note t = calculation
      have "(?L, g2 @ g1, (a, Syn b2 b1), r2 @ r1, ?L[q := l2', p := l1'])  product_trans_s"
        unfolding product_trans_s_alt_def
        apply clarsimp
        using t p(1) x(1,2) trans2 unfolding p(2)[symmetric] a' length T = length L
        by metis
      moreover have "x  collect_clock_pairs (g2 @ g1)"
        using x(3) by (auto simp: collect_clock_pairs_def)
      ultimately show ?thesis unfolding Timed_Automata.collect_clkt_def product_trans_def by force
    next
      case a': (Sil a)
      have "L[p := l1]  states" (is "?L  _")
        using L p(1) x(1,2) unfolding p(2)[symmetric] by (auto intro!: statesI_aux)
      moreover have "?L ! p = l1"
        using p < length T L  states by (auto dest: states_length)
      ultimately have "(?L, g1, (a, Act b1), r1, ?L[p := l1'])  product_trans_i"
        using x p unfolding product_trans_i_def a' by (force simp: states_length[OF L  states])
      with x(3) show ?thesis unfolding Timed_Automata.collect_clkt_def product_trans_def by force
    qed
  qed

  lemma collect_clkvt_product_trans_sups:
    "collect_clkvt product_trans   (collect_clkvt ` set T)"
  proof
    fix x assume "x   (collect_clkvt ` set T)"
    then obtain trans l1 g1 a' b1 r1 l1' where x:
      "trans  set T" "(l1, g1, (a', b1), r1, l1')  trans" "x  set r1"
      unfolding collect_clkvt_def by force
    then obtain p where p:
        "p < length T" "T ! p = trans"
      by (auto dest!: mem_nth)
    from states_not_empty obtain L where L: "L  states" by auto
    show "x  collect_clkvt product_trans"
    proof (cases a')
      case a': (In a)
      with x p trans_complete obtain q l2 g2 b2 r2 l2' where trans2:
        "q < length T" "(l2, g2, (Out a, b2), r2, l2')  T ! q" "p  q"
        by atomize_elim fastforce
      moreover have "L[p := l1, q := l2]  states" (is "?L  _")
        using L p(1) x(1,2) trans2 unfolding p(2)[symmetric] by (auto intro!: statesI_aux)
      moreover have "?L ! p = l1" "?L ! q = l2"
        using p  q p < length T q < length T L  states by (auto dest: states_length)
      ultimately have
        "(?L, g1 @ g2, (a, Syn b1 b2), r1 @ r2, ?L[p := l1', q := l2'])  product_trans_s"
        using p(1) x trans2 unfolding p(2)[symmetric] a' product_trans_s_def
        by (fastforce simp: states_length[OF L  states])
      with x(3) show ?thesis unfolding collect_clkvt_def product_trans_def by force
    next
      case a': (Out a)
      with x p trans_complete obtain q l2 g2 b2 r2 l2' where trans2:
        "q < length T" "(l2, g2, (In a, b2), r2, l2')  T ! q" "p  q"
        by atomize_elim fastforce
      moreover have "L[q := l2, p := l1]  states" (is "?L  _")
        using L p(1) x(1,2) trans2 unfolding p(2)[symmetric] by (auto intro!: statesI_aux)
      moreover have "?L ! p = l1" "?L ! q = l2"
        using p  q p < length T q < length T L  states by (auto dest: states_length)
      ultimately have "(?L, g2 @ g1, (a, Syn b2 b1), r2 @ r1, ?L[q := l2', p := l1'])  product_trans_s"
        using p(1) x trans2 unfolding p(2)[symmetric] a' product_trans_s_def
        apply (simp add: states_length[OF L  states] del: ex_simps)
        apply (tactic rearrange_ex_tac @{context} 1)
        apply simp
        apply (rule exI, rule conjI, assumption)
        apply (simp only: ex_simps[symmetric])
        apply (tactic rearrange_ex_tac @{context} 1)
        apply simp
        by (fastforce simp: states_length[OF L  states])
          (* fastforce can solve this on its own but not very quickly *)
      with x(3) show ?thesis unfolding collect_clkvt_def product_trans_def by force
    next
      case a': (Sil a)
      have "L[p := l1]  states" (is "?L  _")
        using L p(1) x(1,2) unfolding p(2)[symmetric] by (auto intro!: statesI_aux)
      moreover have "?L ! p = l1"
        using p < length T L  states by (auto dest: states_length)
      ultimately have "(?L, g1, (a, Act b1), r1, ?L[p := l1'])  product_trans_i"
        using x p unfolding product_trans_i_def a' by (force simp: states_length[OF L  states])
      with x(3) show ?thesis unfolding collect_clkvt_def product_trans_def by force
    qed
  qed

  lemma collect_clkt_product_trans:
    "Timed_Automata.collect_clkt product_trans =  (Timed_Automata.collect_clkt ` set T)"
    using collect_clkt_product_trans_sups collect_clkt_product_trans_subs by simp

  lemma collect_clkvt_product_trans:
    "collect_clkvt product_trans =  (collect_clkvt ` set T)"
  using collect_clkvt_product_trans_sups collect_clkvt_product_trans_subs by simp

  end (* End of context for syntactic 1-to-1 correspondence for transitions *)

  context
    assumes finite_trans: " A  set N. finite (trans_of A)"
  begin

  lemma finite_states:
    "finite states"
  proof -
    have "states  {L. set L 
          ( {fst ` trans_of (N ! p) | p. p < length N} 
             {(snd  snd  snd  snd) ` trans_of (N ! p) | p. p < length N})
           length L = length N}"
      unfolding states_def
      apply clarsimp
      apply (drule mem_nth)
      apply safe
      subgoal for _ _ i
        by (erule ballE[where x = i]) auto
      done
    moreover have "finite " using finite_trans by - (rule finite_lists_length_eq; auto)
    ultimately show ?thesis by (rule finite_subset)
  qed

  lemma finite_product_trans_i:
    "finite product_trans_i"
  proof -
    let ?N = " (trans_of ` set N)"
    let ?S = "{(L, p, g, (a, Act b), r, l')|L p g a b r l'.
      L  states  (L ! p, g, (Sil a, b), r, l')  map trans_of N ! p  p < length L}"
    let ?R = "{(L, p, g, (a, Act b), r, l')|L p g a b r l'.
      L  states  p < length L  (g, (Sil a, b), r, l')  snd ` ?N}"
    have "?S  ?R" by (fastforce simp: states_length dest: nth_mem)
    moreover have "finite ?R" using finite_states [[simproc add: finite_Collect]]
      apply simp
      apply (rule finite_imageI)
      apply (rule finite_SigmaI)
       apply (rule finite_subset[where B = "{(p, L). p < length L  L  states}"])
        apply force
      using states_length
       apply -
       apply (rule finite_subset[where B = "{(p, L). p < length N  L  states}"]; fastforce)
      using finite_trans
      apply (intro finite_vimageI)
      unfolding inj_on_def by auto
    ultimately have "finite ?S" by (rule finite_subset)
    moreover have "product_trans_i = (λ (L, p, g, a, r, l'). (L, g, a, r, L[p := l'])) ` ?S"
      unfolding product_trans_i_def by (auto 4 3 simp: image_Collect)
    ultimately show ?thesis by auto
  qed

  lemma finite_Collect_bounded_ex_5' [simp]:
  assumes "finite {(a,b,c,d,e) . P a b c d e}"
  shows
    "finite {x. a b c d e. P a b c d e  Q x a b c d e}
     ( a b c d e. P a b c d e  finite {x. Q x a b c d e})"
  using assms finite_Collect_bounded_ex[OF assms, where Q = "λ x. λ (a, b, c, d, e). Q x a b c d e"]
  by clarsimp (* force, simp *)

  lemma finite_product_trans_s:
    "finite product_trans_s"
  proof -
    let ?N = " (trans_of ` set N)"
    have "(g1, (In a, b), r1, l1')  snd ` ?N" if
      "(L ! p, g1, (In a, b), r1, l1')  map trans_of N ! p" "p < length L" "L  states"
      for L p g1 a b r1 l1'
      using that by (auto simp: states_length dest: nth_mem)
    let ?S = "{(L, p, q, g1, g2, (a, Syn b1 b2), r1, r2, l1', l2')|L p q g1 g2 a b1 b2 r1 r2 l1' l2'.
      L  states  (L ! p, g1, (In a, b1), r1, l1')  map trans_of N ! p 
        (L ! q, g2, (Out a, b2), r2, l2')  map trans_of N ! q  p < length L  q < length L}"
    define F1 where "F1  {(g1, a, b, r1, l1') | g1 a b r1 l1'. (g1, (In a, b), r1, l1')  snd ` ?N}"
    have fin1: "finite F1" unfolding F1_def using finite_trans
      using [[simproc add: finite_Collect]] by (force simp: inj_on_def intro: finite_vimageI)
    define F2 where "F2  {(g1, a, b, r1, l1') | g1 a b r1 l1'. (g1, (Out a, b), r1, l1')  snd ` ?N}"
    have fin2: "finite F2" unfolding F2_def using finite_trans
      using [[simproc add: finite_Collect]] by (force simp: inj_on_def intro: finite_vimageI)
    define R where "R  {(L, p, q, g1, g2, (a, Syn b1 b2), r1, r2, l1', l2')|L p q g1 g2 a b1 b2 r1 r2 l1' l2'.
      L  states  p < length L  q < length L  (g1, a, b1, r1, l1')  F1  (g2, a, b2, r2, l2')  F2}"

    have R_alt_def: "R = {t.  L p q g1 a b1 r1 l1' g2 b2 r2 l2'.
      L  states  p < length L  q < length L
       (g1, a, b1, r1, l1')  F1  (g2, a, b2, r2, l2')  F2
       t = (L, p, q, g1, g2, (a, Syn b1 b2), r1, r2, l1', l2')
      }"
      unfolding R_def by auto
    have "?S  R" by (fastforce simp: R_alt_def F1_def F2_def states_length dest: nth_mem)
    moreover have "finite R"
      unfolding R_alt_def
      using fin1 fin2 finite_states
      using [[simproc add: finite_Collect]]
      by (auto simp: inj_on_def intro: finite_vimageI intro!: finite_imageI)
    ultimately have "finite ?S" by (rule finite_subset)
    moreover have
      "product_trans_s
       (λ (L, p, q, g1, g2, a, r1, r2, l1', l2').
          (L, g1 @ g2, a, r1 @ r2, L[p := l1', q := l2'])) ` ?S"
      unfolding product_trans_s_def by (simp add: image_Collect) blast
    ultimately show ?thesis by (auto intro: finite_subset)
  qed

  lemma finite_trans_of_product:
    shows "finite (trans_of product_ta)"
    using finite_product_trans_s finite_product_trans_i
    unfolding product_ta_def trans_of_def product_trans_def
    by auto

  end (* End of context for finiteness of trans *)

  lemma inv_of_product[simp]:
      "inv_of product_ta = product_invariant"
    unfolding product_ta_def inv_of_def by simp

  lemma concat_map_if_aux:
    assumes "(m :: nat)  n"
    shows "concat (map (λ i. if i < n then f i else []) [0..<m])
         = concat (map (λ i. if i < n then f i else []) [0..<n])"
    using assms by (induction rule: dec_induct) auto

  lemma finite_invariant_of_product[folded inv_of_product]:
    assumes " A  set N. finite (range (inv_of A))"
    shows "finite (range product_invariant)"
  proof -
    let ?N = " (range ` inv_of ` set N)"
    let ?X = "{I. set I  ?N  length I  length N}"
    have "[]  ?X" by auto
    have "finite ?N"
      using assms
      by auto
    then have "finite ?X" by (rule finite_lists_length_le)
    moreover have "range product_invariant  concat ` ?X"
    proof
      fix x assume "x  range product_invariant"
      then obtain L where L:
            "x = concat
                       (map (λp. if p < length (map inv_of N)
                                  then (map inv_of N ! p) (L ! p) else [])
                         [0..<length L])"
        unfolding product_invariant_def by auto
      show "x  concat ` ?X"
      proof (cases "length L  length N")
        case True
        then show ?thesis using L by (fastforce dest: nth_mem)
      next
        case False
        then have "x = concat
                       (map (λp. if p < length (map inv_of N)
                                  then (map inv_of N ! p) (L ! p) else [])
                         [0..<length N])"
          using L by (auto intro: concat_map_if_aux)
        then show ?thesis by (fastforce dest: nth_mem)
      qed
    qed
    ultimately show ?thesis by - (drule finite_subset; auto)
  qed

end (* End locale for product TA definition *)

locale Product_TA_Defs' =
  Product_TA_Defs N for N :: "('a, 'b, 'c, 't :: time, 's) nta"
begin

  lemma product_invariantD:
    assumes "u  product_invariant L" "p < length N" "length L = length N"
    shows "u  inv_of (N ! p) (L!p)"
  using assms unfolding product_invariant_def by (force intro: concat_guard)

  lemma states_step:
    "L'  states" if "N N L, u →⇘aL', u'" "L  states"
    using that unfolding states_def apply safe
        apply simp
       apply simp
      apply force
     apply (subst list_update_nth_split)
      apply simp
     apply (rule conjI)
      apply clarsimp
    subgoal premises prems for p g a r l'
      using prems(3-6) by force
     apply clarsimp
     apply (solves auto)
    apply (subst list_update_nth_split)
     apply (simp; fail)
    apply safe
     apply simp
    subgoal premises prems
      using prems(3-7) by force
    apply (subst list_update_nth_split)
     apply simp
    apply safe
     apply simp
    subgoal premises prems
      using prems(3-6) by force
    by auto

  lemma states_steps:
    "L'  states" if "N N L, u →* L', u'" "L  states"
    using that apply (induction N  N _ _ _ _ rule: steps_n.induct)
     apply assumption
    apply simp
    by (rule states_step; assumption)

end

lemma steps_altI:
  "A  l, Z →* l'', Z''" if
  "A  l, Z →* l', Z'" "A  l', Z'  l'', Z''"
  using that by (induction; blast)

(* Network + valid start state *)
locale Product_TA =
  Product_TA_Defs' N for N :: "('a, 'b, 'c, 't :: time, 's) nta" +
  fixes L :: "'s list"
  assumes states[intro]: "L  states"
begin

  lemma
    len[simp]: "length L = length N"
  using states unfolding states_def by auto

  lemma product_delay_complete:
    assumes step: "N N L, u →⇘DelL', u'"
    obtains d where "product_ta  L, u →⇗dL', u'"
  using step proof cases
    case prems: (step_n_t d)
    from prems have *:
      "p{..<length N}. u  d  inv_of (N ! p) (L ! p)"
    by (auto elim!: step_t.cases)
    from prems * show ?thesis
    by (fastforce simp add: product_ta_def inv_of_def product_invariant_def[abs_def]
                  intro!: guard_concat that
       )
  qed

  lemma product_int_complete:
    assumes step: "N N L, u →⇘Act bL', u'"
    obtains a where "product_ta  L, u →⇘(a, Act b)L', u'"
    using step proof cases
    case prems: (step_n_i p l g a r l')
    from prems show ?thesis
      apply -
      apply (rule that)
      apply (rule step_a.intros[where g = g and r = r])
      by (fastforce
          simp: product_trans_def product_trans_i_def product_invariant_def product_ta_def
          trans_of_def inv_of_def
          intro: guard_concat
          )+
  qed

  lemma product_sync_complete:
    assumes step: "N N L, u →⇘Syn b1 b2L', u'"
    obtains a where "product_ta  L, u →⇘(a, Syn b1 b2)L', u'"
    using step proof cases
    case prems: (step_n_s p l1 g1 a r1 l1' q l2 g2 r2 l2')
    from prems show ?thesis
      apply -
      apply (rule that)
      apply (rule step_a.intros[where g = "g1 @ g2" and a = "(a, Syn b1 b2)" and r = "r1 @ r2"])
      subgoal premises prems
        apply
          (clarsimp simp add:
            product_trans_def product_trans_s_def product_invariant_def product_ta_def
            trans_of_def inv_of_def
            )
        apply (erule allE[where x = p])
        using p < _ apply simp
        apply (erule allE[where x = q])
        using prems by (fastforce simp: trans_of_def)
      by (fastforce
            simp: product_invariant_def product_ta_def inv_of_def
            intro: guard_concat guard_append
         )+
  qed

  lemma product_complete:
    assumes step: "N N L, u →⇘bL', u'"
    shows "product_ta  L, u  L', u'"
    using step
    by (cases b) (rule product_delay_complete product_int_complete product_sync_complete, simp, blast)+

  lemma product_ta_cases:
    assumes "product_ta  L ⟶⇗g,a,rL'"
    shows "(L, g, a, r, L')  product_trans_i  (L, g, a, r, L')  product_trans_s"
  using assms unfolding product_ta_def trans_of_def product_trans_def by auto

  lemma product_delay_sound:
    assumes step: "product_ta  L, u →⇗dL', u'"
    shows "N N L, u →⇘DelL', u'"
  using assms by cases (force intro!: step_n_t product_invariantD len)

  lemma product_action_sound:
    assumes step: "product_ta  L, u →⇘(a, b)L', u'"
    shows "N N L, u →⇘bL', u'"
    using assms
    apply cases
    apply simp
    apply (drule product_ta_cases)
    apply (erule disjE)
    unfolding product_trans_i_def product_trans_s_def
     apply (solves auto intro!: product_invariantD step_n_i)
    by (auto intro!: product_invariantD step_n_s simp: clock_val_def)

  lemma product_sound:
    assumes step: "product_ta  L, u  L', u'"
    obtains a where "N N L, u →⇘aL', u'"
    using step by cases (force dest!: product_action_sound product_delay_sound)+

  lemma states_product_step[intro]:
    "L'  states" if "product_ta  L, u  L', u'"
    by (auto intro: product_sound that elim!: states_step)

  lemma product_steps_sound:
    "N N L, u →* L', u'" if "product_ta  L, u →* L', u'"
    using that states proof (induction A  product_ta _ _ _ _ rule: steps.induct)
    case (refl l u)
    then show ?case by blast
  next
    case prems: (step l u l' u' l'' u'')
    interpret interp: Product_TA N l by standard (rule prems)
    from prems have *: "N N l', u' →* l'',u''" by auto
    from prems show ?case by - (erule interp.product_sound, rule stepI2, rule *)
  qed

  lemma product_steps_complete:
    "product_ta  L, u →* L', u'" if "N N L, u →* L', u'"
    using that states proof (induction N  N _ _ _ _ rule: steps_n.induct)
    case (refl l Z)
    then show ?case by blast
  next
    case prems: (step l Z l' Z' _ l'' Z'')
    interpret interp: Product_TA N l' by standard (blast intro: prems states_steps)
    from prems show ?case by - (assumption | rule steps_altI interp.product_complete)+
  qed

  lemma product_correct:
    "product_ta  L, u →* L', u'  N N L, u →* L', u'"
    by (metis product_steps_complete product_steps_sound)

  end (* End context: network + valid start state *)

end (* End of theory *)