Theory Compactification_Synchronization_Product

(***********************************************************************************
 * Copyright (c) 2025 Université Paris-Saclay
 *
 * Author: Benoît Ballenghien, Université Paris-Saclay,
 *         CNRS, ENS Paris-Saclay, LMF
 * Author: Burkhart Wolff, Université Paris-Saclay,
 *         CNRS, ENS Paris-Saclay, LMF
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 ***********************************************************************************)


chapter ‹Compactification of Synchronization Product›

(*<*)
theory Compactification_Synchronization_Product
  imports Combining_Synchronization_Product Process_Normalization_Properties
begin
  (*>*)


section ‹Iterated Combine›

subsection ‹Definitions›

fun iterated_combined_Sync :: ‹'e set ⇒ ('σ, 'e, 'r) Ad list ⇒ ('σ list, 'e, 'r) Ad› (‹⟪d⨂⟦_⟧ _⟫› [0, 0])
  where ‹⟪d⨂⟦E⟧ []⟫ = ⦇τ = λσs a. ◇, ω = λσs. ◇⦈›
  |     ‹⟪d⨂⟦E⟧ [A0]⟫ = d⟪A0⟫σ↪σs›
  |     ‹⟪d⨂⟦E⟧ A0 # A1 # As⟫ = ⟪A0 d⊗⟦E⟧Rlist ⟪d⨂⟦E⟧ A1 # As⟫⟫›

fun iterated_combinend_Sync :: ‹'e set ⇒ ('σ, 'e, 'r) And list ⇒ ('σ list, 'e, 'r) And› (‹⟪nd⨂⟦_⟧ _⟫› [0, 0])
  where ‹⟪nd⨂⟦E⟧ []⟫ = ⦇τ = λσs a. {}, ω = λσs. {}⦈›
  |     ‹⟪nd⨂⟦E⟧ [A0]⟫ = nd⟪A0⟫σ↪σs›
  |     ‹⟪nd⨂⟦E⟧ A0 # A1 # As⟫ = ⟪A0 nd⊗⟦E⟧Rlist ⟪nd⨂⟦E⟧ A1 # As⟫⟫›


lemma iterated_combined_Sync_simps_bis: ‹As ≠ [] ⟹ ⟪d⨂⟦E⟧ A0 # As⟫ = ⟪A0 d⊗⟦E⟧Rlist ⟪d⨂⟦E⟧ As⟫⟫›
  and iterated_combinend_Sync_simps_bis: ‹Bs ≠ [] ⟹ ⟪nd⨂⟦E⟧ B0 # Bs⟫ = ⟪B0 nd⊗⟦E⟧Rlist ⟪nd⨂⟦E⟧ Bs⟫⟫›
  by (induct As, simp_all) (induct Bs, simp_all)


fun iterated_combined_Sync_ε :: ‹('σ, 'e, 'r, 'α) Ad_scheme list ⇒ 'e set ⇒ 'σ list ⇒ 'e set›
  where ‹iterated_combined_Sync_ε [] E σs = {}› 
  |     ‹iterated_combined_Sync_ε [A0] E σs = ε A0 (hd σs)›
  |     ‹iterated_combined_Sync_ε (A0 # A1 # As) E σs = 
         combine_sets_Sync (ε A0 (hd σs)) E (iterated_combined_Sync_ε (A1 # As) E (tl σs))›

fun iterated_combinend_Sync_ε :: ‹('σ, 'e, 'r, 'α) And_scheme list ⇒ 'e set ⇒ 'σ list ⇒ 'e set›
  where ‹iterated_combinend_Sync_ε [] E σs = {}› 
  |     ‹iterated_combinend_Sync_ε [A0] E σs = ε A0 (hd σs)›
  |     ‹iterated_combinend_Sync_ε (A0 # A1 # As) E σs = 
         combine_sets_Sync (ε A0 (hd σs)) E (iterated_combinend_Sync_ε (A1 # As) E (tl σs))›


lemma iterated_combined_Sync_ε_simps_bis:
  ‹As ≠ [] ⟹ iterated_combined_Sync_ε (A0 # As) E σs = 
                combine_sets_Sync (ε A0 (hd σs)) E (iterated_combined_Sync_ε As E (tl σs))›
  and iterated_combinend_Sync_ε_simps_bis: 
  ‹Bs ≠ [] ⟹ iterated_combinend_Sync_ε (B0 # Bs) E σs = 
                 combine_sets_Sync (ε B0 (hd σs)) E (iterated_combinend_Sync_ε Bs E (tl σs))›
  by (induct As, simp_all) (induct Bs, simp_all)



subsection ‹First Results›

lemma ε_iterated_combined_Sync:
  ‹length σs = length As ⟹ ε ⟪d⨂⟦E⟧ As⟫ σs = iterated_combined_Sync_ε As E σs›
  by (induct σs As rule: induct_2_lists012)
    (simp_all add: ε_combineRlist_Sync combine_Sync_ε_def)

lemma ε_iterated_combinend_Sync:
  ‹length σs = length Bs ⟹ ε ⟪nd⨂⟦E⟧ Bs⟫ σs = iterated_combinend_Sync_ε Bs E σs›
  by (induct σs Bs rule: induct_2_lists012)
    (simp_all add: ε_combineRlist_Sync combine_Sync_ε_def)


lemma combineListslenL_Sync_combineRlist_Sync_eq:
  ‹ε ⟪d⟪A0⟫σ↪σs d⊗⟦1, E⟧ListslenL A1⟫ σs = ε ⟪A0 d⊗⟦E⟧Rlist A1⟫ σs›
  ‹τ ⟪d⟪A0⟫σ↪σs d⊗⟦1, E⟧ListslenL A1⟫ (s0 # σs) e = τ ⟪A0 d⊗⟦E⟧Rlist A1⟫ (s0 # σs) e›
  ‹ε ⟪nd⟪B0⟫σ↪σs nd⊗⟦1, E⟧ListslenL B1⟫ σs = ε ⟪B0 nd⊗⟦E⟧Rlist B1⟫ σs›
  ‹τ ⟪nd⟪B0⟫σ↪σs nd⊗⟦1, E⟧ListslenL B1⟫ (s0 # σs) e = τ ⟪B0 nd⊗⟦E⟧Rlist B1⟫ (s0 # σs) e›
  by (simp_all add: ε_combineListslenL_Sync ε_combineRlist_Sync drop_Suc combine_Sync_ε_def,
      auto simp add: combineListslenL_Sync_defs combineRlist_Sync_defs σ_σs_conv_defs ε_simps) 
    (metis append_Cons append_Nil)



lemma combinePairlist_Sync_and_iterated_combinend_Sync_eq:
  ‹ε ⟪A0 d⊗⟦E⟧Pairlist A1⟫ [s0, s1] = ε ⟪d⨂⟦E⟧ [A0, A1]⟫ [s0, s1]›
  ‹τ ⟪A0 d⊗⟦E⟧Pairlist A1⟫ [s0, s1] e = τ ⟪d⨂⟦E⟧ [A0, A1]⟫ [s0, s1] e›
  ‹ε ⟪B0 nd⊗⟦E⟧Pairlist B1⟫ [s0, s1] = ε ⟪nd⨂⟦E⟧ [B0, B1]⟫ [s0, s1]›
  ‹τ ⟪B0 nd⊗⟦E⟧Pairlist B1⟫ [s0, s1] e = τ ⟪nd⨂⟦E⟧ [B0, B1]⟫ [s0, s1] e›
  by (simp_all add: ε_combinePairlist_Sync ε_combineRlist_Sync)
    (auto simp add: combinePairlist_Sync_defs combineRlist_Sync_defs σ_σs_conv_defs 
      option.case_eq_if ε_simps combine_Sync_ε_def)



lemmas combinePairlist_Sync_and_combineRlist_Sync_eq =
  combinePairlist_Sync_and_iterated_combinend_Sync_eq[simplified]



subsection ‹Reachability›

lemma same_length_ℛd_iterated_combined_Sync_description:
  ‹length σs = length As ⟹ σs' ∈ ℛd ⟪d⨂⟦E⟧ As⟫ σs ⟹
   length σs' = length As ∧ (∀i < length As. σs' ! i ∈ ℛd (As ! i) (σs ! i))›
proof (induct σs As arbitrary: σs' rule: induct_2_lists012)
  case Nil thus ?case by simp
next
  case (single σ1 A1)
  thus ?case by (auto simp add: ℛd_from_σ_to_σs_description)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  from set_mp[OF ℛd_combinedRlist_Sync_subset, OF Cons.prems[simplified]]
  obtain σ1' σs'' where ‹σs' = σ1' # σs''› ‹σ1' ∈ ℛd A1 σ1›
    ‹σs'' ∈ ℛd ⟪d⨂⟦E⟧ A2 # As⟫ (σ2 # σs)› by blast
  from Cons.hyps(3)[OF this(3)] this(1, 2)
  show ?case using less_Suc_eq_0_disj nth_Cons_0 nth_Cons_Suc by simp auto
qed


lemma same_length_ℛnd_iterated_combinend_Sync_description:
  ‹length σs = length Bs ⟹ σs' ∈ ℛnd ⟪nd⨂⟦E⟧ Bs⟫ σs ⟹
   length σs' = length Bs ∧ (∀i < length Bs. σs' ! i ∈ ℛnd (Bs ! i) (σs ! i))›
proof (induct σs Bs arbitrary: σs' rule: induct_2_lists012)
  case Nil thus ?case by simp
next
  case (single σ1 B1)
  thus ?case by (auto simp add: ℛnd_from_σ_to_σs_description)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  from set_mp[OF ℛnd_combinendRlist_Sync_subset, OF Cons.prems[simplified]]
  obtain σ1' σs'' where ‹σs' = σ1' # σs''› ‹σ1' ∈ ℛnd A1 σ1›
    ‹σs'' ∈ ℛnd ⟪nd⨂⟦E⟧ A2 # As⟫ (σ2 # σs)› by blast
  from Cons.hyps(3)[OF this(3)] this(1, 2)
  show ?case using less_Suc_eq_0_disj nth_Cons_0 nth_Cons_Suc by simp auto
qed



subsection ‹Transmission of Properties›

lemma finite_trans_transmission_to_iterated_combinend_Sync:
  ‹(⋀A. A ∈ set As ⟹ finite_trans A) ⟹ finite_trans ⟪nd⨂⟦E⟧ As⟫›
  by (induct As rule: induct_list012) 
    (auto simp add: σ_σs_conv_defs combineRlist_Sync_defs finite_trans_def finite_image_set2)

lemma ρ_disjoint_ε_transmission_to_iterated_combined_Sync:
  ‹(⋀A. A ∈ set As ⟹ ρ_disjoint_ε A) ⟹ ρ_disjoint_ε ⟪d⨂⟦E⟧ As⟫›
  by (induct As rule: induct_list012)
    (simp_all add: ρ_combineRlist_Sync ε_combineRlist_Sync ρ_disjoint_ε_def combine_Sync_ε_def)

lemma ρ_disjoint_ε_transmission_to_iterated_combinend_Sync:
  ‹(⋀A. A ∈ set As ⟹ ρ_disjoint_ε A) ⟹ ρ_disjoint_ε ⟪nd⨂⟦E⟧ As⟫›
  by (induct As rule: induct_list012)
    (simp_all add: ρ_combineRlist_Sync ε_combineRlist_Sync ρ_disjoint_ε_def combine_Sync_ε_def)

lemma at_most_1_elem_term_transmission_to_iterated_combinend_Sync:
  ‹(⋀A. A ∈ set As ⟹ at_most_1_elem_term A) ⟹ at_most_1_elem_term ⟪nd⨂⟦E⟧ As⟫›
  by (induct As rule: induct_list012,
      simp_all add: at_most_1_elem_term_def σ_σs_conv_defs combineRlist_Sync_defs)
    fastforce


lemma same_length_indep_transmission_to_iterated_combined_Sync:
  ‹length σs = length As ⟹
   (⋀i j. i ≤ length As ⟹ j ≤ length As ⟹ i ≠ j ⟹ 
   indep_enabl ((A0 # As) ! i) ((s0 # σs) ! i) E ((A0 # As) ! j) ((s0 # σs) ! j)) ⟹
   indep_enabl A0 s0 E ⟪d⨂⟦E⟧ As⟫ σs›
proof (induct σs As rule: induct_2_lists012)
  case Nil
  then show ?case by (simp add: indep_enablI)
next
  case (single σ1 A1)
  from single.prems[of 0 1] show ?case
    by (auto simp add: ℛd_from_σ_to_σs_description
        intro!: indep_enablI dest!: indep_enablD)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  show ?case
  proof (rule indep_enablI)
    fix t0 ts assume assms : ‹t0 ∈ ℛd A0 s0› ‹ts ∈ ℛd ⟪d⨂⟦E⟧ A1 # A2 # As⟫ (σ1 # σ2 # σs)›
    from assms(2) obtain t1 ts' where ‹ts = t1 # ts'›
      by (metis Cons.hyps(1) Zero_not_Suc length_Cons list.exhaust_sel list.size(3)
          same_length_ℛd_iterated_combined_Sync_description)
    with assms(2)[simplified, THEN set_mp[OF ℛd_combinedRlist_Sync_subset]]
    have ‹ts' ∈ ℛd ⟪d⨂⟦E⟧ A2 # As⟫ (σ2 # σs)› by simp

    have ‹indep_enabl A0 s0 E ⟪d⨂⟦E⟧ A2 # As⟫ (σ2 # σs)›
    proof (rule Cons.hyps(3))
      show ‹i ≤ length (A2 # As) ⟹ j ≤ length (A2 # As) ⟹ i ≠ j ⟹
            indep_enabl ((A0 # A2 # As) ! i) ((s0 # σ2 # σs) ! i) E
                            ((A0 # A2 # As) ! j) ((s0 # σ2 # σs) ! j)› for i j
        using Cons.prems[of ‹if i = 0 then 0 else Suc i› ‹if j = 0 then 0 else Suc j›]
        by (cases i; cases j) simp_all
    qed
    from this[THEN indep_enablD, OF assms(1) ‹ts' ∈ ℛd ⟪d⨂⟦E⟧ A2 # As⟫ (σ2 # σs)›]
    have ‹ε A0 t0 ∩ ε ⟪d⨂⟦E⟧ A2 # As⟫ ts' ⊆ E› .
    moreover from Cons.prems[THEN indep_enablD, of 0 ‹Suc 0› t0 t1]
      assms(2)[simplified, THEN set_mp[OF ℛd_combinedRlist_Sync_subset]] assms(1)
    have ‹ε A0 t0 ∩ ε A1 t1 ⊆ E› by (simp add: ‹ts = t1 # ts'›)
    ultimately show ‹ε A0 t0 ∩ ε ⟪d⨂⟦E⟧ A1 # A2 # As⟫ ts ⊆ E›
      by (auto simp add: ε_combineRlist_Sync ‹ts = t1 # ts'› combine_Sync_ε_def)
  qed
qed


lemma ω_iterated_combined_Sync :
  ‹length σs = length As ⟹
   ω ⟪d⨂⟦E⟧ As⟫ σs = (case those (map2 ω As σs) of ◇ ⇒ ◇
    | ⌊terms⌋ ⇒ if card (set terms) = Suc 0 then ⌊THE r. set terms = {r}⌋ else ◇)›
  by (induct σs As rule: induct_2_lists012)
    (auto simp add: σ_σs_conv_defs combineRlist_Sync_defs card_1_singleton_iff the_equality split: option.split)

lemma ω_iterated_combinend_Sync :
  ‹length σs = length As ⟹
   ω ⟪nd⨂⟦E⟧ As⟫ σs = (if As = [] then {} else {r. ∀i < length As. r ∈ ω (As ! i) (σs ! i)})›
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ1 A1)
  from length_Suc_conv show ?case
    by (auto simp add: σ_σs_conv_defs)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  show ?case (is ‹_ = ?rhs σ1 σ2 σs A1 A2 As›)
  proof (intro subset_antisym subsetI)
    fix r assume ‹r ∈ ω ⟪nd⨂⟦E⟧ A1 # A2 # As⟫ (σ1 # σ2 # σs)›
    hence ‹r ∈ ω A1 σ1› ‹r ∈ ω ⟪nd⨂⟦E⟧ A2 # As⟫ (σ2 # σs)›
      by (simp_all add: combineRlist_Sync_defs split: if_split_asm)
    from this(2) have ‹∀i<Suc (length As). r ∈ ω ((A2 # As) ! i) ((σ2 # σs) ! i)›
      by (simp add: Cons.hyps(3))
    with ‹r ∈ ω A1 σ1› show ‹r ∈ ?rhs σ1 σ2 σs A1 A2 As›
      by (auto simp add: less_Suc_eq_0_disj)
  next
    from Cons.hyps(3)
    show ‹r ∈ ?rhs σ1 σ2 σs A1 A2 As ⟹
          r ∈ ω ⟪nd⨂⟦E⟧ A1 # A2 # As⟫ (σ1 # σ2 # σs)› for r
      by (auto simp add: combineRlist_Sync_defs)
  qed
qed


subsection ‹Normalization›

lemma ω_iterated_combinend_Sync_det_ndet_conv:
  ‹length σs = length As ⟹
   ω ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫ σs = ω ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs›
proof (induct σs As rule: induct_2_lists012)
  case Nil
  show ?case by (simp add: base_trans_det_ndet_conv(1))
next
  case (single σ1 A1)
  show ?case by (simp add: from_det_to_ndet_σ_σs_conv_commute)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  thus ?case
    by (auto simp add: det_ndet_conv_defs combineRlist_Sync_defs split: option.split)
qed

lemma τ_iterated_combinend_Sync_behaviour_when_indep:
  ‹length σs = length As ⟹
   (⋀i j. ⟦i < length As; j < length As; i ≠ j⟧
    ⟹ indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)) ⟹ 
   τ ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs e = τ ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫ σs e›
proof (induct σs As rule: induct_2_lists012)
  case Nil
  show ?case by simp
next
  case (single σ1 A1)
  show ?case by (simp add: from_det_to_ndet_σ_σs_conv_commute(1))
next
  case (Cons σ1 σ2 σs A1 A2 As)
  have * : ‹τ ⟪⟪d⨂⟦E⟧ A2 # As⟫⟫d↪nd (σ2 # σs) e =
            τ ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) (A2 # As)⟫ (σ2 # σs) e›
  proof (rule Cons.hyps(3))
    show ‹⟦i < length (A2 # As); j < length (A2 # As); i ≠ j⟧
          ⟹ indep_enabl ((A2 # As) ! i) ((σ2 # σs) ! i) E
                              ((A2 # As) ! j) ((σ2 # σs) ! j)› for i j
      using Cons.prems[of ‹Suc i› ‹Suc j›] by simp
  qed
  have ‹τ ⟪⟪d⨂⟦E⟧ A1 # A2 # As⟫⟫d↪nd (σ1 # σ2 # σs) e =
        τ ⟪⟪A1⟫d↪nd nd⊗⟦E⟧Rlist ⟪⟪d⨂⟦E⟧ A2 # As⟫⟫d↪nd⟫ (σ1 # σ2 # σs) e›
  proof (subst iterated_combined_Sync.simps(3), rule τ_combineRlist_Sync_behaviour_when_indep)
    show ‹ε A1 σ1 ∩ ε ⟪d⨂⟦E⟧ A2 # As⟫ (σ2 # σs) ⊆ E›
    proof (rule indep_enablD[OF _ ℛd.init ℛd.init])
      show ‹indep_enabl A1 σ1 E ⟪d⨂⟦E⟧ A2 # As⟫ (σ2 # σs)›
        by (simp add: Cons.hyps(1) Cons.prems order_le_less_trans
            same_length_indep_transmission_to_iterated_combined_Sync)
    qed
  qed
  also have ‹… = τ ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) (A1 # A2 # As)⟫ (σ1 # σ2 # σs) e›
    by (use "*" in ‹simp add: combineRlist_Sync_defs ε_simps›)
      (metis empty_from_det_to_ndet_is_None_trans option.exhaust)
  finally show ?case .
qed



lemma PSKIPS_iterated_combinend_Sync_behaviour_when_indep:
  assumes same_length: ‹length σs = length As›
    and indep: ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
                      indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
  shows ‹PSKIPS⟪⟪d⨂⟦E⟧ As⟫⟫d σs = PSKIPS⟪⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫⟫nd σs›
proof (fold PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d, rule PSKIPS_nd_eqI_strong_id)
  show ‹σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs ⟹
        τ ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫ σs' e = τ ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs' e› for σs' e
  proof (rule τ_iterated_combinend_Sync_behaviour_when_indep[symmetric])
    show ‹σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs ⟹ length σs' = length As›
      by (metis ℛnd_from_det_to_ndet same_length same_length_ℛd_iterated_combined_Sync_description)
  next
    show ‹⟦σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs; i < length As; j < length As; i ≠ j⟧
          ⟹ indep_enabl (As ! i) (σs' ! i) E (As ! j) (σs' ! j)› for i j
      by (subst (asm) ℛnd_from_det_to_ndet,
          drule same_length_ℛd_iterated_combined_Sync_description[OF same_length])
        (meson ℛd_trans indep_enabl_def indep)
  qed
next
  show ‹σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs ⟹
        ω ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫ σs' = ω ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs'› for σs'
    by (metis ℛnd_from_det_to_ndet ω_iterated_combinend_Sync_det_ndet_conv same_length
        same_length_ℛd_iterated_combined_Sync_description)
qed


lemma P_d_iterated_combinend_Sync_behaviour_when_indep:
  assumes same_length: ‹length σs = length As›
    and indep: ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
                      indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
  shows ‹P⟪⟪d⨂⟦E⟧ As⟫⟫d σs = P⟪⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫⟫nd σs›
proof (fold P_nd_from_det_to_ndet_is_P_d, rule P_nd_eqI_strong_id)
  show ‹σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs ⟹
        τ ⟪nd⨂⟦E⟧ map (λA. ⟪A⟫d↪nd) As⟫ σs' e = τ ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs' e› for σs' e
  proof (rule τ_iterated_combinend_Sync_behaviour_when_indep[symmetric])
    show ‹σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs ⟹ length σs' = length As›
      by (metis ℛnd_from_det_to_ndet same_length same_length_ℛd_iterated_combined_Sync_description)
  next
    show ‹⟦σs' ∈ ℛnd ⟪⟪d⨂⟦E⟧ As⟫⟫d↪nd σs; i < length As; j < length As; i ≠ j⟧
          ⟹ indep_enabl (As ! i) (σs' ! i) E (As ! j) (σs' ! j)› for i j
      by (subst (asm) ℛnd_from_det_to_ndet,
          drule same_length_ℛd_iterated_combined_Sync_description[OF same_length])
        (meson ℛd_trans indep_enabl_def indep)
  qed
qed



section ‹Compactification Theorems›

subsection ‹Binary›

subsubsection ‹Pair›

theorem PSKIPS_nd_combinePair_Sync :
  fixes E :: ‹'a set› and A0 :: ‹('σ, 'a, 'r, 'α) And_scheme›
  assumes ρ_disjoint_ε : ‹ρ_disjoint_ε A0› ‹ρ_disjoint_ε A1›
    and at_most_1_elem_term : ‹at_most_1_elem_term A0› ‹at_most_1_elem_term A1›
  defines A_def: ‹A ≡ ⟪A0 nd⊗⟦E⟧Pair A1⟫›      
  defines P_def: ‹P ≡ PSKIPS⟪A0⟫nd› and Q_def: ‹Q ≡ PSKIPS⟪A1⟫nd› and S_def: ‹S ≡ PSKIPS⟪A⟫nd›
  shows ‹P σ0 ⟦E⟧ Q σ1 = S (σ0, σ1)›
proof -
  let ?f = ‹PSKIPS_nd_step (ε A) (τ A) (ω A) (λσ'. case σ' of (σ0, σ1) ⇒ P σ0 ⟦E⟧ Q σ1)›
  note cartprod_rwrt = GlobalNdet_cartprod[of _ _ ‹λx y. _ (x, y)›, simplified]
  note Ndet_and_Sync = Sync_distrib_GlobalNdet_left
    Sync_distrib_GlobalNdet_right
  note Mprefix_Sync_constant =
    SKIP_Sync_Mprefix Mprefix_Sync_SKIP
    STOP_Sync_Mprefix Mprefix_Sync_STOP
  note P_rec = restriction_fix_eq[OF PSKIPS_nd_step_constructive_bis[of A0], folded PSKIPS_nd_def P_def, THEN fun_cong]
  note Q_rec = restriction_fix_eq[OF PSKIPS_nd_step_constructive_bis[of A1], folded PSKIPS_nd_def Q_def, THEN fun_cong]
  have ω_A : ‹ω A (σ0', σ1') = ω A0 σ0' ∩ ω A1 σ1'› for σ0' σ1'
    by (auto simp add: A_def combinePair_Sync_defs)
  have ε_A : ‹ε A (σ0', σ1') = combine_sets_Sync (ε A0 σ0') E (ε A1 σ1')› for σ0' σ1'
    by (simp add: A_def ε_combinePair_Sync combine_Sync_ε_def)
  have Mprefix_Sync_Mprefix_for_procomata :
    ‹□a∈A → P a ⟦E⟧ □b∈B → Q b =
     (□a∈(A - E - B) → (P a ⟦E⟧ □b∈B → Q b))                            □
     (□b∈(B - E - A) → (□a∈A → P a ⟦E⟧ Q b))                            □
     (□x∈(A ∩ B - E) → (P x ⟦E⟧ □b∈B → Q b) ⊓ (□a∈A → P a ⟦E⟧ Q x)) □
     (□x∈(A ∩ B ∩ E) → (P x ⟦E⟧ Q x))› (is ?eq) for A B and P Q :: ‹'a ⇒ ('a, 'r) processptick›
  proof -
    have  * : ‹□a∈(A - E) → (P a ⟦E⟧ □b∈B → Q b) =
              (□a∈(A - E - B) → (P a ⟦E⟧ □b∈B → Q b)) □
              (□a∈(A ∩ B - E) → (P a ⟦E⟧ □b∈B → Q b))›
      by (metis Diff_Int2 Diff_Int_distrib2 Mprefix_Un_distrib Un_Diff_Int)
    have ** : ‹□b∈(B - E) → (□a∈A → P a ⟦E⟧ Q b) =
               (□b∈(B - E - A) → (□a∈A → P a ⟦E⟧ Q b)) □
               (□b∈(A ∩ B - E) → (□a∈A → P a ⟦E⟧ Q b))›
      by (metis (no_types) Int_Diff Int_commute Mprefix_Un_distrib Un_Diff_Int)
    have ‹□a∈A → P a ⟦E⟧ □b∈B → Q b =
          (□a∈(A - E - B) → (P a ⟦E⟧ □b∈B → Q b))    □
          (□b∈(B - E - A) → (□a∈A → P a ⟦E⟧ Q b))    □
          ((□a∈(A ∩ B - E) → (P a ⟦E⟧ □b∈B → Q b))   □
           (□b∈(A ∩ B - E) → (□a∈A → P a ⟦E⟧ Q b)))  □
          (□x∈(A ∩ B ∩ E) → (P x ⟦E⟧ Q x))›
      unfolding Mprefix_Sync_Mprefix
      by (auto simp add: "**" Det_assoc intro!: arg_cong[where f = ‹λP. P □ _›])
        (subst (3) Det_commute, subst Det_assoc,
          auto simp add: "*" Det_commute intro: arg_cong[where f = ‹λP. P □ _›])
    also have ‹(□a∈(A ∩ B - E) → (P a ⟦E⟧ □b∈B → Q b)) □
                (□b∈(A ∩ B - E) → (□a∈A → P a ⟦E⟧ Q b)) =
                □x∈(A ∩ B - E) → ((P x ⟦E⟧ □b∈B → Q b)) ⊓ (□a∈A → P a ⟦E⟧ Q x)›
      by (simp add: Mprefix_Det_Mprefix, rule mono_Mprefix_eq, simp)
    finally show ?thesis .
  qed
  show ‹P σ0 ⟦E⟧ Q σ1 = S (σ0, σ1)›
  proof (rule fun_cong[of ‹λ(σ0, σ1). P σ0 ⟦E⟧ Q σ1› _ ‹(σ0, σ1)›, simplified])
    show ‹(λ(σ0, σ1). P σ0 ⟦E⟧ Q σ1) = S›
    proof (rule restriction_fix_unique[OF PSKIPS_nd_step_constructive_bis[of A],
          symmetric, folded PSKIPS_nd_def S_def])
      show ‹?f = (λ(σ0, σ1). P σ0 ⟦E⟧ Q σ1)›
      proof (rule ext, clarify)
        have ρ_disjoint_ε_bis : ‹ω A0 σ0 ≠ {} ⟹ ε A0 σ0 = {}›
          ‹ω A1 σ1 ≠ {} ⟹ ε A1 σ1 = {}› for σ0 σ1
          by (simp_all add: ρ_simps ρ_disjoint_εD ρ_disjoint_ε)
        show ‹?f (σ0, σ1) = P σ0 ⟦E⟧ Q σ1› for σ0 σ1
        proof (cases ‹ω A0 σ0 = {}›; cases ‹ω A1 σ1 = {}›)
          assume ‹ω A0 σ0 = {}› ‹ω A1 σ1 = {}›
          hence P_rec' : ‹P σ0 = P_nd_step (ε A0) (τ A0) P σ0›
            and Q_rec' : ‹Q σ1 = P_nd_step (ε A1) (τ A1) Q σ1›
            and S_rec' : ‹PSKIPS_nd_step (ε A) (τ A) (ω A) (λ(σ0, σ1). P σ0 ⟦E⟧ Q σ1) (σ0, σ1) =
                        P_nd_step (ε A) (τ A) (λ(σ0, σ1). P σ0 ⟦E⟧ Q σ1) (σ0, σ1)›
            by (simp_all add: P_rec[of σ0] Q_rec[of σ1] ω_A)
          show ‹?f (σ0, σ1) = P σ0 ⟦E⟧ Q σ1›
            unfolding P_rec' Q_rec' S_rec' Mprefix_Sync_Mprefix_for_procomata
            unfolding ε_A Mprefix_Un_distrib
            by (intro arg_cong2[where f = ‹(□)›] mono_Mprefix_eq, fold P_rec' Q_rec',
                auto simp add: A_def Ndet_and_Sync cartprod_rwrt
                combinePair_Sync_defs ε_simps GlobalNdet_sets_commute[of ‹τ A1 _ _›]
                simp flip: GlobalNdet_factorization_union
                intro!: mono_GlobalNdet_eq arg_cong2[where f = ‹(⊓)›])
        next
          assume ‹ω A0 σ0 ≠ {}› ‹ω A1 σ1 = {}›
          from ρ_disjoint_ε(1) ‹ω A0 σ0 ≠ {}› have ‹ε A0 σ0 = {}›
            by (simp add: ρ_disjoint_ε_def ρ_simps)
          have ‹?f (σ0, σ1) = □b∈(ε A1 σ1 - E) → (⊓σ1'∈τ A1 σ1 b. (SKIPS (ω A0 σ0) ⟦E⟧ Q σ1'))›
            by (auto simp add: ω_A ε_A ‹ω A1 σ1 = {}› ‹ε A0 σ0 = {}› intro!: mono_Mprefix_eq,
                auto simp add: A_def combinePair_Sync_defs ‹ω A0 σ0 ≠ {}›
                ‹ε A0 σ0 = {}› cartprod_rwrt P_rec[of σ0] intro!: mono_GlobalNdet_eq)
          also have ‹… = P σ0 ⟦E⟧ Q σ1›
            by (unfold P_rec[of σ0] Q_rec[of σ1])
              (auto simp add: SKIPS_def Ndet_and_Sync Mprefix_Sync_constant ‹ω A0 σ0 ≠ {}›
                GlobalNdet_Mprefix_distr GlobalNdet_sets_commute[of ‹τ A1 _ _›] ‹ω A1 σ1 = {}›
                intro!: mono_Mprefix_eq mono_GlobalNdet_eq)
          finally show ‹?f (σ0, σ1) = …› .
        next
          assume ‹ω A0 σ0 = {}› ‹ω A1 σ1 ≠ {}›
          from ρ_disjoint_ε(2) ‹ω A1 σ1 ≠ {}› have ‹ε A1 σ1 = {}›
            by (simp add: ρ_disjoint_ε_def ρ_simps)
          have ‹?f (σ0, σ1) = □a∈(ε A0 σ0 - E) → (⊓σ0'∈τ A0 σ0 a. (P σ0' ⟦E⟧ SKIPS (ω A1 σ1)))›
            by (auto simp add: ω_A ε_A ‹ω A0 σ0 = {}› ‹ε A1 σ1 = {}› intro!: mono_Mprefix_eq,
                auto simp add: A_def combinePair_Sync_defs ‹ω A1 σ1 ≠ {}›
                ‹ε A1 σ1 = {}› cartprod_rwrt Q_rec[of σ1] intro!: mono_GlobalNdet_eq)
          also have ‹… = P σ0 ⟦E⟧ Q σ1›
            by (unfold P_rec[of σ0] Q_rec[of σ1])
              (auto simp add: SKIPS_def Ndet_and_Sync Mprefix_Sync_constant ‹ω A1 σ1 ≠ {}›
                GlobalNdet_Mprefix_distr GlobalNdet_sets_commute[of ‹τ A0 _ _›] ‹ω A0 σ0 = {}›
                intro!: mono_Mprefix_eq mono_GlobalNdet_eq)
          finally show ‹?f (σ0, σ1) = …› .
        next
          assume ‹ω A0 σ0 ≠ {}› ‹ω A1 σ1 ≠ {}›
          with ρ_disjoint_ε have ‹ε A0 σ0 = {}› ‹ε A1 σ1 = {}›
            by (simp_all add: ρ_disjoint_ε_def ρ_simps)
          from at_most_1_elem_term
          show ‹ω A0 σ0 ≠ {} ⟹ ω A1 σ1 ≠ {} ⟹ ?f (σ0, σ1) = P σ0 ⟦E⟧ Q σ1›
            by (auto simp add: ‹ω A0 σ0 ≠ {}› ‹ω A1 σ1 ≠ {}› ω_A P_rec[of σ0] Q_rec[of σ1]
                SKIPS_def Ndet_and_Sync cartprod_rwrt GlobalNdet_sets_commute[of ‹ω A0 _›]
                ε_A ‹ε A0 σ0 = {}› ‹ε A1 σ1 = {}› elim!: at_most_1_elem_termE)
        qed
      qed
    qed
  qed
qed

corollary P_nd_combinePair_Sync :
  ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 = P⟪⟪A0 nd⊗⟦E⟧Pair A1⟫⟫nd (σ0, σ1)›
proof -
  have ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 =
        PSKIPS⟪A0⦇ω := λσ. {}⦈⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. {}⦈⟫nd σ1›
    by (simp add: PSKIPS_nd_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. {}⦈ nd⊗⟦E⟧Pair A1⦇ω := λσ. {}⦈⟫⟫nd (σ0, σ1)›
    by (rule PSKIPS_nd_combinePair_Sync) simp_all
  also have ‹⟪A0⦇ω := λσ. {}⦈ nd⊗⟦E⟧Pair A1⦇ω := λσ. {}⦈⟫ = ⟪A0 nd⊗⟦E⟧Pair A1⟫⦇ω := λσ. {}⦈›
    by (simp add: combinePair_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 nd⊗⟦E⟧Pair A1⟫⦇ω := λσ. {}⦈⟫nd = P⟪⟪A0 nd⊗⟦E⟧Pair A1⟫⟫nd›
    by (simp add: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combinePair_Sync:
  ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0 d⊗⟦E⟧Pair A1⟫⟫d (σ0, σ1)›
  if ‹ρ_disjoint_ε A0› and ‹ρ_disjoint_ε A1› and ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0⟫d↪nd⟫nd σ0 ⟦E⟧ PSKIPS⟪⟪A1⟫d↪nd⟫nd σ1›
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1, 2) have ‹… = PSKIPS⟪⟪⟪A0⟫d↪nd nd⊗⟦E⟧Pair ⟪A1⟫d↪nd⟫⟫nd (σ0, σ1)›
    by (auto intro: PSKIPS_nd_combinePair_Sync)
  also have ‹… = PSKIPS⟪⟪A0 d⊗⟦E⟧Pair A1⟫⟫d (σ0, σ1)›
    by (simp add: PSKIPS_combinePair_Sync_behaviour_when_indep ‹indep_enabl A0 σ0 E A1 σ1›)
  finally show ?thesis .
qed

corollary P_d_combinePair_Sync:
  ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 = P⟪⟪A0 d⊗⟦E⟧Pair A1⟫⟫d (σ0, σ1)›
  if ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 =
        PSKIPS⟪A0⦇ω := λσ. ◇⦈⟫d σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. ◇⦈⟫d σ1›
    by (simp add: PSKIPS_d_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. ◇⦈ d⊗⟦E⟧Pair A1⦇ω := λσ. ◇⦈⟫⟫d (σ0, σ1)›
    by (subst PSKIPS_d_combinePair_Sync, simp_all add: ρ_simps ρ_disjoint_ε_def)
      (rule indep_enablI,
        use ‹indep_enabl A0 σ0 E A1 σ1›[THEN indep_enablD] in ‹simp add: ε_simps›)
  also have ‹⟪A0⦇ω := λσ. ◇⦈ d⊗⟦E⟧Pair A1⦇ω := λσ. ◇⦈⟫ = ⟪A0 d⊗⟦E⟧Pair A1⟫⦇ω := λσ. ◇⦈›
    by (simp add: combinePair_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 d⊗⟦E⟧Pair A1⟫⦇ω := λσ. ◇⦈⟫d = P⟪⟪A0 d⊗⟦E⟧Pair A1⟫⟫d›
    by (simp add: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsubsection ‹Pairlist›

theorem PSKIPS_nd_combinePairlist_Sync :
  ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⟫nd σ1 = PSKIPS⟪⟪A0 nd⊗⟦E⟧Pairlist A1⟫⟫nd [σ0, σ1]›
  if ‹ρ_disjoint_ε A0› ‹ρ_disjoint_ε A1› ‹at_most_1_elem_term A0› ‹at_most_1_elem_term A1›
proof -
  from PSKIPS_nd_combinePair_Sync that
  have ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⟫nd σ1 = PSKIPS⟪⟪A0 nd⊗⟦E⟧Pair A1⟫⟫nd (σ0, σ1)› .
  also have ‹… = PSKIPS⟪⟪A0 nd⊗⟦E⟧Pairlist A1⟫⟫nd [σ0, σ1]›
    by (auto intro!: PSKIPS_nd_eqI_strong[of ‹λ(r, s). [r, s]› _ ‹(σ0, σ1)›, simplified] inj_onI)
      (auto simp add: combine_Sync_defs split: if_split_asm)
  finally show ?thesis .
qed

corollary P_nd_combinePairlist_Sync :
  ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 = P⟪⟪A0 nd⊗⟦E⟧Pairlist A1⟫⟫nd [σ0, σ1]›
proof -
  have ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 =
        PSKIPS⟪A0⦇ω := λσ. {}⦈⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. {}⦈⟫nd σ1›
    by (simp only: PSKIPS_nd_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. {}⦈ nd⊗⟦E⟧Pairlist A1⦇ω := λσ. {}⦈⟫⟫nd [σ0, σ1]›
    by (rule PSKIPS_nd_combinePairlist_Sync) simp_all
  also have ‹⟪A0⦇ω := λσ. {}⦈ nd⊗⟦E⟧Pairlist A1⦇ω := λσ. {}⦈⟫ = ⟪A0 nd⊗⟦E⟧Pairlist A1⟫⦇ω := λσ. {}⦈›
    by (simp add: combinePairlist_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 nd⊗⟦E⟧Pairlist A1⟫⦇ω := λσ. {}⦈⟫nd = P⟪⟪A0 nd⊗⟦E⟧Pairlist A1⟫⟫nd›
    by (simp only: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combinePairlist_Sync :
  ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0 d⊗⟦E⟧Pairlist A1⟫⟫d [σ0, σ1]›
  if ‹ρ_disjoint_ε A0› and ‹ρ_disjoint_ε A1› and ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0⟫d↪nd⟫nd σ0 ⟦E⟧ PSKIPS⟪⟪A1⟫d↪nd⟫nd σ1›
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1, 2) have ‹… = PSKIPS⟪⟪⟪A0⟫d↪nd nd⊗⟦E⟧Pairlist ⟪A1⟫d↪nd⟫⟫nd [σ0, σ1]›
    by (auto intro: PSKIPS_nd_combinePairlist_Sync)
  also have ‹… = PSKIPS⟪⟪A0 d⊗⟦E⟧Pairlist A1⟫⟫d [σ0, σ1]›
    by (simp add: PSKIPS_combinePairlist_Sync_behaviour_when_indep ‹indep_enabl A0 σ0 E A1 σ1›)
  finally show ?thesis .
qed

corollary P_d_combinePairlist_Sync :
  ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 = P⟪⟪A0 d⊗⟦E⟧Pairlist A1⟫⟫d [σ0, σ1]›
  if ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 =
        PSKIPS⟪A0⦇ω := λσ. ◇⦈⟫d σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. ◇⦈⟫d σ1›
    by (simp only: PSKIPS_d_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. ◇⦈ d⊗⟦E⟧Pairlist A1⦇ω := λσ. ◇⦈⟫⟫d [σ0, σ1]›
    by (subst PSKIPS_d_combinePairlist_Sync, simp_all)
      (rule indep_enablI,
        use ‹indep_enabl A0 σ0 E A1 σ1›[THEN indep_enablD] in simp)
  also have ‹⟪A0⦇ω := λσ. ◇⦈ d⊗⟦E⟧Pairlist A1⦇ω := λσ. ◇⦈⟫ = ⟪A0 d⊗⟦E⟧Pairlist A1⟫⦇ω := λσ. ◇⦈›
    by (simp add: combinePairlist_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 d⊗⟦E⟧Pairlist A1⟫⦇ω := λσ. ◇⦈⟫d = P⟪⟪A0 d⊗⟦E⟧Pairlist A1⟫⟫d›
    by (simp only: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsection ‹Rlist›

theorem PSKIPS_nd_combineRlist_Sync :
  ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⟫nd σ1 = PSKIPS⟪⟪A0 nd⊗⟦E⟧Rlist A1⟫⟫nd (σ0 # σ1)›
  if ‹ρ_disjoint_ε A0› ‹ρ_disjoint_ε A1› ‹at_most_1_elem_term A0› ‹at_most_1_elem_term A1›
proof -
  from PSKIPS_nd_combinePair_Sync that
  have ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⟫nd σ1 = PSKIPS⟪⟪A0 nd⊗⟦E⟧Pair A1⟫⟫nd (σ0, σ1)› .
  also have ‹… = PSKIPS⟪⟪A0 nd⊗⟦E⟧Rlist A1⟫⟫nd (σ0 # σ1)›
    by (auto intro!: PSKIPS_nd_eqI_strong[of ‹λ(r, s). r # s› _ ‹(σ0, σ1)›, simplified] inj_onI)
      (auto simp add: combine_Sync_defs split: if_split_asm)
  finally show ?thesis .
qed

corollary P_nd_combineRlist_Sync :
  ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 = P⟪⟪A0 nd⊗⟦E⟧Rlist A1⟫⟫nd (σ0 # σ1)›
proof -
  have ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 =
        PSKIPS⟪A0⦇ω := λσ. {}⦈⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. {}⦈⟫nd σ1›
    by (simp only: PSKIPS_nd_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. {}⦈ nd⊗⟦E⟧Rlist A1⦇ω := λσ. {}⦈⟫⟫nd (σ0 # σ1)›
    by (rule PSKIPS_nd_combineRlist_Sync) simp_all
  also have ‹⟪A0⦇ω := λσ. {}⦈ nd⊗⟦E⟧Rlist A1⦇ω := λσ. {}⦈⟫ = ⟪A0 nd⊗⟦E⟧Rlist A1⟫⦇ω := λσ. {}⦈›
    by (simp add: combineRlist_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 nd⊗⟦E⟧Rlist A1⟫⦇ω := λσ. {}⦈⟫nd = P⟪⟪A0 nd⊗⟦E⟧Rlist A1⟫⟫nd›
    by (simp only: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combineRlist_Sync :
  ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0 d⊗⟦E⟧Rlist A1⟫⟫d (σ0 # σ1)›
  if ‹ρ_disjoint_ε A0› and ‹ρ_disjoint_ε A1› and ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0⟫d↪nd⟫nd σ0 ⟦E⟧ PSKIPS⟪⟪A1⟫d↪nd⟫nd σ1›
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1, 2) have ‹… = PSKIPS⟪⟪⟪A0⟫d↪nd nd⊗⟦E⟧Rlist ⟪A1⟫d↪nd⟫⟫nd (σ0 # σ1)›
    by (auto intro: PSKIPS_nd_combineRlist_Sync)
  also have ‹… = PSKIPS⟪⟪A0 d⊗⟦E⟧Rlist A1⟫⟫d (σ0 # σ1)›
    by (simp add: PSKIPS_combineRlist_Sync_behaviour_when_indep ‹indep_enabl A0 σ0 E A1 σ1›)
  finally show ?thesis .
qed

corollary P_d_combineRlist_Sync :
  ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 = P⟪⟪A0 d⊗⟦E⟧Rlist A1⟫⟫d (σ0 # σ1)›
  if ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 =
        PSKIPS⟪A0⦇ω := λσ. ◇⦈⟫d σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. ◇⦈⟫d σ1›
    by (simp only: PSKIPS_d_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. ◇⦈ d⊗⟦E⟧Rlist A1⦇ω := λσ. ◇⦈⟫⟫d (σ0 # σ1)›
    by (subst PSKIPS_d_combineRlist_Sync, simp_all)
      (rule indep_enablI,
        use ‹indep_enabl A0 σ0 E A1 σ1›[THEN indep_enablD] in simp)
  also have ‹⟪A0⦇ω := λσ. ◇⦈ d⊗⟦E⟧Rlist A1⦇ω := λσ. ◇⦈⟫ = ⟪A0 d⊗⟦E⟧Rlist A1⟫⦇ω := λσ. ◇⦈›
    by (simp add: combineRlist_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 d⊗⟦E⟧Rlist A1⟫⦇ω := λσ. ◇⦈⟫d = P⟪⟪A0 d⊗⟦E⟧Rlist A1⟫⟫d›
    by (simp only: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsection ‹ListslenL›

theorem PSKIPS_nd_combineListslenL_Sync :
  assumes same_length_reach0 : ‹⋀σ0'. σ0' ∈ ℛnd A0 σ0 ⟹ length σ0' = len0›
    and ρ_disjoint_ε : ‹ρ_disjoint_ε A0› ‹ρ_disjoint_ε A1› ‹at_most_1_elem_term A0› ‹at_most_1_elem_term A1›
  shows ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⟫nd σ1 = PSKIPS⟪⟪A0 nd⊗⟦len0, E⟧ListslenL A1⟫⟫nd (σ0 @ σ1)›
proof -
  from set_mp[OF ℛnd_combinendPair_Sync_subset]
  have * : ‹σ' ∈ ℛnd ⟪A0 nd⊗⟦E⟧Pair A1⟫ (σ0, σ1) ⟹
            ∃σ0' σ1'. σ' = (σ0', σ1') ∧ σ0' ∈ ℛnd A0 σ0 ∧ σ1' ∈ ℛnd A1 σ1› for σ' by fast
  from PSKIPS_nd_combinePair_Sync assms(2-5)
  have ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⟫nd σ1 = PSKIPS⟪⟪A0 nd⊗⟦E⟧Pair A1⟫⟫nd (σ0, σ1)› .
  also have ‹… = PSKIPS⟪⟪A0 nd⊗⟦len0, E⟧ListslenL A1⟫⟫nd (σ0 @ σ1)›
    by  (auto intro!: PSKIPS_nd_eqI_strong[of ‹λ(r, s). r @ s› _ ‹(σ0, σ1)›, simplified] inj_onI
        dest!: "*" same_length_reach0 simp add: same_length_reach0 image_iff)
      (auto simp add: combine_Sync_defs ε_simps split: if_split_asm,
        (metis SigmaI UnCI case_prod_conv insertI1)+)
  finally show ?thesis .
qed

corollary P_nd_combineListslenL_Sync :
  ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 = P⟪⟪A0 nd⊗⟦len0, E⟧ListslenL A1⟫⟫nd (σ0 @ σ1)›
  if ‹⋀σ0'. σ0' ∈ ℛnd A0 σ0 ⟹ length σ0' = len0›
proof -
  have ‹P⟪A0⟫nd σ0 ⟦E⟧ P⟪A1⟫nd σ1 =
        PSKIPS⟪A0⦇ω := λσ. {}⦈⟫nd σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. {}⦈⟫nd σ1›
    by (simp only: PSKIPS_nd_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. {}⦈ nd⊗⟦len0, E⟧ListslenL A1⦇ω := λσ. {}⦈⟫⟫nd (σ0 @ σ1)›
    by (rule PSKIPS_nd_combineListslenL_Sync) (simp_all add: that)
  also have ‹⟪A0⦇ω := λσ. {}⦈ nd⊗⟦len0, E⟧ListslenL A1⦇ω := λσ. {}⦈⟫ = ⟪A0 nd⊗⟦len0, E⟧ListslenL A1⟫⦇ω := λσ. {}⦈›
    by (simp add: combineListslenL_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 nd⊗⟦len0, E⟧ListslenL A1⟫⦇ω := λσ. {}⦈⟫nd = P⟪⟪A0 nd⊗⟦len0, E⟧ListslenL A1⟫⟫nd›
    by (simp only: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combineListslenL_Sync :
  ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0 d⊗⟦len0, E⟧ListslenL A1⟫⟫d (σ0 @ σ1)›
  if ‹⋀σ0'. σ0' ∈ ℛd A0 σ0 ⟹ length σ0' = len0›
    ‹ρ_disjoint_ε A0› ‹ρ_disjoint_ε A1› ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹PSKIPS⟪A0⟫d σ0 ⟦E⟧ PSKIPS⟪A1⟫d σ1 = PSKIPS⟪⟪A0⟫d↪nd⟫nd σ0 ⟦E⟧ PSKIPS⟪⟪A1⟫d↪nd⟫nd σ1›
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1-3) have ‹… = PSKIPS⟪⟪⟪A0⟫d↪nd nd⊗⟦len0, E⟧ListslenL ⟪A1⟫d↪nd⟫⟫nd (σ0 @ σ1)›
    by (auto simp add: ℛnd_from_det_to_ndet intro!: PSKIPS_nd_combineListslenL_Sync)
  also have ‹… = PSKIPS⟪⟪A0 d⊗⟦len0, E⟧ListslenL A1⟫⟫d (σ0 @ σ1)›
    by (simp add: PSKIPS_combineListslenL_Sync_behaviour_when_indep that(1, 4))
  finally show ?thesis .
qed

corollary P_d_combineListslenL_Sync :
  ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 = P⟪⟪A0 d⊗⟦len0, E⟧ListslenL A1⟫⟫d (σ0 @ σ1)›
  if ‹⋀σ0'. σ0' ∈ ℛd A0 σ0 ⟹ length σ0' = len0› ‹indep_enabl A0 σ0 E A1 σ1›
proof -
  have ‹P⟪A0⟫d σ0 ⟦E⟧ P⟪A1⟫d σ1 =
        PSKIPS⟪A0⦇ω := λσ. ◇⦈⟫d σ0 ⟦E⟧ PSKIPS⟪A1⦇ω := λσ. ◇⦈⟫d σ1›
    by (simp only: PSKIPS_d_updated_ω)
  also have ‹… = PSKIPS⟪⟪A0⦇ω := λσ. ◇⦈ d⊗⟦len0, E⟧ListslenL A1⦇ω := λσ. ◇⦈⟫⟫d (σ0 @ σ1)›
    by (subst PSKIPS_d_combineListslenL_Sync) (simp_all add: that)
  also have ‹⟪A0⦇ω := λσ. ◇⦈ d⊗⟦len0, E⟧ListslenL A1⦇ω := λσ. ◇⦈⟫ = ⟪A0 d⊗⟦len0, E⟧ListslenL A1⟫⦇ω := λσ. ◇⦈›
    by (simp add: combineListslenL_Sync_defs, intro ext, simp)
  also have ‹PSKIPS⟪⟪A0 d⊗⟦len0, E⟧ListslenL A1⟫⦇ω := λσ. ◇⦈⟫d = P⟪⟪A0 d⊗⟦len0, E⟧ListslenL A1⟫⟫d›
    by (simp only: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsection ‹Multiple›

theorem PSKIPS_nd_compactification_Sync:
  ‹⟦length σs = length As; ⋀A. A ∈ set As ⟹ ρ_disjoint_ε A;
    ⋀A. A ∈ set As ⟹ at_most_1_elem_term A⟧
   ⟹ ⟦E⟧ (σ, A) ∈# mset (zip σs As). PSKIPS⟪A⟫nd σ = PSKIPS⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs›
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst PSKIPS_nd_rec, simp)
next
  case (single σ0 A0) show ?case
    by (auto simp add: σ_σs_conv_defs intro!: inj_onI PSKIPS_nd_eqI_strong)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  have ‹⟦E⟧ (σ, A) ∈# mset (zip (σ0 # σ1 # σs) (A0 # A1 # As)). PSKIPS⟪A⟫nd σ =
        PSKIPS⟪A0⟫nd σ0 ⟦E⟧ ⟦E⟧ (σ, A) ∈# mset (zip (σ1 # σs) (A1 # As)). PSKIPS⟪A⟫nd σ› by simp
  also have ‹⟦E⟧ (σ, A) ∈# mset (zip (σ1 # σs) (A1 # As)). PSKIPS⟪A⟫nd σ =
             PSKIPS⟪⟪nd⨂⟦E⟧ A1 # As⟫⟫nd (σ1 # σs)›
    by (rule Cons.hyps(3)) (simp_all add: Cons.prems)
  also have ‹PSKIPS⟪A0⟫nd σ0 ⟦E⟧ PSKIPS⟪⟪nd⨂⟦E⟧ A1 # As⟫⟫nd (σ1 # σs) =
             PSKIPS⟪⟪A0 nd⊗⟦E⟧Rlist ⟪nd⨂⟦E⟧ A1 # As⟫⟫⟫nd (σ0 # σ1 # σs)›
    by (rule PSKIPS_nd_combineRlist_Sync
        [OF _ ρ_disjoint_ε_transmission_to_iterated_combinend_Sync
          _ at_most_1_elem_term_transmission_to_iterated_combinend_Sync])
      (simp_all add: Cons.prems)
  also have ‹⟪A0 nd⊗⟦E⟧Rlist ⟪nd⨂⟦E⟧ A1 # As⟫⟫ = ⟪nd⨂⟦E⟧ A0 # A1 # As⟫› by simp
  finally show ?case .
qed

lemma P_nd_compactification_Sync:
  ‹length σs = length As ⟹
   ⟦E⟧ (σ, A) ∈# mset (zip σs As). P⟪A⟫nd σ = P⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs›
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst P_nd_rec, simp)
next
  case (single σ0 A0) show ?case
    by (simp add: P_nd_from_σ_to_σs_is_P_nd)
next
  case (Cons σ0 σ1 σs A0 A1 As) thus ?case
    by (simp add: P_nd_combineRlist_Sync)
qed

lemma PSKIPS_d_compactification_Sync:
  ‹⟦length σs = length As; ⋀A. A ∈ set As ⟹ ρ_disjoint_ε A;
    ⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
          indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)⟧ ⟹
   ⟦E⟧ (σ, A) ∈# mset (zip σs As). PSKIPS⟪A⟫d σ = PSKIPS⟪⟪d⨂⟦E⟧ As⟫⟫d σs›
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst PSKIPS_d_rec, simp)
next
  case (single σ0 A0) show ?case
    by (auto simp add: RenamingTick_PSKIPS_d σ_σs_conv_defs
        intro!: inj_onI PSKIPS_d_eqI_strong split: option.split)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  have ρ_disjoint_ε : ‹A ∈ set (A1 # As) ⟹ ρ_disjoint_ε A› for A
    by (simp add: Cons.prems(1))
  have indep_enabl :
    ‹⟦i < length (A1 # As); j < length (A1 # As); i ≠ j⟧ ⟹
     indep_enabl ((A1 # As) ! i) ((σ1 # σs) ! i) E ((A1 # As) ! j) ((σ1 # σs) ! j)› for i j
    by (metis Cons.prems(2) Suc_less_eq length_Cons nat.inject nth_Cons_Suc)
  have ‹ρ_disjoint_ε A0› by (simp add: Cons.prems(1))
  moreover have ‹ρ_disjoint_ε ⟪d⨂⟦E⟧ A1 # As⟫›
    by (meson ρ_disjoint_ε ρ_disjoint_ε_transmission_to_iterated_combined_Sync)
  moreover have ‹indep_enabl A0 σ0 E ⟪d⨂⟦E⟧ A1 # As⟫ (σ1 # σs)›
    by (metis Cons.hyps(1) Cons.prems(2) length_Cons less_Suc_eq_le
        same_length_indep_transmission_to_iterated_combined_Sync)
  ultimately show ?case 
    by (simp add: PSKIPS_d_combineRlist_Sync
        Cons.hyps(3)[OF ρ_disjoint_ε indep_enabl, simplified])
qed

lemma P_d_compactification_Sync:
  ‹⟦length σs = length As;
    ⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
          indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)⟧ ⟹
   ⟦E⟧ (σ, A) ∈# mset (zip σs As). P⟪A⟫d σ = P⟪⟪d⨂⟦E⟧ As⟫⟫d σs›
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst P_d_rec, simp)
next
  case (single σ0 A0) show ?case
    by (simp, subst (1 2) PSKIPS_d_updated_ω)
      (auto simp add: RenamingTick_PSKIPS_d σ_σs_conv_defs
        intro!: inj_onI PSKIPS_d_eqI_strong split: option.split)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  have indep_enabl :
    ‹⟦i < length (A1 # As); j < length (A1 # As); i ≠ j⟧ ⟹
     indep_enabl ((A1 # As) ! i) ((σ1 # σs) ! i) E ((A1 # As) ! j) ((σ1 # σs) ! j)› for i j
    by (metis Cons.prems Suc_less_eq length_Cons nat.inject nth_Cons_Suc)
  have ‹indep_enabl A0 σ0 E ⟪d⨂⟦E⟧ A1 # As⟫ (σ1 # σs)›
    by (metis Cons.hyps(1) Cons.prems length_Cons less_Suc_eq_le
        same_length_indep_transmission_to_iterated_combined_Sync)
  thus ?case 
    by (simp add: P_d_combineRlist_Sync
        Cons.hyps(3)[OF indep_enabl, simplified])
qed




corollary PSKIPS_nd_compactification_Sync_order_is_arbitrary:
  ‹PSKIPS⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs = PSKIPS⟪⟪nd⨂⟦E⟧ As'⟫⟫nd σs'›
  if ‹length σs = length As› ‹length σs' = length As'›
    ‹mset (zip σs As) = mset (zip σs' As')› 
    ‹⋀A. A ∈ set As ⟹ ρ_disjoint_ε A›
    ‹⋀A. A ∈ set As ⟹ at_most_1_elem_term A›
proof -
  have ‹PSKIPS⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs = ⟦E⟧ (σ, A)∈#mset (zip σs As). PSKIPS⟪A⟫nd σ›
    by (rule PSKIPS_nd_compactification_Sync[OF that(1, 4, 5), symmetric])
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip σs' As'). PSKIPS⟪A⟫nd σ›
    by (simp only: that(3))
  also have ‹… = PSKIPS⟪⟪nd⨂⟦E⟧ As'⟫⟫nd σs'›
  proof (rule PSKIPS_nd_compactification_Sync[OF that(2)])
    show ‹A ∈ set As' ⟹ ρ_disjoint_ε A› for A
      by (metis in_set_impl_in_set_zip2 set_mset_mset set_zip_rightD that(2-4))
  next
    show ‹A ∈ set As' ⟹ at_most_1_elem_term A› for A
      by (metis in_set_impl_in_set_zip2 set_mset_mset set_zip_rightD that(2, 3, 5))
  qed
  finally show ?thesis .
qed

corollary P_nd_compactification_Sync_order_is_arbitrary:
  ‹P⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs = P⟪⟪nd⨂⟦E⟧ As'⟫⟫nd σs'›
  if ‹length σs = length As› ‹length σs' = length As'›
    ‹mset (zip σs As) = mset (zip σs' As')› 
proof -
  have ‹P⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs = ⟦E⟧ (σ, A)∈#mset (zip σs As). P⟪A⟫nd σ›
    by (fact P_nd_compactification_Sync[OF that(1), symmetric])
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip σs' As'). P⟪A⟫nd σ›
    by (simp only: that(3))
  also have ‹… = P⟪⟪nd⨂⟦E⟧ As'⟫⟫nd σs'›
    by (fact P_nd_compactification_Sync[OF that(2)])
  finally show ?thesis .
qed

corollary PSKIPS_d_compactification_Sync_order_is_arbitrary:
  ‹PSKIPS⟪⟪d⨂⟦E⟧ As⟫⟫d σs = PSKIPS⟪⟪d⨂⟦E⟧ As'⟫⟫d σs'›
  if ‹length σs = length As› ‹length σs' = length As'›
    ‹mset (zip σs As) = mset (zip σs' As')› 
    ‹⋀A. A ∈ set As ⟹ ρ_disjoint_ε A›
    ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
            indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
proof -
  have ‹PSKIPS⟪⟪d⨂⟦E⟧ As⟫⟫d σs = ⟦E⟧ (σ, A)∈#mset (zip σs As). PSKIPS⟪A⟫d σ›
    by (rule PSKIPS_d_compactification_Sync[OF that(1, 4, 5), symmetric])
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip σs' As'). PSKIPS⟪A⟫d σ›
    by (simp only: that(3))
  also have ‹… = PSKIPS⟪⟪d⨂⟦E⟧ As'⟫⟫d σs'›
  proof (rule PSKIPS_d_compactification_Sync[OF that(2)])
    show ‹A ∈ set As' ⟹ ρ_disjoint_ε A› for A
      by (metis in_set_impl_in_set_zip2 set_mset_mset set_zip_rightD that(2-4))
  next
    from ‹length σs = length As› ‹length σs' = length As'› ‹mset (zip σs As) = mset (zip σs' As')›
    obtain n where * : ‹length σs = n› ‹length σs' = n› ‹length As = n› ‹length As' = n›
      by (metis length_zip min_less_iff_conj nat_neq_iff size_mset)
    from that(3)[symmetric, THEN permutation_Ex_bij] obtain f
      where ** : ‹bij_betw f {..<n} {..<n}›
        ‹i < n ⟹ zip σs' As' ! i = zip σs As ! f i› for i by (auto simp add: "*")
    { fix i assume ‹i < n›
      hence ‹f i < n› using "**"(1) bij_betwE by blast
      from ‹i < n› have ‹zip σs' As' ! i = (σs' ! i, As' ! i)› by (simp add: "*"(2, 4))
      moreover from ‹f i < n› have ‹zip σs As ! f i = (σs ! f i, As ! f i)›
        by (simp add: "*"(1, 3))
      ultimately have ‹σs' ! i = σs ! f i› ‹As' ! i = As ! f i›
        using "**"(2)[OF ‹i < n›] by simp_all
    } note *** = this
    fix i j assume ‹i < length As'› ‹j < length As'› ‹i ≠ j›
    hence ‹i < n› ‹j < n› by (simp_all add: "*"(2, 4))
    with bij_betw_imp_surj_on[OF "**"(1)] bij_betw_imp_inj_on[OF "**"(1)] ‹i ≠ j›
    have ‹f i < length As› ‹f j < length As› ‹f i ≠ f j›
      by (auto simp add: "*" dest: inj_onD)
    from that(5)[OF this]
    show ‹indep_enabl (As' ! i) (σs' ! i) E (As' ! j) (σs' ! j)›
      by (simp add: "***"(1, 2) ‹i < n› ‹j < n›)
  qed
  finally show ?thesis .
qed

corollary P_d_compactification_Sync_order_is_arbitrary:
  ‹P⟪⟪d⨂⟦E⟧ As⟫⟫d σs = P⟪⟪d⨂⟦E⟧ As'⟫⟫d σs'›
  if ‹length σs = length As› ‹length σs' = length As'›
    ‹mset (zip σs As) = mset (zip σs' As')› 
    ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
            indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
proof -
  have ‹P⟪⟪d⨂⟦E⟧ As⟫⟫d σs = ⟦E⟧ (σ, A)∈#mset (zip σs As). P⟪A⟫d σ›
    by (rule P_d_compactification_Sync[OF that(1, 4), symmetric])
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip σs' As'). P⟪A⟫d σ›
    by (simp only: that(3))
  also have ‹… = P⟪⟪d⨂⟦E⟧ As'⟫⟫d σs'›
  proof (rule P_d_compactification_Sync[OF that(2)])
    from ‹length σs = length As› ‹length σs' = length As'› ‹mset (zip σs As) = mset (zip σs' As')›
    obtain n where * : ‹length σs = n› ‹length σs' = n› ‹length As = n› ‹length As' = n›
      by (metis length_zip min_less_iff_conj nat_neq_iff size_mset)
    from that(3)[symmetric, THEN permutation_Ex_bij] obtain f
      where ** : ‹bij_betw f {..<n} {..<n}›
        ‹i < n ⟹ zip σs' As' ! i = zip σs As ! f i› for i by (auto simp add: "*")
    { fix i assume ‹i < n›
      hence ‹f i < n› using "**"(1) bij_betwE by blast
      from ‹i < n› have ‹zip σs' As' ! i = (σs' ! i, As' ! i)› by (simp add: "*"(2, 4))
      moreover from ‹f i < n› have ‹zip σs As ! f i = (σs ! f i, As ! f i)›
        by (simp add: "*"(1, 3))
      ultimately have ‹σs' ! i = σs ! f i› ‹As' ! i = As ! f i›
        using "**"(2)[OF ‹i < n›] by simp_all
    } note *** = this
    fix i j assume ‹i < length As'› ‹j < length As'› ‹i ≠ j›
    hence ‹i < n› ‹j < n› by (simp_all add: "*"(2, 4))
    with bij_betw_imp_surj_on[OF "**"(1)] bij_betw_imp_inj_on[OF "**"(1)] ‹i ≠ j›
    have ‹f i < length As› ‹f j < length As› ‹f i ≠ f j›
      by (auto simp add: "*" dest: inj_onD)
    from that(4)[OF this]
    show ‹indep_enabl (As' ! i) (σs' ! i) E (As' ! j) (σs' ! j)›
      by (simp add: "***"(1, 2) ‹i < n› ‹j < n›)
  qed
  finally show ?thesis .
qed



section ‹Derived Versions›

lemma PSKIPS_nd_compactification_Sync_upt_version:
  ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = PSKIPS⟪⟪nd⨂⟦E⟧ map A [0..<n]⟫⟫nd (replicate n 0)›
  if ‹⋀i. i < n ⟹ ρ_disjoint_ε (A i)›
    ‹⋀i. i < n ⟹ at_most_1_elem_term (A i)›
    ‹⋀i. i < n ⟹ PSKIPS⟪A i⟫nd 0 = Q i›
proof -
  have ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = ⟦E⟧ i ∈# (mset_set {0..<n}). Q i›
    by (auto intro: mono_MultiSync_eq2)
  also have ‹… = ⟦E⟧ i ∈# (mset_set {0..<n}). PSKIPS⟪A i⟫nd 0›
    by (auto simp add: that(3) intro: mono_MultiSync_eq)
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). PSKIPS⟪A⟫nd σ›
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have ‹⟦E⟧ i∈#mset_set {0..<Suc k}. PSKIPS⟪A i⟫nd 0 =
          PSKIPS⟪A k⟫nd 0 ⟦E⟧ ⟦E⟧ i∈#mset_set {0..<k}. PSKIPS⟪A i⟫nd 0›
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have ‹… = PSKIPS⟪A k⟫nd 0 ⟦E⟧
                    ⟦E⟧ (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). PSKIPS⟪A⟫nd σ›
      by (simp only: Suc.hyps(2))
    also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). PSKIPS⟪A⟫nd σ›
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have ‹… = PSKIPS⟪⟪nd⨂⟦E⟧ map A [0..<n]⟫⟫nd (replicate n 0)›
    by (rule PSKIPS_nd_compactification_Sync)
      (auto simp add: that(1, 2))
  finally show ?thesis .
qed

lemma P_nd_compactification_Sync_upt_version:
  ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = P⟪⟪nd⨂⟦E⟧ map A [0..<n]⟫⟫nd (replicate n 0)›
  if ‹⋀i. i < n ⟹ P⟪A i⟫nd 0 = Q i›
proof -
  have ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = ⟦E⟧ i ∈# (mset_set {0..<n}). Q i›
    by (auto intro: mono_MultiSync_eq2)
  also have ‹… = ⟦E⟧ i ∈# (mset_set {0..<n}). P⟪A i⟫nd 0›
    by (auto simp add: that(1) intro: mono_MultiSync_eq)
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). P⟪A⟫nd σ›
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have ‹⟦E⟧ i∈#mset_set {0..<Suc k}. P⟪A i⟫nd 0 =
          P⟪A k⟫nd 0 ⟦E⟧ ⟦E⟧ i∈#mset_set {0..<k}. P⟪A i⟫nd 0›
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have ‹… = P⟪A k⟫nd 0 ⟦E⟧ ⟦E⟧ (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). P⟪A⟫nd σ›
      by (simp only: Suc.hyps(2))
    also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). P⟪A⟫nd σ›
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have ‹… = P⟪⟪nd⨂⟦E⟧ map A [0..<n]⟫⟫nd (replicate n 0)›
    by (auto intro: P_nd_compactification_Sync)
  finally show ?thesis .
qed

lemma PSKIPS_d_compactification_Sync_upt_version:
  ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = PSKIPS⟪⟪d⨂⟦E⟧ map A [0..<n]⟫⟫d (replicate n 0)›
  if ‹⋀i. i < n ⟹ ρ_disjoint_ε (A i)›
    ‹⋀i j. i < n ⟹ j < n ⟹ i ≠ j ⟹ indep_enabl (A i) 0 E (A j) 0›
    ‹⋀i. i < n ⟹ PSKIPS⟪A i⟫d 0 = Q i›
proof -
  have ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = ⟦E⟧ i ∈# (mset_set {0..<n}). Q i›
    by (auto intro: mono_MultiSync_eq2)
  also have ‹… = ⟦E⟧ i ∈# (mset_set {0..<n}). PSKIPS⟪A i⟫d 0›
    by (auto simp add: that(3) intro: mono_MultiSync_eq)
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). PSKIPS⟪A⟫d σ›
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have ‹⟦E⟧ i∈#mset_set {0..<Suc k}. PSKIPS⟪A i⟫d 0 =
          PSKIPS⟪A k⟫d 0 ⟦E⟧ ⟦E⟧ i∈#mset_set {0..<k}. PSKIPS⟪A i⟫d 0›
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have ‹… = PSKIPS⟪A k⟫d 0 ⟦E⟧
                    ⟦E⟧ (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). PSKIPS⟪A⟫d σ›
      by (simp only: Suc.hyps(2))
    also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). PSKIPS⟪A⟫d σ›
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have ‹… = PSKIPS⟪⟪d⨂⟦E⟧ map A [0..<n]⟫⟫d (replicate n 0)›
    by (rule PSKIPS_d_compactification_Sync)
      (auto simp add: that(1, 2))
  finally show ?thesis .
qed

lemma P_d_compactification_Sync_upt_version:
  ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = P⟪⟪d⨂⟦E⟧ map A [0..<n]⟫⟫d (replicate n 0)›
  if ‹⋀i. i < n ⟹ P⟪A i⟫d 0 = Q i›
    ‹⋀i j. i < n ⟹ j < n ⟹ i ≠ j ⟹ indep_enabl (A i) 0 E (A j) 0›
proof -
  have ‹⟦E⟧ P ∈# mset (map Q [0..<n]). P = ⟦E⟧ i ∈# (mset_set {0..<n}). Q i›
    by (auto intro: mono_MultiSync_eq2)
  also have ‹… = ⟦E⟧ i ∈# (mset_set {0..<n}). P⟪A i⟫d 0›
    by (auto simp add: that(1) intro: mono_MultiSync_eq)
  also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). P⟪A⟫d σ›
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have ‹⟦E⟧ i∈#mset_set {0..<Suc k}. P⟪A i⟫d 0 =
          P⟪A k⟫d 0 ⟦E⟧ ⟦E⟧ i∈#mset_set {0..<k}. P⟪A i⟫d 0›
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have ‹… = P⟪A k⟫d 0 ⟦E⟧ ⟦E⟧ (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). P⟪A⟫d σ›
      by (simp only: Suc.hyps(2))
    also have ‹… = ⟦E⟧ (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). P⟪A⟫d σ›
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have ‹… = P⟪⟪d⨂⟦E⟧ map A [0..<n]⟫⟫d (replicate n 0)›
    by (rule P_d_compactification_Sync) (simp_all add: that(2))
  finally show ?thesis .
qed



section ‹More on Iterated Combine›

lemma ε_iterated_combinend_Sync_general_form:
  ‹length σs = length As ⟹ ε ⟪nd⨂⟦E⟧ As⟫ σs =
   (if As = [] then {}
    else (⋃i < length As. ε (As ! i) (σs ! i)) - E ∪ (⋂i < length As. ε (As ! i) (σs ! i)))›
  for As :: ‹('σ, 'e, 'r) And list›
proof (subst ε_iterated_combinend_Sync, assumption, induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ0 A0) show ?case by auto
next
  case (Cons σ0 σ1 σs A0 A1 As)
  define U and I
    where U_def : ‹U As σs ≡ ⋃i<length As. ε (As ! i) (σs ! i)›
      and I_def : ‹I As σs ≡ ⋂i<length As. ε (As ! i) (σs ! i)›
    for As :: ‹('σ, 'e, 'r) And list› and σs
  have * : ‹U (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0 ∪ U (A1 # As) (σ1 # σs)›
    by (auto simp add: U_def nth_Cons split: nat.split_asm)
  have ** : ‹I (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0 ∩ I (A1 # As) (σ1 # σs)›
    by (auto simp add: I_def nth_Cons split: nat.splits)
  have ‹iterated_combinend_Sync_ε (A0 # A1 # As) E (σ0 # σ1 # σs) =
        combine_sets_Sync (ε A0 σ0) E (U (A1 # As) (σ1 # σs) - E ∪ (I (A1 # As) (σ1 # σs)))›
    by (simp add: U_def I_def Cons.hyps(3))
  also have ‹… = U (A0 # A1 # As) (σ0 # σ1 # σs) - E ∪ I (A0 # A1 # As) (σ0 # σ1 # σs)›
    unfolding "*" "**" by (auto simp add: U_def I_def)
  finally show ?case by (simp add: U_def I_def)
qed

lemma ε_iterated_combined_Sync_general_form:
  ‹length σs = length As ⟹ ε ⟪d⨂⟦E⟧ As⟫ σs =
   (if As = [] then {}
    else (⋃i < length As. ε (As ! i) (σs ! i)) - E ∪ (⋂i < length As. ε (As ! i) (σs ! i)))›
  for As :: ‹('σ, 'e, 'r) Ad list›
proof (subst ε_iterated_combined_Sync, assumption, induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ0 A0) show ?case by auto
next
  case (Cons σ0 σ1 σs A0 A1 As)
  define U and I
    where U_def : ‹U As σs ≡ ⋃i<length As. ε (As ! i) (σs ! i)›
      and I_def : ‹I As σs ≡ ⋂i<length As. ε (As ! i) (σs ! i)›
    for As :: ‹('σ, 'e, 'r) Ad list› and σs
  have * : ‹U (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0 ∪ U (A1 # As) (σ1 # σs)›
    by (auto simp add: U_def nth_Cons split: nat.split_asm)
  have ** : ‹I (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0 ∩ I (A1 # As) (σ1 # σs)›
    by (auto simp add: I_def nth_Cons split: nat.splits)
  have ‹iterated_combined_Sync_ε (A0 # A1 # As) E (σ0 # σ1 # σs) =
        combine_sets_Sync (ε A0 σ0) E (U (A1 # As) (σ1 # σs) - E ∪ (I (A1 # As) (σ1 # σs)))›
    by (simp add: U_def I_def Cons.hyps(3))
  also have ‹… = U (A0 # A1 # As) (σ0 # σ1 # σs) - E ∪ I (A0 # A1 # As) (σ0 # σ1 # σs)›
    unfolding "*" "**" by (auto simp add: U_def I_def)
  finally show ?case by (simp add: U_def I_def)
qed


lemma τ_iterated_combinend_Sync_general_form:
  ‹⟦length σs = length As; σs' ∈ τ ⟪nd⨂⟦E⟧ As⟫ σs a; i < length As⟧ ⟹
   σs' ! i ∈ insert (σs ! i) (τ (As ! i) (σs ! i) a)›
proof (induct σs As arbitrary: σs' i rule: induct_2_lists012)
  case Nil thus ?case by simp
next
  case (single σ0 A0)
  from single.prems show ?case by (auto simp add: behaviour_σ_σs_conv)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  from ‹length σs = length As› have ‹length (σ0 # σ1 # σs) = length (A0 # A1 # As)› by simp
  from same_length_ℛnd_iterated_combinend_Sync_description[OF this]
  have ‹length σs' = length (A0 # A1 # As)›
    by (metis Cons.prems(1) ℛnd.init ℛnd.step)
  then obtain σ0' σ1' σs'' where ‹σs' = σ0' # σ1' # σs''› by (metis length_Suc_conv)
  with Cons.prems Cons.hyps(3)[of ‹σ1' # σs''› ‹nat.pred i›] show ?case
    by (auto simp add: combine_Sync_defs nth_Cons split: if_split_asm nat.splits)
qed


lemma τ_iterated_combined_Sync_general_form:
  ‹length σs = length As ⟹
   τ ⟪d⨂⟦E⟧ As⟫ σs a =
   (if As = [] then ◇ else
    if a ∈ (⋃i < length As. ε (As ! i) (σs ! i)) - E ∪ (⋂i < length As. ε (As ! i) (σs ! i))
    then ⌊map2 (λσ A. if a ∈ ε A σ then ⌈τ A σ a⌉ else σ) σs As⌋ else ◇)›
  for As :: ‹('σ, 'e, 'r) Ad list›
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ0 A0) show ?case by (auto simp add: behaviour_σ_σs_conv ε_simps)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  let ?U = ‹λAs σs. ⋃i<length As. ε (As ! i) (σs ! i)›
  let ?I = ‹λAs σs. ⋂i<length As. ε (As ! i) (σs ! i)›
  show ?case
  proof (split if_split, split if_split, intro conjI impI)
    show ‹A0 # A1 # As = [] ⟹ τ ⟪d⨂⟦E⟧ A0 # A1 # As⟫ (σ0 # σ1 # σs) a = ◇›
      and ‹A0 # A1 # As = [] ⟹ τ ⟪d⨂⟦E⟧ A0 # A1 # As⟫ (σ0 # σ1 # σs) a = ◇› by simp_all
  next
    assume ‹a ∉ ?U (A0 # A1 # As) (σ0 # σ1 # σs) - E ∪ ?I (A0 # A1 # As) (σ0 # σ1 # σs)›
    hence ‹a ∉ ε ⟪d⨂⟦E⟧ A0 # A1 # As⟫ (σ0 # σ1 # σs)›
      by (subst ε_iterated_combined_Sync_general_form)
        (simp_all add: Cons.hyps(1))
    thus ‹τ ⟪d⨂⟦E⟧ A0 # A1 # As⟫ (σ0 # σ1 # σs) a = ◇›
      by (simp add: ε_simps)
  next
    assume * : ‹a ∈ ?U (A0 # A1 # As) (σ0 # σ1 # σs) - E ∪ ?I (A0 # A1 # As) (σ0 # σ1 # σs)›
    have ** : ‹?U (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0 ∪ ?U (A1 # As) (σ1 # σs)›
      by (auto simp add: nth_Cons split: nat.split_asm)
    have *** : ‹?I (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0 ∩ ?I (A1 # As) (σ1 # σs)›
      by (auto simp add: nth_Cons split: nat.splits)
    have **** : ‹?U (A0 # A1 # As) (σ0 # σ1 # σs) - E ∪ ?I (A0 # A1 # As) (σ0 # σ1 # σs) =
                 combine_sets_Sync (ε A0 σ0) E (?U (A1 # As) (σ1 # σs) - E ∪ ?I (A1 # As) (σ1 # σs))›
      unfolding "**" "***" by auto
    have $ : ‹?U (A1 # As) (σ1 # σs) - E ∪ ?I (A1 # As) (σ1 # σs) = ε ⟪d⨂⟦E⟧ A1 # As⟫ (σ1 # σs)›
      by (subst ε_iterated_combined_Sync_general_form)
        (simp_all add: Cons.hyps(1))

    from Cons.hyps(1) have ‹a ∉ ?U As σs ⟹
            map2 (λσ A. if a ∈ ε A σ then ⌈τ A σ a⌉ else σ) σs As = σs›
      by (induct σs As rule: induct_2_lists012)
        (auto simp add: ε_simps lessThan_def, fastforce)
    moreover have ‹?U As σs ⊆ ?U (A1 # As) (σ1 # σs)› by force
    ultimately show ‹τ ⟪d⨂⟦E⟧ A0 # A1 # As⟫ (σ0 # σ1 # σs) a =
                  ⌊map2 (λx y. if a ∈ ε y x then ⌈τ y x a⌉ else x) (σ0 # σ1 # σs) (A0 # A1 # As)⌋›
      using "*" unfolding "****" "$"
      by (simp add: ε_combineRlist_Sync combine_Sync_ε_def, safe,
          auto simp add: combineRlist_Sync_defs ε_simps Cons.hyps(3) lessThan_def subset_iff
          split: option.splits if_splits)
        (metis (no_types, lifting) not_less_eq nth_Cons_Suc)
  qed
qed


lemma indep_implies_only_one_enabled':
  ‹∃!i. i < length As ∧ a ∈ ε (As ! i) (σs ! i)›
  if ‹length σs = length As›
    and ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
            ε (As ! i) (σs ! i) ∩ ε (As ! j) (σs ! j) ⊆ E›
    and ‹a ∈ (⋃i<length As. ε (As ! i) (σs ! i)) - E›
proof (rule ex_ex1I)
  from that(3) show ‹∃i<length As. a ∈ ε (As ! i) (σs ! i)› by auto
next
  fix i j assume ‹i < length As ∧ a ∈ ε (As ! i) (σs ! i)›
    ‹j < length As ∧ a ∈ ε (As ! j) (σs ! j)›
  moreover from that(3) have ‹a ∉ E› by blast
  ultimately show ‹i = j› using that(2)[of i j] by auto
qed

lemma indep_implies_only_one_enabled:
  ‹⟦length σs = length As;
    ⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
           indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j);
    a ∈ (⋃i<length As. ε (As ! i) (σs ! i)) - E⟧ ⟹
    ∃!i. i < length As ∧ a ∈ ε (As ! i) (σs ! i)›
  by (erule indep_implies_only_one_enabled'[where E = E])
    (simp_all add: indep_enabl_def subset_iff, meson IntI ℛd.init)


lemma τ_iterated_combined_Sync_general_form_when_indep:
  ‹τ ⟪d⨂⟦E⟧ As⟫ σs a =
   (if As = [] then ◇
    else   if a ∈ (⋂i<length As. ε (As ! i) (σs ! i))
         then ⌊map2 (λσ A. ⌈τ A σ a⌉) σs As⌋
         else   if a ∈ (⋃i<length As. ε (As ! i) (σs ! i)) - E
              then let i = THE i. i < length As ∧  a ∈ ε (As ! i) (σs ! i)
                    in ⌊σs[i := ⌈τ (As ! i) (σs ! i) a⌉]⌋
              else ◇)›
  (is ‹_ = (if As = [] then ◇ else 
            if a ∈ ?I As σs then ⌊map2 (λσ A. ⌈τ A σ a⌉) σs As⌋ else
            if a ∈ ?U As σs - E then ?upd As σs else ◇)›)
    if ‹length σs = length As›
      ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
            indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
proof (subst τ_iterated_combined_Sync_general_form[OF that(1)], rule if_cong)
  show ‹(if a ∈ ?U As σs - E ∪ ?I As σs
         then ⌊map2 (λx y. if a ∈ ε y x then ⌈τ y x a⌉ else x) σs As⌋ else ◇) =
        (if a ∈ ?I As σs then ⌊map2 (λx y. ⌈τ y x a⌉) σs As⌋ else
         if a ∈ ?U As σs - E then ?upd As σs else ◇)›
  proof (split if_split, intro conjI impI)
    assume * : ‹a ∈ ?I As σs›
    with that(1) have ‹(σ, A) ∈ set (zip σs As) ⟹ a ∈ ε A σ› for σ A
      by (induct σs As rule: list_induct2) (use lessThan_Suc_eq_insert_0 in auto)
    with "*" show ‹(if a ∈ ?U As σs - E ∪ ?I As σs
                    then ⌊map2 (λx y. if a ∈ ε y x then ⌈τ y x a⌉ else x) σs As⌋ else ◇) =
                   ⌊map2 (λx y. ⌈τ y x a⌉) σs As⌋› by auto
  next
    assume * : ‹a ∉ ?I As σs›
    show ‹(if a ∈ ?U As σs - E ∪ ?I As σs
           then ⌊map2 (λx y. if a ∈ ε y x then ⌈τ y x a⌉ else x) σs As⌋ else ◇) =
          (if a ∈ ?U As σs - E then ?upd As σs else ◇)›
    proof (rule if_cong)
      assume ‹a ∈ ?U As σs - E›
      from indep_implies_only_one_enabled[OF that this]
      obtain i where $ : ‹i < length As›  ‹a ∈ ε (As ! i) (σs ! i)›
        ‹j < length As ⟹ j ≠ i ⟹ a ∉ ε (As ! j) (σs ! j)› for j by blast
      have $$ : ‹(THE i. i < length As ∧ a ∈ ε (As ! i) (σs ! i)) = i›
        using "$" by blast
      have ‹⌊map2 (λx y. if a ∈ ε y x then ⌈τ y x a⌉ else x) σs As⌋ =
            ⌊σs[i := ⌈τ (As ! i) (σs ! i) a⌉]⌋›
        by (auto intro!: nth_equalityI simp add: that(1))
          (use that(1) "$"(3) in fastforce, metis "$"(2) nth_list_update_neq)
      also have ‹… = ?upd As σs›
        using "$$" by auto
      finally show ‹⌊map2 (λx y. if a ∈ ε y x then ⌈τ y x a⌉ else x) σs As⌋ = ?upd As σs› .
    qed (use "*" in auto)
  qed
qed simp_all



section ‹More on Events›

lemma events_of_MultiSync_PSKIPS_nd : 
  ‹α(⟦E⟧ (σ, A) ∈# mset (zip σs As). PSKIPS⟪A⟫nd σ) =
   (if As = [] then {} else
    ⋃ σs' ∈ ℛnd ⟪nd⨂⟦E⟧ As⟫ σs. (⋃i<length As. ε (As ! i) (σs' ! i)) - E ∪
                                 (⋂i<length As. ε (As ! i) (σs' ! i)))›
  (is ‹_ = ?rhs›) if ‹length σs = length As›
  ‹⋀A. A ∈ set As ⟹ ρ_disjoint_ε A› ‹⋀A. A ∈ set As ⟹ at_most_1_elem_term A›
proof -
  have ‹⟦E⟧ (σ, A) ∈# mset (zip σs As). PSKIPS⟪A⟫nd σ = PSKIPS⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs›
    by (simp only: PSKIPS_nd_compactification_Sync[OF that])
  also have ‹α(…) = ⋃ (ε ⟪nd⨂⟦E⟧ As⟫ ` ℛnd ⟪nd⨂⟦E⟧ As⟫ σs)› 
  proof (rule events_of_PSKIPS_nd)
    show ‹ρ_disjoint_ε ⟪nd⨂⟦E⟧ As⟫›
      by (simp only: ρ_disjoint_ε_transmission_to_iterated_combinend_Sync that(2))
  qed
  also from same_length_ℛnd_iterated_combinend_Sync_description[OF that(1)]
  have ‹… = ?rhs› by (auto simp add: ε_iterated_combinend_Sync_general_form)
  finally show ?thesis .
qed


lemma events_of_MultiSync_P_nd : 
  ‹α(⟦E⟧ (σ, A) ∈# mset (zip σs As). P⟪A⟫nd σ) =
   (if As = [] then {} else
    ⋃ σs' ∈ ℛnd ⟪nd⨂⟦E⟧ As⟫ σs. (⋃i<length As. ε (As ! i) (σs' ! i)) - E ∪
                                 (⋂i<length As. ε (As ! i) (σs' ! i)))›
  (is ‹_ = ?rhs›) if ‹length σs = length As›
proof -
  have ‹⟦E⟧ (σ, A) ∈# mset (zip σs As). P⟪A⟫nd σ = P⟪⟪nd⨂⟦E⟧ As⟫⟫nd σs›
    by (fact P_nd_compactification_Sync[OF that])
  also have ‹α(…) = ⋃ (ε ⟪nd⨂⟦E⟧ As⟫ ` ℛnd ⟪nd⨂⟦E⟧ As⟫ σs)› by (fact events_of_P_nd)
  also from same_length_ℛnd_iterated_combinend_Sync_description[OF that(1)]
  have ‹… = ?rhs› by (auto simp add: ε_iterated_combinend_Sync_general_form)
  finally show ?thesis .
qed



lemma events_of_MultiSync_PSKIPS_d : 
  ‹α(⟦E⟧ (σ, A) ∈# mset (zip σs As). PSKIPS⟪A⟫d σ) =
   (if As = [] then {} else
    ⋃ σs' ∈ ℛd ⟪d⨂⟦E⟧ As⟫ σs. (⋃i<length As. ε (As ! i) (σs' ! i) - E ∪
                               (⋂i<length As. ε (As ! i) (σs' ! i))))›
  (is ‹_ = ?rhs›) if ‹length σs = length As› ‹⋀A. A ∈ set As ⟹ ρ_disjoint_ε A›
  ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
          indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
proof -
  have ‹⟦E⟧ (σ, A) ∈# mset (zip σs As). PSKIPS⟪A⟫d σ = PSKIPS⟪⟪d⨂⟦E⟧ As⟫⟫d σs›
    by (simp add: PSKIPS_d_compactification_Sync[OF that])
  also have ‹α(…) = ⋃ (ε ⟪d⨂⟦E⟧ As⟫ ` ℛd ⟪d⨂⟦E⟧ As⟫ σs)› 
  proof (rule events_of_PSKIPS_d)
    show ‹ρ_disjoint_ε ⟪d⨂⟦E⟧ As⟫›
      by (simp only: ρ_disjoint_ε_transmission_to_iterated_combined_Sync that(2))
  qed
  also from same_length_ℛd_iterated_combined_Sync_description[OF that(1)]
  have ‹… = ?rhs› by (auto simp add: ε_iterated_combined_Sync_general_form)
  finally show ?thesis .
qed


lemma events_of_MultiSync_P_d : 
  ‹α(⟦E⟧ (σ, A) ∈# mset (zip σs As). P⟪A⟫d σ) =
   (if As = [] then {} else
    ⋃ σs' ∈ ℛd ⟪d⨂⟦E⟧ As⟫ σs. (⋃i<length As. ε (As ! i) (σs' ! i) - E ∪
                                (⋂i<length As. ε (As ! i) (σs' ! i))))›
  (is ‹_ = ?rhs›) if ‹length σs = length As›
  and ‹⋀i j. ⟦i < length As; j < length As; i ≠ j⟧ ⟹
             indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)›
proof -
  have ‹⟦E⟧ (σ, A) ∈# mset (zip σs As). P⟪A⟫d σ = P⟪⟪d⨂⟦E⟧ As⟫⟫d σs›
    by (simp add: P_d_compactification_Sync[OF that])
  also have ‹α(…) = ⋃ (ε ⟪d⨂⟦E⟧ As⟫ ` ℛd ⟪d⨂⟦E⟧ As⟫ σs)› by (fact events_of_P_d)
  also from same_length_ℛd_iterated_combined_Sync_description[OF that(1)]
  have ‹… = ?rhs› by (auto simp add: ε_iterated_combined_Sync_general_form)
  finally show ?thesis .
qed



(*<*)
end
  (*>*)