Theory Diagrams

theory Diagrams
imports HBDAlgebra
(**-----------------------------------------------------------------------------
 * © [I Dragomir, V Preoteasa, S Tripakis]
 *
 * Contributors:
 *  Viorel Preoteasa
 *  Iulia Dragomir
 *
 * This software is governed by the MIT licence and abiding by the rules of
 * distribution of free software. You can use, modify and/or redistribute the
 * software under the terms of the MIT licence included in this distribution.
 *)

subsection‹Diagrams with Named Inputs and Outputs›

(* Was: DiagramFeedbackless.thy *)

theory Diagrams imports HBDAlgebra
begin 
  
text‹This file contains the definition and properties for the named input output diagrams›
  

record ('var, 'a) Dgr = 
    In:: "'var list"
    Out:: "'var list"
    Trs:: 'a
    
context BaseOperationFeedbacklessVars
begin
definition "Var A B = (Out A) ⊗ (In B)"

definition "io_diagram A = (TVs (In A) = TI (Trs A) ∧ TVs (Out A) = TO (Trs A) ∧ distinct (In A) ∧ distinct (Out A))"

definition  Comp :: "('var, 'a) Dgr ⇒ ('var, 'a) Dgr ⇒ ('var, 'a) Dgr"  (infixl ";;" 70) where
  "A ;; B = (let I = In B ⊖ Var A B in let O' = Out A ⊖ Var A B in
    ⦇In = (In A) ⊕ I, Out = O' @ Out B, 
    Trs = [(In A) ⊕ I ↝ In A @ I ] oo Trs A ∥ [I ↝ I] oo [Out A @ I ↝ O' @ In B]  oo ([O' ↝ O'] ∥ Trs B) ⦈)"

lemma io_diagram_Comp: "io_diagram A ⟹ io_diagram B
        ⟹ set (Out A ⊖ In B) ∩ set (Out B) = {} ⟹ io_diagram (A ;; B)"
  by (auto simp add: io_diagram_def Comp_def Let_def Var_def addvars_def set_diff set_inter)
        
lemma Comp_in_disjoint: 
  assumes "io_diagram A"
    and "io_diagram B"
    and "set (In A) ∩ set (In B) = {}"
    shows "A ;; B = (let I = In B ⊖ Var A B in let O' = Out A ⊖ Var A B in
      ⦇In = (In A) @ I, Out = O' @ Out B, Trs = Trs A ∥ [I ↝ I] oo [Out A @ I ↝ O' @ In B]  oo ([O' ↝ O'] ∥ Trs B) ⦈)"
proof -
  have [simp]: "In A ⊕ (In B ⊖ Var A B) = In A @ (In B ⊖ Var A B)"
    by (metis addvars_def assms(3) diff_emptyset diff_inter_right empty_inter_diff)
  have [simp]: "[In A @ (In B ⊖ Var A B) ↝ In A @ (In B ⊖ Var A B)] = ID (TVs (In A) @ TVs (In B ⊖ Var A B))"
    apply (subst distinct_id, simp_all)
    by (metis ‹In A ⊕ (In B ⊖ Var A B) = In A @ (In B ⊖ Var A B)› assms(1) assms(2) distinct_addvars distinct_append distinct_diff io_diagram_def)
      
  have [simp]: "TI (Trs A) = TVs (In A)"
    using assms(1) io_diagram_def by force       
  show ?thesis
    by (simp add: Comp_def Let_def)
qed

lemma Comp_full: "io_diagram A ⟹ io_diagram B ⟹ Out A = In B ⟹
  A ;; B = ⦇In = In A, Out = Out B, Trs = Trs A oo Trs B ⦈"
  by (simp_all add: Comp_def Let_def Var_def io_diagram_def diff_inter_left diff_eq addvars_def  par_empty_left par_empty_right)

lemma Comp_in_out: "io_diagram A ⟹ io_diagram B ⟹ set (Out A) ⊆ set (In B) ⟹
  A ;; B = (let I = diff (In B) (Var A B) in let O' = diff (Out A) (Var A B) in
          ⦇In = In A ⊕ I, Out = Out B, Trs = [In A ⊕ I ↝ In A @ I ] oo Trs A ∥ [I ↝ I] oo [Out A @ I ↝ In B] oo Trs B ⦈)"
  by (simp add: Comp_def Let_def Var_def diff_inter_left diff_inter_right diff_subset par_empty_left)

  
lemma Comp_assoc_new: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹
          set (Out A ⊖ In B) ∩ set (Out B) = {} ⟹  set (Out A ⊗ In B) ∩ set (In C) = {}
          ⟹ A ;; B ;; C = A ;; (B ;; C)"
proof -
            assume [simp]: "io_diagram A"
            assume [simp]: "io_diagram B"
            assume [simp]: "io_diagram C"
            assume U: "set (Out A ⊖ In B) ∩ set (Out B) = {}"
            assume V: " set (Out A ⊗ In B) ∩ set (In C) = {}"
            have A: "In A ⊕ (In B ⊖ Out A ⊗ In B) ⊕ (In C ⊖ (Out A ⊖ Out A ⊗ In B) @ Out B ⊗ In C) = In A ⊕ (In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C)))"
             apply (simp add: diff_inter_left diff_inter_right)
             apply (simp add: addvars_def union_diff diff_union diff_cancel)
             apply (subst diff_sym [THEN sym])
             apply (subst (2) diff_sym [THEN sym])
             apply (subst ZZZ_b)
             using V apply (auto simp add: set_inter set_diff) [1]
             by (simp add: diff_sym)

            have B: "((Out A ⊖ Out A ⊗ In B) @ Out B ⊖ (Out A ⊖ Out A ⊗ In B) @ Out B ⊗ In C) = (Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) @ (Out B ⊖ Out B ⊗ In C)"
              using U by (simp add: diff_inter_left diff_inter_right addvars_def union_diff diff_union diff_cancel diff_notin)

          define x where "x ≡ In A"
          define u where "u ≡ Out A"
          define y where "y ≡ In B"
          define v where "v ≡ Out B"
          define z where "z ≡ In C"
          define w where "w ≡ Out C"

          have [simp]: "TI (Trs A) = TVs x"
            by (metis ‹io_diagram A› io_diagram_def x_def)

          have [simp]: "TI (Trs B) = TVs y"
            by (metis ‹io_diagram B› io_diagram_def y_def)

          have [simp]: "TO (Trs A) = TVs u"
            by (metis ‹io_diagram A› io_diagram_def u_def)

          have [simp]: "distinct x"
           by (metis ‹io_diagram A› io_diagram_def x_def)

          have [simp]: "distinct u"
           by (metis ‹io_diagram A› io_diagram_def u_def)

          have [simp]: "distinct y"
           by (metis ‹io_diagram B› io_diagram_def y_def)

          have [simp]: "distinct z"
           by (metis ‹io_diagram C› io_diagram_def z_def)

          have [simp]: "distinct (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)"
            by (simp add: )

          have [simp]: "distinct (x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))))"
            by (simp add: distinct_addvars )

          have [simp]: "distinct (x ⊕ (y ⊖ u ⊗ y))"
            by (simp add: distinct_addvars )

          have [simp]: "set (x ⊕ (y ⊖ u ⊗ y)) ⊆ set (x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))))"
            apply (simp add: set_addvars set_diff set_inter)
            by blast

          have [simp]: "set (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ⊆ set (x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))))"
            apply (simp add: diff_inter_left diff_inter_right diff_union addvars_minus set_addvars)
            apply (subgoal_tac "set (z ⊖ (u ⊖ y) ⊖ v) ⊆ set (z ⊖ v ⊖ u)")
            apply blast
            apply (subst diff_sym)
            apply (simp add: set_diff)
            by (metis diff_cancel_set Int_ac(3) V diff_inter_left eq_iff set_diff u_def y_def z_def)

          have [simp]: "set x ⊆ set (x ⊕ (y ⊖ u ⊗ y)) ∧ set (y ⊖ u ⊗ y) ⊆ set (x ⊕ (y ⊖ u ⊗ y))"
            by (simp add: set_addvars set_diff set_inter)

          have [simp]: "distinct (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))"
            by (simp add: distinct_addvars )
            
          have [simp]: "set u ∩ set (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) = {}"
            by (simp add: set_diff set_inter set_addvars, auto)
            
          have [simp]: "distinct (y ⊕ (z ⊖ v ⊗ z))"
            by (simp add: distinct_addvars )
            
          have [simp]: "set (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ⊆ set u ∪ set (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))"
            by (simp add: set_diff set_inter set_addvars, auto)
          have [simp]: "set (y ⊕ (z ⊖ v ⊗ z)) ⊆ set u ∪ set (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))"
            by (simp add: set_diff set_inter set_addvars, auto)
          have [simp]: "set y ⊆ set (y ⊕ (z ⊖ v ⊗ z))"
            by (simp add: set_diff set_inter set_addvars)
            
          have [simp]: "set (z ⊖ v ⊗ z) ⊆ set (y ⊕ (z ⊖ v ⊗ z))"
            by (simp add: set_diff set_inter set_addvars)

          have [simp]: "TO (Trs B) = TVs v"
            by (metis ‹io_diagram B› io_diagram_def v_def)
          have [simp]: " TI (Trs C) = TVs z"
            by (metis ‹io_diagram C› io_diagram_def z_def)

          have "[x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (x ⊕ (y ⊖ u ⊗ y)) @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)] oo
              ([x ⊕ (y ⊖ u ⊗ y) ↝ x @ (y ⊖ u ⊗ y)] oo Trs A ∥ [y ⊖ u ⊗ y ↝ y ⊖ u ⊗ y] oo [u @ (y ⊖ u ⊗ y) ↝ (u ⊖ u ⊗ y) @ y] oo [u ⊖ u ⊗ y ↝ u ⊖ u ⊗ y] ∥ Trs B) ∥
              [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z] oo
              [(u ⊖ u ⊗ y) @ v @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) @ z] oo
              [(u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z)] ∥ Trs C
              = 
              [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (x ⊕ (y ⊖ u ⊗ y)) @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)] oo
              ([x ⊕ (y ⊖ u ⊗ y) ↝ x @ (y ⊖ u ⊗ y)] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo Trs A ∥ [y ⊖ u ⊗ y ↝ y ⊖ u ⊗ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u @ (y ⊖ u ⊗ y) ↝ (u ⊖ u ⊗ y) @ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u ⊖ u ⊗ y ↝ u ⊖ u ⊗ y] ∥ Trs B ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]) oo
              [(u ⊖ u ⊗ y) @ v @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) @ z] oo
              [(u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z)] ∥ Trs C" (is "?Tx = _")

          apply (subst comp_parallel_distrib, simp_all)
          apply (subst comp_parallel_distrib, simp_all )
            by (subst comp_parallel_distrib, simp_all)
               
          also have "... = [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (x ⊕ (y ⊖ u ⊗ y)) @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)] oo
              [x ⊕ (y ⊖ u ⊗ y) ↝ x @ (y ⊖ u ⊗ y)] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo Trs A ∥ [y ⊖ u ⊗ y ↝ y ⊖ u ⊗ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u @ (y ⊖ u ⊗ y) ↝ (u ⊖ u ⊗ y) @ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u ⊖ u ⊗ y ↝ u ⊖ u ⊗ y] ∥ Trs B ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z] oo
              [(u ⊖ u ⊗ y) @ v @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) @ z] oo
              [(u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z)] ∥ Trs C"
           by (simp add: comp_assoc )

           also have "... = [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝x @ (y ⊖ u ⊗ y) @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)]
              oo Trs A ∥ [y ⊖ u ⊗ y ↝ y ⊖ u ⊗ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u @ (y ⊖ u ⊗ y) ↝ (u ⊖ u ⊗ y) @ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u ⊖ u ⊗ y ↝ u ⊖ u ⊗ y] ∥ Trs B ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z] oo
              [(u ⊖ u ⊗ y) @ v @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) @ z] oo
              [(u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z)] ∥ Trs C"
           by (subst switch_par_comp, simp_all)

           also have "... = [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝x @ (y ⊖ u ⊗ y) @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)]
              oo Trs A ∥ [y ⊖ u ⊗ y ↝ y ⊖ u ⊗ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo ([u @ (y ⊖ u ⊗ y) ↝ (u ⊖ u ⊗ y) @ y] ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z]
              oo [u ⊖ u ⊗ y ↝ u ⊖ u ⊗ y] ∥ Trs B ∥ [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z] oo
              [(u ⊖ u ⊗ y) @ v @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) @ z] oo
              [(u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z)] ∥ Trs C)" (is "_ = ?Ty")
           by (simp add: comp_assoc  )

          finally have E: "?Tx = ?Ty"
            by simp

          thm comp_parallel_distrib

          have [simp]: "distinct (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) )"
            by (simp add: diff_inter_left diff_inter_right)

          have "[x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ x @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))] 
              oo Trs A ∥ [y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] oo
              [u @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (y ⊕ (z ⊖ v ⊗ z))] oo
              [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥
              ([y ⊕ (z ⊖ v ⊗ z) ↝ y @ (z ⊖ v ⊗ z)] oo Trs B ∥ [z ⊖ v ⊗ z ↝ z ⊖ v ⊗ z] oo [v @ (z ⊖ v ⊗ z) ↝ (v ⊖ v ⊗ z) @ z] oo [v ⊖ v ⊗ z ↝ v ⊖ v ⊗ z] ∥ Trs C)
              = 
                [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ x @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))] 
                oo Trs A ∥ [y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] oo
                [u @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (y ⊕ (z ⊖ v ⊗ z))] oo
                  ([u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [y ⊕ (z ⊖ v ⊗ z) ↝ y @ (z ⊖ v ⊗ z)] oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ (Trs B ∥ [z ⊖ v ⊗ z ↝ z ⊖ v ⊗ z]) oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [v @ (z ⊖ v ⊗ z) ↝ (v ⊖ v ⊗ z) @ z] oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ ([v ⊖ v ⊗ z ↝ v ⊖ v ⊗ z] ∥ Trs C))" (is "?Ta = _")

          apply (subst comp_parallel_distrib, simp_all)
          apply (subst comp_parallel_distrib, simp_all )
          by (subst comp_parallel_distrib, simp_all )

          also have "... =  [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ x @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))] 
                oo Trs A ∥ [y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] oo
                  ([u @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (y ⊕ (z ⊖ v ⊗ z))] oo
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [y ⊕ (z ⊖ v ⊗ z) ↝ y @ (z ⊖ v ⊗ z)]) oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ (Trs B ∥ [z ⊖ v ⊗ z ↝ z ⊖ v ⊗ z]) oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [v @ (z ⊖ v ⊗ z) ↝ (v ⊖ v ⊗ z) @ z] oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ ([v ⊖ v ⊗ z ↝ v ⊖ v ⊗ z] ∥ Trs C)"
           by (simp add: comp_assoc  )

           also have "... = [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ x @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))] 
                oo Trs A ∥ [y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] oo
                  [u @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (y @ (z ⊖ v ⊗ z))] oo
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ (Trs B ∥ [z ⊖ v ⊗ z ↝ z ⊖ v ⊗ z]) oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [v @ (z ⊖ v ⊗ z) ↝ (v ⊖ v ⊗ z) @ z] oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ ([v ⊖ v ⊗ z ↝ v ⊖ v ⊗ z] ∥ Trs C)"
           by (subst switch_par_comp, simp_all)

           also have "... = [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ x @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))] 
                oo Trs A ∥ [y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] oo
                  ([u @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (y @ (z ⊖ v ⊗ z))] oo
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ Trs B ∥ [z ⊖ v ⊗ z ↝ z ⊖ v ⊗ z] oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [v @ (z ⊖ v ⊗ z) ↝ (v ⊖ v ⊗ z) @ z] oo 
                  [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥ [v ⊖ v ⊗ z ↝ v ⊖ v ⊗ z] ∥ Trs C)" (is "_ = ?Tb")
           by (simp add: comp_assoc par_assoc  )

          finally have F: "?Ta = ?Tb"
            by simp


          have [simp]: "distinct  (z ⊖ (u ⊖ y) @ v)"
            by (metis ‹distinct (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)› diff_inter_left diff_inter_right)


          define z' where "z' ≡ newvars (y ⊖ u) (TVs (z ⊖ (u ⊖ y) @ v))"

          have [simp]: "distinct (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
            by (metis ‹distinct (x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))))› diff_inter_right)
          have "distinct (y ⊖ u)"
            by (simp add: )

          have [simp]: "distinct z'"
            by (simp add: z'_def)

          have [simp]: "set (y ⊖ u) ∩ set z' = {}"
            by (simp add: z'_def)

          have [simp]: "distinct (y ⊕ (z ⊖ v) ⊖ u)"
            by (simp add:  distinct_addvars)

          have [simp]: "TVs (z ⊖ (u ⊖ y) @ v) = TVs z'"
            by (simp add: z'_def)

          have [simp]:"set x ⊆ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
            by (simp add: set_diff set_inter set_addvars)
            
          have [simp]:"set (y ⊖ u) ⊆ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
            by (simp add: set_diff set_inter set_addvars, auto)
          
          have [simp]:"set (z ⊖ (u ⊖ y) @ v) ⊆ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
            by (metis ‹set (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ⊆ set (x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))))› diff_inter_left diff_inter_right)

          have [simp]:"set (y ⊕ (z ⊖ v) ⊖ u) ⊆ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
            by (simp add: set_addvars)

          have [simp]: "distinct (y ⊖ u)"
            by (simp add: )

          have H: "Trs A ∥ [y ⊖ u ↝ y ⊖ u] ∥ [z ⊖ (u ⊖ y) @ v ↝ z ⊖ (u ⊖ y) @ v] = Trs A ∥ [(y ⊖ u) @ z' ↝ (y ⊖ u) @ z']"
            by (simp add: par_assoc distinct_id)

          define u' where "u' ≡ newvars (x @ y @ z @ v) (TVs u)"

          have b: "set (x @ y @ z @ v) ∩ set u' = {}"
            by (simp add: u'_def del: set_append)
            

          have [simp]: "distinct u'"
            by (simp add: u'_def)
          from b have [simp]: "set u' ∩ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) = {}"
            by (simp add: set_addvars set_diff, auto)
          have [simp]: "set u ∩ set (y ⊕ (z ⊖ v) ⊖ u) = {}"
            by (metis ‹set u ∩ set (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) = {}› diff_inter_right)
          have [simp]: "TVs u' = TVs u"
            by (simp add: u'_def)

 
          have Ha: "[u ↝ u] ∥ [x ⊕ (y ⊕ (z ⊖ v) ⊖ u) ↝ (y ⊖ u) @ (z ⊖ (u ⊖ y) @ v)] =  [u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ u' @ ((y ⊖ u) @ (z ⊖ (u ⊖ y) @ v))]"
            proof -
            have "[u ↝ u] ∥ [x ⊕ (y ⊕ (z ⊖ v) ⊖ u) ↝ (y ⊖ u) @ (z ⊖ (u ⊖ y) @ v)] = [u' ↝ u'] ∥ [x ⊕ (y ⊕ (z ⊖ v) ⊖ u) ↝ (y ⊖ u) @ (z ⊖ (u ⊖ y) @ v)]"
              by (simp add: par_assoc distinct_id)
            also have "... = [u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ u' @ ((y ⊖ u) @ (z ⊖ (u ⊖ y) @ v))]"
              by (simp add: par_switch)
            finally show ?thesis by simp
            qed
       
          have Hb: "[u ↝ u] ∥ [x ⊕ (y ⊕ (z ⊖ v) ⊖ u) ↝ y ⊕ (z ⊖ v) ⊖ u] = [u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ u' @ (y ⊕ (z ⊖ v) ⊖ u)]"
            proof -
            have "[u ↝ u] ∥ [x ⊕ (y ⊕ (z ⊖ v) ⊖ u) ↝ y ⊕ (z ⊖ v) ⊖ u] = [u' ↝ u'] ∥ [x ⊕ (y ⊕ (z ⊖ v) ⊖ u) ↝ y ⊕ (z ⊖ v) ⊖ u]"
              by (simp add: par_assoc distinct_id)
            also have "... =  [u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ u' @ (y ⊕ (z ⊖ v) ⊖ u)]"
              by (simp add: par_switch)
            finally show ?thesis by simp
            qed

         have [simp]: " Subst (z ⊖ (u ⊖ y) @ v) (z ⊖ (u ⊖ y) @ v) (z ⊖ (u ⊖ y) @ v) = (z ⊖ (u ⊖ y) @ v)"
          by (simp add: Subst_eq)

         have [simp]: "Subst (u @ (y ⊖ u)) (u' @ (y ⊖ u)) ((u ⊖ y) @ y) = Subst u u' (u ⊖ y) @ Subst u u' y"
          apply (simp add: Subst_append, safe)
          apply (subst Subst_cancel_left, simp_all)
          apply (rule TVs_length_eq, simp)
          apply (subst Subst_cancel_left, simp_all)
          by (rule TVs_length_eq, simp)
        
         have Hc: "[u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ u' @ (y ⊖ u) @ (z ⊖ (u ⊖ y) @ v)] oo [u @ (y ⊖ u) ↝ (u ⊖ y) @ y] ∥ [z ⊖ (u ⊖ y) @ v ↝ z ⊖ (u ⊖ y) @ v]
          = [u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ Subst u u' (u ⊖ y) @ Subst u u' y @ (z ⊖ (u ⊖ y) @ v)]"
            apply (subst append_assoc [THEN sym])
            apply (subst switch_par_comp_Subst, simp_all)
            apply (simp_all add: set_diff set_addvars )
            apply auto
            using  V  by (auto simp add: set_inter set_diff u_def y_def x_def v_def z_def) [1]

         have [simp]: "Subst (u @ (y ⊕ (z ⊖ v) ⊖ u)) (u' @ (y ⊕ (z ⊖ v) ⊖ u)) ((u ⊖ y ⊕ (z ⊖ v)) @ y @ (z ⊖ v)) 
            = Subst u  u' ((u ⊖ y ⊕ (z ⊖ v)) @ y @ (z ⊖ v))"
          apply (subst Subst_cancel_left, simp_all)
          by (rule TVs_length_eq, simp)

         thm par_switch_eq_a

         have J: "[u ⊖ (y ⊕ (z ⊖ v)) ↝ u ⊖ (y ⊕ (z ⊖ v))] ∥ [v ⊖ z ↝ v ⊖ z] =  [(u ⊖ (y ⊕ (z ⊖ v))) @ (v ⊖ z) ↝ (u ⊖ (y ⊕ (z ⊖ v))) @ (v ⊖ z)]"
          apply (subst par_switch, simp_all, safe)
          using ‹io_diagram B› distinct_diff io_diagram_def v_def apply blast
          apply (simp add: set_diff set_addvars set_inter, auto)
          using U by (auto simp add: set_inter set_diff u_def y_def v_def z_def) [1]

         have [simp]: "distinct v"
          using ‹io_diagram B› io_diagram_def v_def by blast

         have [simp]: "distinct (z ⊖ v)"
          by (simp add: )

         have [simp]: "distinct (u ⊖ y)"
          by (simp add: )

         have [simp]: "distinct (u ⊖ (y ⊕ (z ⊖ v)))"
          by (simp add: )

          have [simp]: "length u' = length u"
            by (rule TVs_length_eq, simp)

         have [simp]: "set (Subst u u' (u ⊖ y)) ⊆ set u' ∪ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
          by (rule set_SubstI, simp_all add: set_diff set_addvars, auto)

         have [simp]: "set (Subst u u' y) ⊆ set u' ∪ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
          by (rule set_SubstI, simp_all add: set_diff set_addvars, auto)

        have [simp]: "set (z ⊖ (u ⊖ y) @ v) ⊆ set u' ∪ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
          apply (simp add: set_diff set_addvars, auto)
          using  V  by (auto simp add: set_inter set_diff u_def y_def x_def v_def z_def) [1]

        have [simp]: "set (Subst u u' (u ⊖ (y ⊕ (z ⊖ v)))) ⊆ set u' ∪ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
          by (rule set_SubstI, simp_all add: set_diff set_addvars, auto)
        
        have [simp]: "set (Subst u u' (z ⊖ v)) ⊆ set u' ∪ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))"
          by (rule set_SubstI, simp_all add: set_diff set_addvars, auto)

         define v' where "v' ≡ newvars (u' @ u @ x @ y @ z) (TVs v)"  

         have [simp]: "distinct v'"
          by (simp add: v'_def)

        have a: "set (u' @ u @ x @ y @ z) ∩ set v' = {}"
          by (simp add: v'_def del: set_append)

        from this have [simp]: "set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ∩ set v' = {}"
          by (simp add: set_diff set_addvars, auto)
          

         from a have [simp]: "set u' ∩ set v' = {}"
          by auto

         have [simp]: "TVs v' = TVs v"
          by (simp add: v'_def)

         have [simp]: "set (Subst u u' (u ⊖ (y ⊕ (z ⊖ v)))) ⊆ set u' ∪ (set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ∪ set v')"
          by (rule set_SubstI, simp_all add: set_diff set_addvars, auto)

          have [simp]: " set v' ⊆ set u' ∪ (set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ∪ set v')"
            by auto

         have [simp]: "set (Subst u u' (z ⊖ v)) ⊆ set u' ∪ (set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ∪ set v')"
          by (rule set_SubstI, simp_all add: set_diff set_addvars, auto)

          thm Subst_Subst_a
          thm Subst_Subst
         have [simp]: "length v' = length v"
          by (rule TVs_length_eq, simp)

         have [simp]: "set v ∩ set (u ⊖ (y ⊕ (z ⊖ v))) = {}"
          using U by (auto simp add: set_inter set_diff set_addvars u_def y_def x_def v_def z_def) [1]

        thm Subst_not_in

        thm Subst_Subst

      have "set (u ⊖ y) ⊆ set (u ⊖ v)"
        using U by (auto simp add: set_inter set_diff set_addvars u_def y_def x_def v_def z_def) [1]
            

       have Ka:"Subst ((u ⊖ y) @ v) (Subst u u' (u ⊖ y) @ v') z = Subst ((u ⊖ y ⊖ v) @ v) (Subst u u' (u ⊖ y ⊖ v) @ v') z"
        apply (subgoal_tac "(u ⊖ y ⊖ v) = (u ⊖ y)")
        apply simp
        apply (rule diff_disjoint)
        using U by (auto simp add: set_inter set_diff set_addvars u_def y_def x_def v_def z_def) [1]

      from a have [simp]: "set v' ∩ set (z ⊖ v) = {}"
        by (simp add: set_diff set_addvars, auto)

      from a have [simp]: " set v' ∩ set (u ⊖ y ⊖ v) = {}"
       by  (simp add: set_diff set_addvars, auto)

      have [simp]: "set (Subst u u' (z ⊖ v)) ∩ set v = {}"
        apply (subgoal_tac "set (Subst u u' (z ⊖ v)) ⊆ - set v")
        apply auto [1]
        apply (rule set_SubstI, simp_all add: set_diff)
        using b by auto
 
      have [simp]: "set (Subst u u' (u ⊖ y ⊖ v)) ∩ set v = {}"
        apply (subgoal_tac "set (Subst u u' (u ⊖ y ⊖ v)) ⊆ - set v")
        apply auto [1]
        apply (rule set_SubstI, simp_all add: set_diff)
        using b by auto

      have [simp]: "set u ∩ set y ∩ set z = {}"
        using V by (auto simp add: set_inter set_diff set_addvars u_def y_def x_def v_def z_def) [1]
  
      have Kb: "Subst (v @ (z ⊖ v)) (v' @ Subst u u' (z ⊖ v)) z = Subst (v @ (u ⊖ y ⊖ v)) (v' @ Subst u u' (u ⊖ y ⊖ v)) z"
        apply (subst Subst_switch, simp_all)
        apply (subst Subst_comp, simp_all)
        apply (simp add: set_diff)
        apply auto [1]
        apply (subst Comp_assoc_new_subst_aux [of _ y], simp_all)

        apply (subst Subst_switch, simp_all)
        apply (subst Subst_comp, simp_all)
        by (auto simp add: set_diff) [1]

         have K: "Subst ((u ⊖ y) @ v @ (z ⊖ (u ⊖ y) @ v)) (Subst u u' (u ⊖ y) @ v' @ (z ⊖ (u ⊖ y) @ v)) ((u ⊖ (y ⊕ (z ⊖ v))) @ (v ⊖ z) @ z)
            = Subst u u' (u ⊖ (y ⊕ (z ⊖ v))) @ Subst (v @ (z ⊖ v)) (v' @ Subst u u' (z ⊖ v)) ((v ⊖ z) @ z)"
            apply (simp add: Subst_append, safe)
            apply (unfold append_assoc [THEN sym])
            apply (subst Subst_cancel_left)
            apply (auto simp add: set_diff) [2]
            apply (subst Subst_not_in, simp_all)
            apply (subst Subst_Subst, simp_all)
            apply (simp add: set_diff set_addvars, auto)

            apply (unfold append_assoc [THEN sym])
            apply (subst Subst_not_in, simp_all)
            apply (simp add: set_diff, auto)

            apply (subst (2) Subst_not_in, simp_all)
            apply (simp add: set_diff, auto)
            apply (subst Subst_not_in_a, simp_all)
            apply (simp add: set_diff, auto)
            using U apply (auto simp add: set_inter set_diff set_addvars u_def y_def x_def v_def z_def) [1]


            apply (unfold append_assoc [THEN sym])
            apply (subst Subst_cancel_left)
            apply (auto simp add: set_diff) [2]
            apply (simp add: Ka Kb)
            apply (subst Subst_switch, simp_all)
            by (simp add: set_diff, auto)
 
         have I: "[u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ Subst u u' (u ⊖ y) @ Subst u u' y @ (z ⊖ (u ⊖ y) @ v)] oo [u ⊖ y ↝ u ⊖ y] ∥ Trs B ∥ [z ⊖ (u ⊖ y) @ v ↝ z ⊖ (u ⊖ y) @ v] oo
            [(u ⊖ y) @ v @ (z ⊖ (u ⊖ y) @ v) ↝ (u ⊖ (y ⊕ (z ⊖ v))) @ (v ⊖ z) @ z]
             =
            [u' @ (x ⊕ (y ⊕ (z ⊖ v) ⊖ u)) ↝ Subst u u' (u ⊖ (y ⊕ (z ⊖ v))) @ Subst u u' y @ Subst u u' (z ⊖ v)] oo [u ⊖ (y ⊕ (z ⊖ v)) ↝ u ⊖ (y ⊕ (z ⊖ v))] ∥ Trs B ∥ [z ⊖ v ↝ z ⊖ v] oo
            [u ⊖ (y ⊕ (z ⊖ v)) ↝ u ⊖ (y ⊕ (z ⊖ v))] ∥ [v @ (z ⊖ v) ↝ (v ⊖ z) @ z]"
          apply (rule_tac v = v' in par_switch_eq_a, simp_all add:  )
           apply (subst switch_comp_subst, simp_all) 
             (*
          apply (simp add: set_diff)
          using U  apply (simp add: v_def u_def z_def y_def set_diff set_inter set_addvars)*)
          apply auto [1]
          apply safe         
          apply (meson UnE ‹set (Subst u u' (u ⊖ y)) ⊆ set u' ∪ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))› subsetCE)
          using ‹set (z ⊖ (u ⊖ y) @ v) ⊆ set (x ⊕ (y ⊕ (z ⊖ v) ⊖ u))› apply blast
          using U V apply (simp add: v_def u_def z_def y_def set_diff set_inter set_addvars)
          using U V apply (simp add: v_def u_def z_def y_def set_diff set_inter set_addvars)
          using U V apply (simp add: v_def u_def z_def y_def set_diff set_inter set_addvars)
          apply (subst switch_par_comp_Subst)
          apply (simp_all add: set_diff)
          by (simp add: K)

         have "?Ty = ?Tb"
            apply (simp add: diff_inter_left diff_inter_right H)
            apply (rule par_switch_eq, simp_all add:  )
            apply (simp add: comp_assoc [THEN sym]  )
            apply (simp add: Ha Hb Hc)
            apply (subst switch_comp_subst, simp_all)         
            apply (simp add: le_supI2)
            apply (metis ‹set (u ⊖ (u ⊗ (y ⊕ (z ⊖ v ⊗ z)))) ⊆ set u ∪ set (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))› ‹set (y ⊕ (z ⊖ v ⊗ z)) ⊆ set u ∪ set (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))› ‹set (z ⊖ v ⊗ z) ⊆ set (y ⊕ (z ⊖ v ⊗ z))› ‹set y ⊆ set (y ⊕ (z ⊖ v ⊗ z))› diff_inter_left diff_inter_right subset_trans)
            apply (simp add: Subst_append)
            using I apply (simp add: comp_assoc  )
            apply (subst J)

            by (simp add: J)


         from this E and F have " [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (x ⊕ (y ⊖ u ⊗ y)) @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z)] oo
              ([x ⊕ (y ⊖ u ⊗ y) ↝ x @ (y ⊖ u ⊗ y)] oo Trs A ∥ [y ⊖ u ⊗ y ↝ y ⊖ u ⊗ y] oo [u @ (y ⊖ u ⊗ y) ↝ (u ⊖ u ⊗ y) @ y] oo [u ⊖ u ⊗ y ↝ u ⊖ u ⊗ y] ∥ Trs B) ∥
              [z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z ↝ z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z] oo
              [(u ⊖ u ⊗ y) @ v @ (z ⊖ (u ⊖ u ⊗ y) @ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) @ z] oo
              [(u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (v ⊖ v ⊗ z)] ∥ Trs C 
              =
              [x ⊕ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ x @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)))] oo Trs A ∥ [y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] oo
              [u @ (y ⊕ (z ⊖ v ⊗ z) ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) ↝ (u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))) @ (y ⊕ (z ⊖ v ⊗ z))] oo
              [u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z)) ↝ u ⊖ u ⊗ (y ⊕ (z ⊖ v ⊗ z))] ∥
              ([y ⊕ (z ⊖ v ⊗ z) ↝ y @ (z ⊖ v ⊗ z)] oo Trs B ∥ [z ⊖ v ⊗ z ↝ z ⊖ v ⊗ z] oo [v @ (z ⊖ v ⊗ z) ↝ (v ⊖ v ⊗ z) @ z] oo [v ⊖ v ⊗ z ↝ v ⊖ v ⊗ z] ∥ Trs C)"
          by simp


          from this have C: "[In A ⊕ (In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) ↝ (In A ⊕ (In B ⊖ Out A ⊗ In B)) @ (In C ⊖ (Out A ⊖ Out A ⊗ In B) @ Out B ⊗ In C)] oo
              ([In A ⊕ (In B ⊖ Out A ⊗ In B) ↝ In A @ (In B ⊖ Out A ⊗ In B)] oo Trs A ∥ [In B ⊖ Out A ⊗ In B ↝ In B ⊖ Out A ⊗ In B] oo [Out A @ (In B ⊖ Out A ⊗ In B) ↝ (Out A ⊖ Out A ⊗ In B) @ In B] oo
               [Out A ⊖ Out A ⊗ In B ↝ Out A ⊖ Out A ⊗ In B] ∥ Trs B) ∥
              [In C ⊖ (Out A ⊖ Out A ⊗ In B) @ Out B ⊗ In C ↝ In C ⊖ (Out A ⊖ Out A ⊗ In B) @ Out B ⊗ In C] oo
              [(Out A ⊖ Out A ⊗ In B) @ Out B @ (In C ⊖ (Out A ⊖ Out A ⊗ In B) @ Out B ⊗ In C) ↝ (Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) @ (Out B ⊖ Out B ⊗ In C) @ In C] oo
              [(Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) @ (Out B ⊖ Out B ⊗ In C) ↝ (Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) @ (Out B ⊖ Out B ⊗ In C)] ∥ Trs C =
              [In A ⊕ (In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) ↝ In A @ (In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C)))] oo
              Trs A ∥ [In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C)) ↝ In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))] oo
              [Out A @ (In B ⊕ (In C ⊖ Out B ⊗ In C) ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) ↝ (Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))) @ (In B ⊕ (In C ⊖ Out B ⊗ In C))] oo
              [Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C)) ↝ Out A ⊖ Out A ⊗ (In B ⊕ (In C ⊖ Out B ⊗ In C))] ∥
              ([In B ⊕ (In C ⊖ Out B ⊗ In C) ↝ In B @ (In C ⊖ Out B ⊗ In C)] oo Trs B ∥ [In C ⊖ Out B ⊗ In C ↝ In C ⊖ Out B ⊗ In C] oo [Out B @ (In C ⊖ Out B ⊗ In C) ↝ (Out B ⊖ Out B ⊗ In C) @ In C] oo
               [Out B ⊖ Out B ⊗ In C ↝ Out B ⊖ Out B ⊗ In C] ∥ Trs C)"
             by (simp add: x_def [THEN symmetric] y_def [THEN symmetric] z_def [THEN symmetric] u_def [THEN symmetric] v_def [THEN symmetric] w_def [THEN symmetric])

          show "A ;; B ;; C = A ;; (B ;; C)"
            by (simp add: Comp_def Let_def Var_def A B C)
      qed

    lemma Comp_assoc_a: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹
          set (In B) ∩ set (In C) = {} ⟹
          set (Out A) ∩ set (Out B) = {} ⟹
          A ;; B ;; C = A ;; (B ;; C)"
        apply (rule Comp_assoc_new, simp_all)
         apply (metis diff.simps(1) inter_diff_distrib set_empty2 set_inter)
        by (simp add: inf_assoc set_inter)

    (*to do too many conditions in next, replace with the theorem above*)
(*
    lemma Comp_assoc: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹
          set (In A) ∩ set (In B) = {} ⟹ set (In B) ∩ set (In C) = {} ⟹ set (In A) ∩ set (In C) = {} ⟹
          set (Out A) ∩ set (Out B) = {} ⟹ set (Out B) ∩ set (Out C) = {} ⟹ set (Out A) ∩ set (Out C) = {} ⟹
          A ;; B ;; C = A ;; (B ;; C)"
      apply (rule Comp_assoc_new)
          apply simp
         apply simp
        apply simp
         apply (metis diff.simps(1) inter_diff_distrib set_empty2 set_inter)
        by (simp add: inf_assoc set_inter)
*)

definition Parallel :: "('var, 'a) Dgr ⇒ ('var, 'a) Dgr ⇒ ('var, 'a) Dgr"  (infixl "|||" 80) where
   "A ||| B = ⦇In = In A ⊕ In B, Out = Out A @ Out B, Trs = [In A ⊕ In B ↝ In A @ In B] oo (Trs A ∥ Trs B) ⦈"
       

      lemma io_diagram_Parallel: "io_diagram A ⟹ io_diagram B  ⟹ set (Out A) ∩ set (Out B) = {} ⟹ io_diagram (A ||| B)"
        by (simp add: io_diagram_def Parallel_def   distinct_addvars)

 
      lemma Parallel_indep: "io_diagram A ⟹ io_diagram B  ⟹ set (In A) ∩ set (In B) = {} ⟹
        A ||| B = ⦇In = In A @ In B, Out = Out A @ Out B, Trs = (Trs A ∥ Trs B) ⦈"
        apply (simp add: Parallel_def, safe)
        apply (simp add: addvars_def diff_distinct)
        apply (subgoal_tac "In A ⊕ In B = In A @ In B")
        apply simp
        apply (subst distinct_id)
        apply (simp add: io_diagram_def)
        apply (subst comp_id_left_simp)
        apply (simp add: io_diagram_def)
        apply simp
        by (simp add: addvars_def diff_distinct)


      lemma Parallel_assoc_gen: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ 
            A ||| B ||| C = A ||| (B ||| C)"
        proof -
          assume [simp]: "io_diagram A"
          assume [simp]: "io_diagram B"
          assume [simp]: "io_diagram C"

          have [simp]: "TVs (In A) = TI (Trs A)"
            apply (subgoal_tac "io_diagram A")
            apply (simp only: io_diagram_def)
            by simp

          have [simp]: "distinct (In A)"
            apply (subgoal_tac "io_diagram A")
            apply (simp only: io_diagram_def)
            by simp

          have [simp]: "TVs (In B) = TI (Trs B)"
            apply (subgoal_tac "io_diagram B")
            apply (simp only: io_diagram_def)
            by simp

          have [simp]: "distinct (In B)"
            apply (subgoal_tac "io_diagram B")
            apply (simp only: io_diagram_def)
            by simp

          have [simp]: "TVs (In C) = TI (Trs C)"
            apply (subgoal_tac "io_diagram C")
            apply (simp only: io_diagram_def)
            by simp

          have [simp]: "distinct (In C)"
            apply (subgoal_tac "io_diagram C")
            apply (simp only: io_diagram_def)
            by simp

          have [simp]: "distinct (In A ⊕ (In B ⊕ In C))"
            by (simp add: distinct_addvars)

          have [simp]: "set (In A ⊕ In B) ⊆ set (In A ⊕ (In B ⊕ In C))"
            apply (simp add: addvars_def set_diff)
            by blast

          have [simp]: "set (In C) ⊆ set (In A ⊕ (In B ⊕ In C))"
            apply (simp add: addvars_def set_diff)
            by blast

          have [simp]: "set (In A) ⊆ set (In A ⊕ (In B ⊕ In C))"
            by (simp add: addvars_def set_diff)

          have [simp]: "set (In B ⊕ In C) ⊆ set (In A ⊕ (In B ⊕ In C))"
            by (simp add: addvars_def set_diff)

          have "Trs (A ||| B ||| C) = [In A ⊕ (In B ⊕ In C) ↝ (In A ⊕ In B) @ In C] oo ([In A ⊕ In B ↝ In A @ In B] oo Trs A ∥ Trs B) ∥ Trs C"
            by (simp add: Parallel_def addvars_assoc)
          also have "... = [In A ⊕ (In B ⊕ In C) ↝ (In A ⊕ In B) @ In C] oo 
              ([In A ⊕ In B ↝ In A @ In B] ∥ [In C ↝ In C] oo Trs A ∥ Trs B ∥ Trs C)"
            apply (subst comp_parallel_distrib)
            by (simp_all)
          also have "... = ([In A ⊕ (In B ⊕ In C) ↝ (In A ⊕ In B) @ In C] oo [In A ⊕ In B ↝ In A @ In B] ∥ [In C ↝ In C]) oo 
              Trs A ∥ Trs B ∥ Trs C"
            by (simp add: comp_assoc)
          also have "... = [In A ⊕ (In B ⊕ In C) ↝ In A @ In B @ In C] oo Trs A ∥ Trs B ∥ Trs C"
            apply (rule_tac f = "λ X . X oo (Trs A ∥ Trs B ∥ Trs C)" in arg_cong)
            apply (simp add: addvars_assoc [THEN sym])
            by (subst switch_par_comp_Subst, simp_all add: distinct_addvars set_addvars Subst_eq)            
          also have "... = [In A ⊕ (In B ⊕ In C) ↝ In A @ (In B @ In C)] oo 
              Trs A ∥ (Trs B ∥ Trs C)"
            by (simp add: par_assoc)
          also have "... = ([In A ⊕ (In B ⊕ In C) ↝ In A @ (In B ⊕ In C)] oo [In A ↝ In A] ∥ [In B ⊕ In C ↝ In B @ In C]) oo
              Trs A ∥ (Trs B ∥ Trs C)"
            apply (rule_tac f = "λ X . X oo (Trs A ∥ (Trs B ∥ Trs C))" in arg_cong)
            apply (simp add: addvars_assoc [THEN sym])
            by (subst switch_par_comp_Subst, simp_all add: distinct_addvars set_addvars Subst_eq, auto)
          also have "... = [In A ⊕ (In B ⊕ In C) ↝ In A @ (In B ⊕ In C)] oo 
              (([In A ↝ In A] oo Trs A) ∥ ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C))"
            apply (simp add: comp_assoc par_assoc)
            apply (subst comp_parallel_distrib)
            by (simp_all )
          also have "... = [In A ⊕ (In B ⊕ In C) ↝ In A @ (In B ⊕ In C)] oo 
               Trs A ∥ ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C)"
            apply (subst comp_id_switch)
            by simp_all
          also have "... = Trs (A ||| (B ||| C))"
            by (simp add: Parallel_def)

        show  "A ||| B ||| C = A ||| (B ||| C)"
          using Parallel_def addvars_assoc calculation by fastforce
      qed
        
definition "VarFB A = Var A A"
definition "InFB A= In A ⊖ VarFB A"
definition "OutFB A = Out A ⊖ VarFB A"

definition FB :: "('var, 'a) Dgr ⇒ ('var, 'a) Dgr" where
  "FB A = (let I = In A ⊖ Var A A in let O' = Out A ⊖ Var A A in
      ⦇In = I, Out = O', Trs = (fb ^^ (length (Var A A))) ([Var A A @ I ↝ In A] oo Trs A oo [Out A ↝ Var A A @ O']) ⦈)"


lemma Type_ok_FB: "io_diagram A ⟹ io_diagram (FB A)"
        apply (simp add: io_diagram_def FB_def Let_def Var_def, safe)
        apply (cut_tac t="TVs(Out A ⊗ In A)" and ts="TVs ((In A ⊖ Out A ⊗ In A))" and ts'="TVs ((Out A ⊖ Out A ⊗ In A))" and
            S="([(Out A ⊗ In A) @ (In A ⊖ Out A ⊗ In A) ↝ In A] oo Trs A oo [Out A ↝ (Out A ⊗ In A) @ (Out A ⊖ Out A ⊗ In A)])" in TI_fb_fbtype_n)
        apply (simp add: fbtype_def)
        apply (subgoal_tac "length (TVs (Out A ⊗ In A)) = length (Out A ⊗ In A)")
        apply simp
        apply (simp add: length_TVs)
        apply (cut_tac t="TVs (Out A ⊗ In A)" and ts="TVs (In A ⊖ Out A ⊗ In A)" and ts'="TVs (Out A ⊖ Out A ⊗ In A)" and
            S="([(Out A ⊗ In A) @ (In A ⊖ Out A ⊗ In A) ↝ In A] oo Trs A oo [Out A ↝ (Out A ⊗ In A) @ (Out A ⊖ Out A ⊗ In A)])" in TO_fb_fbtype_n)
        apply (simp add: fbtype_def)
        apply (subgoal_tac " length (TVs (Out A ⊗ In A)) =  length (Out A ⊗ In A)")
        apply simp
        by (simp add: length_TVs)

lemma perm_var_Par: "io_diagram A ⟹ io_diagram B ⟹ set (In A) ∩ set (In B) = {} 
  ⟹ perm (Var (A ||| B) (A ||| B)) (Var A A @ Var B B @ Var A B @ Var B A)"
        apply (simp add: Parallel_indep Var_def append_inter)
        apply (frule_tac x = "Out A" in inter_append)
        apply (drule_tac x = "Out B" in inter_append)
        by (simp add: perm_mset union_commute union_lcomm)

      lemma distinct_Parallel_Var[simp]: "io_diagram A ⟹ io_diagram B  
        ⟹ set (Out A) ∩ set (Out B) = {} ⟹ distinct (Var (A ||| B) (A ||| B))"
        apply (simp add: Parallel_def Var_def append_inter, safe)
        apply (simp add:  io_diagram_def)
         apply (simp add:  io_diagram_def)
        by (metis IntI notin_inter)

      lemma distinct_Parallel_In[simp]: "io_diagram A ⟹ io_diagram B ⟹ distinct (In (A ||| B))"
        apply (simp add: Parallel_def Var_def append_inter io_diagram_def)
        using distinct_addvars by auto

      lemma drop_assumption: "p ⟹ True"
        by simp


(*
New proof
      theorem FP_IC_res_new: "io_diagram A ⟹ io_diagram B ⟹ set (In A) ∩ set (In B) = {} 
      ⟹ set (Out A) ∩ set (Out B) = {} ⟹ FB (A ||| B) = FB (FB (A) ;; FB (B))"
        proof -
          assume A [simp]: "set (In A) ∩ set (In B) = {}"
          assume B [simp]: "set (Out A) ∩ set (Out B) = {}"
          have [simp]: "In A ⊕ In B = In A @ In B"
            by (simp add: addvars_distinct)
          assume "io_diagram A"
          assume "io_diagram B"
          have [simp]: "distinct (In A)" and [simp]: "distinct (In B)"
            using ‹io_diagram A› io_diagram_def apply auto[1]
            using ‹io_diagram B› io_diagram_def by auto[1]
          have [simp]: "TI (Trs A) = TVs (In A)" and "TO (Trs A) = TVs (Out A)"
            using ‹io_diagram A› io_diagram_def apply force
            using ‹io_diagram A› io_diagram_def by force
          have [simp]: "TI (Trs B) = TVs (In B)" and "TO (Trs B) = TVs (Out B)"
            using ‹io_diagram B› io_diagram_def apply force
            using ‹io_diagram B› io_diagram_def by force

          have [simp]: "In A ⊖ Out A ⊖ (Out B ⊖ In B) = (In A ⊖ Out A ⊖ Out B)"
            apply (subst diff_notin, simp_all add: set_diff)
            using A by blast

          thm diff_commute

          have [simp]: "In B ⊖ Out B ⊖ (Out A ⊖ In A) = (In B ⊖ Out A ⊖ Out B)"
            apply (subst diff_notin, simp_all add: set_diff diff_sym)
            using A by blast

          have [simp]: "Out A ⊖ In A ⊖ (In B ⊖ Out B) = (Out A ⊖ In A ⊖ In B)"
            apply (subst diff_notin, simp_all add: set_diff)
            using B by blast

          have [simp]: "Out B ⊖ In B ⊖ (In A ⊖ Out A) = (Out B ⊖ In A ⊖ In B)"
            apply (subst diff_notin, simp_all add: set_diff diff_sym)
            using B by blast

          have [simp]: "⋀ x y x' y' . (In A ⊖ x ⊖ y) ⊕ (In B ⊖ x' ⊖ y') = (In A ⊖ x ⊖ y) @ (In B ⊖ x' ⊖ y')"
            apply (subst addvars_distinct, simp_all add: set_diff)
            using A by blast

          have [simp]: "⋀ x x' y' . (In A ⊖ x) ⊕ (In B ⊖ x' ⊖ y') = (In A ⊖ x) @ (In B ⊖ x' ⊖ y')"
            apply (subst addvars_distinct, simp_all add: set_diff)
            using A by blast
          have [simp]: "distinct (In B ⊖ Out A ⊖ Out B)"
            by (simp add: distinct_diff)

          show ?thesis
            apply (simp add: Parallel_def FB_def Comp_def Let_def Var_def, safe)
            apply (simp_all add: diff_inter_left diff_inter_right)
            apply (simp_all add: addvars_minus diff_union distinct_id union_diff diff_addvars diff_redundant_a 
                diff_redundant_b diff_redundant_c diff_redundant_d)
            sorry
        qed
*)

   lemma  Dgr_eq: "In A = x ⟹ Out A = y ⟹ Trs A = S ⟹  ⦇In = x, Out = y, Trs = S⦈ = A"
        by auto


      lemma Var_FB[simp]: "Var (FB A) (FB A) = []"
        by (simp add: FB_def Var_def Let_def)

      theorem FB_idemp: "io_diagram A ⟹ FB (FB A) = FB A"
        apply (subst FB_def)
        apply (simp add: Let_def diff_emptyset)
        apply (rule Dgr_eq, simp_all)
        by (metis (no_types, lifting) io_diagram_def  Type_ok_FB comp_id_right comp_id_switch distinct_id)

    definition VarSwitch :: "'var list ⇒ 'var list ⇒ ('var, 'a) Dgr" ("[[_ ↝ _]]") where
      "VarSwitch x y = ⦇In = x, Out = y, Trs = [x ↝ y]⦈"
      

      definition "in_equiv  A B = (perm (In A) (In B) ∧ Trs A = [In A ↝ In B] oo Trs B ∧ Out A  = Out B)"
      definition "out_equiv A B = (perm (Out A) (Out B) ∧ Trs A = Trs B oo [Out B ↝ Out A] ∧ In A = In B)"

      definition "in_out_equiv A B = (perm (In A) (In B) ∧ perm (Out A) (Out B) ∧ Trs A = [In A ↝ In B] oo Trs B oo [Out B ↝ Out A])"

      lemma in_equiv_io_diagram: "in_equiv A B ⟹ io_diagram B ⟹ io_diagram A"
        apply (simp add: io_diagram_def in_equiv_def, safe)
        using dist_perm perm_sym by blast

      lemma in_out_equiv_io_diagram: "in_out_equiv A B ⟹ io_diagram B ⟹ io_diagram A"
        apply (simp add: io_diagram_def in_out_equiv_def, safe)
        using dist_perm perm_sym apply blast
        using dist_perm perm_sym by blast

      lemma in_equiv_sym: "io_diagram B ⟹ in_equiv A B ⟹ in_equiv B A"
        by (auto simp add: in_equiv_def perm_sym  comp_assoc[THEN sym] io_diagram_def switch_comp )
      
      lemma in_equiv_eq: "io_diagram A ⟹ A = B ⟹ in_equiv A B"
        by (simp add: in_equiv_def perm_mset io_diagram_def)

      lemma [simp]: "io_diagram A ⟹ [In A ↝ In A] oo Trs A oo [Out A ↝ Out A] = Trs A"
        by (simp add: io_diagram_def)

      lemma in_equiv_tran: "io_diagram C ⟹ in_equiv A B ⟹ in_equiv B C ⟹ in_equiv A C"
        apply (subgoal_tac "io_diagram B")
        apply (subgoal_tac "io_diagram A")
        apply (simp add: in_equiv_def)
        apply (simp_all add: in_equiv_io_diagram)
        apply (cut_tac x="In A" and y="In B" and z="In C" in  perm_trans)
        apply simp_all
        apply (subst comp_assoc [THEN sym])
        apply simp_all
        apply (unfold io_diagram_def, simp_all)
        apply (subst switch_comp)
           apply simp
          apply simp
         apply simp
          by simp

    lemma in_out_equiv_refl: "io_diagram A ⟹ in_out_equiv A A"
      by (simp add: in_out_equiv_def perm_mset)

    lemma in_out_equiv_sym: "io_diagram A ⟹ io_diagram B ⟹ in_out_equiv A B ⟹ in_out_equiv B A"
      apply (simp add: in_out_equiv_def, safe)
      apply (simp add: perm_mset)
      apply (simp add: perm_mset)
      apply (simp add: io_diagram_def)
      apply (simp add: comp_assoc)
      apply (subgoal_tac "[Out B ↝ Out A] oo [Out A ↝ Out B] = ID (TVs (Out B))")
      apply simp_all
      apply (simp add: comp_assoc [THEN sym])
      apply (subgoal_tac "[In B ↝ In A] oo [In A ↝ In B] =  ID (TVs (In B))")
      apply simp_all
      apply (simp add: distinct_vars_comp perm_sym)
      by (simp add: distinct_vars_comp perm_sym)

    lemma in_out_equiv_tran: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ in_out_equiv A B ⟹ in_out_equiv B C ⟹ in_out_equiv A C"
      apply (simp add: in_out_equiv_def, safe)
      apply (simp add: perm_mset)
      apply (simp add: perm_mset)
      apply (unfold io_diagram_def, safe)
      proof -
        assume [simp]: "TVs (In A) = TI (Trs A)" 
        assume [simp]: "TVs (In B) = TI (Trs B) "
        assume [simp]: "TVs (In C) = TI (Trs C) "
        assume [simp]: "TVs (Out A) = TO (Trs A) "
        assume [simp]: "TVs (Out B) = TO (Trs B) "
        assume [simp]: "TVs (Out C) = TO (Trs C) "
        have [simp]: "[In A ↝ In B] oo ([In B ↝ In C] oo Trs C oo [Out C ↝ Out B]) oo [Out B ↝ Out A]
          = ([In A ↝ In B] oo [In B ↝ In C]) oo Trs C oo ([Out C ↝ Out B] oo [Out B ↝ Out A])"
          by (simp add: comp_assoc)
        assume [simp]: "perm (In A) (In B)"
        assume "perm (In B) (In C)"
        assume "perm (Out A) (Out B)"
        assume "perm (Out B) (Out C)"
        assume [simp]: "distinct (In A)"
        assume [simp]: "distinct (Out C)"

        have [simp]: "[In A ↝ In B] oo [In B ↝ In C] = [In A ↝ In C]"
          apply (subst  switch_comp, simp_all)
          using ‹perm (In B) (In C)› perm_set_eq by auto

        have [simp]: "[Out C ↝ Out B] oo [Out B ↝ Out A] = [Out C ↝ Out A]"
          apply (subst  switch_comp, simp_all)
          apply (simp add: ‹perm (Out B) (Out C)› perm_sym)
          using ‹perm (Out A) (Out B)› perm_set_eq by auto
        show " [In A ↝ In B] oo ([In B ↝ In C] oo Trs C oo [Out C ↝ Out B]) oo [Out B ↝ Out A] = [In A ↝ In C] oo Trs C oo [Out C ↝ Out A]"
          by simp
     qed


    lemma [simp]: "distinct (Out A) ⟹ distinct (Var A B)"
      by (simp add: Var_def)

    lemma [simp]: "set (Var A B) ⊆ set (Out A)"
      by (auto simp add: Var_def set_inter)
    lemma [simp]: "set (Var A B) ⊆ set (In B)"
      by (auto simp add: Var_def set_inter)



    lemmas fb_indep_sym = fb_indep [THEN sym]

declare length_TVs [simp] 
  
  end
  

  primrec op_list :: "'a ⇒ ('a ⇒ 'a ⇒'a) ⇒ 'a list ⇒ 'a" where
    "op_list e opr [] = e" |
    "op_list e opr (a # x) = opr a (op_list e opr x)"

primrec inter_set :: "'a list ⇒ 'a set ⇒ 'a list" where
  "inter_set [] X = []" |
  "inter_set (x # xs) X = (if x ∈ X then x # inter_set xs X else inter_set xs X)"

lemma list_inter_set: "x ⊗ y = inter_set x (set y)"
      by (induction x, simp_all)

fun map2 :: "('a ⇒ 'b ⇒ bool) ⇒ 'a list ⇒ 'b list ⇒ bool" where
  "map2 f [] [] = True" |
  "map2 f (a # x) (b # y) = (f a b ∧ map2 f x y)" |
  "map2 _ _ _ = False"
  
thm map_def
  
context BaseOperationFeedbacklessVars
begin
definition ParallelId :: "('var, 'a) Dgr" ("□")
  where "□ =  ⦇In = [], Out = [], Trs = ID []⦈"
    
lemma [simp]: "Out □ = []"
  by (simp add: ParallelId_def)

lemma [simp]: "In □ = []"
  by (simp add: ParallelId_def)

lemma [simp]: "Trs □ = ID []"
  by (simp add: ParallelId_def)
    
lemma ParallelId_right[simp]: "io_diagram A ⟹ A ||| □ = A"
  apply (simp add: Parallel_def ParallelId_def)
  apply (subst comp_id_switch)
    apply (simp add: io_diagram_def)
   apply (simp add: io_diagram_def)
  apply (cut_tac x="[]" in  distinct_id)
   apply simp
  apply (subgoal_tac "TVs [] = []")
  using par_empty_right apply auto[1]
  by (simp add: TVs_def)

lemma ParallelId_left: "io_diagram A ⟹ □ ||| A = A"
  apply (simp add: Parallel_def ParallelId_def)
  apply (subst comp_id_switch)
  by (simp_all add: io_diagram_def)

definition "parallel_list = op_list (ID []) (∥)"
  
definition "Parallel_list = op_list □ (|||)"
  
lemma [simp]: "Parallel_list [] = □"
  by (simp add: Parallel_list_def)

definition "io_distinct As = (distinct (concat (map In As)) ∧ distinct (concat (map Out As)) ∧ (∀ A ∈ set As . io_diagram A))"
       
definition "io_rel A = set (Out A) × set (In A)"

definition "IO_Rel As = ⋃ (set (map io_rel As))"

definition "out A = hd (Out A)" (*the first output of A*)

definition "Type_OK As = ((∀ B ∈ set As . io_diagram B ∧ length (Out B) = 1) 
                    ∧ distinct (concat (map Out As)))"

      lemma concat_map_out: "(∀ A ∈ set As . length (Out A) = 1) ⟹ concat (map Out As) = map out As"
        apply (induction As, simp_all)
        apply (case_tac "Out a", simp_all)
        by (simp add: out_def)

      lemma Type_OK_simp: "Type_OK As =  ((∀ B ∈ set As . io_diagram B ∧ length (Out B) = 1) ∧ distinct (map out As))"
        apply (simp add: Type_OK_def, safe)
        by (simp_all add: concat_map_out)

      definition "single_out A = (io_diagram A ∧ length (Out A) = 1)"


definition CompA :: "('var, 'a) Dgr ⇒ ('var, 'a) Dgr ⇒ ('var, 'a) Dgr" (infixl "⊳" 75) where
(*  "A ⊳ B = (if set(Out A) ⊆ set (In B) then A ;; B else B)"*)
  "A ⊳ B = (if out A ∈ set (In B) then A ;; B else B)"

  
definition "internal As = {x . (∃ A ∈ set As . ∃ B ∈ set As . x ∈ set (Out A) ∧ x ∈ set (In B))}"


primrec get_comp_out :: "'var ⇒ ('var, 'a) Dgr list ⇒ ('var, 'a) Dgr" where
    "get_comp_out x [] = ⦇In = [x], Out = [x], Trs = [ [x] ↝ [x] ]⦈" | (*can be undefined also. Using identity to be more convenient*)
    "get_comp_out x (A # As) = (if x ∈ set (Out A) then A else get_comp_out x As)" 
        

primrec get_other_out :: "'c ⇒ ('c, 'd) Dgr list ⇒ ('c, 'd) Dgr list" where
    "get_other_out x [] = []" |
    "get_other_out x (A # As) = (if x ∈ set (Out A) then get_other_out x As else A # get_other_out x As)"
    
      (*we assume the A is not in As*)
definition "fb_less_step A As = map (CompA A) As" 

      
definition "fb_out_less_step x As = fb_less_step (get_comp_out x As) (get_other_out x As)"

primrec fb_less :: "'var list ⇒ ('var, 'a) Dgr list ⇒ ('var, 'a) Dgr list" where
      "fb_less [] As = As" |
      "fb_less (x # xs) As = fb_less xs (fb_out_less_step x As)"
  

lemma [simp]: "VarFB □ = []"
  by (simp add: VarFB_def Var_def)
lemma [simp]: "InFB □ = []"
  by (simp add: VarFB_def Var_def InFB_def)
lemma [simp]: "OutFB □ = []"
  by (simp add: VarFB_def Var_def OutFB_def)
    

      definition "loop_free As = (∀ x . (x,x) ∉ (IO_Rel As)+)"

lemma [simp]: "Parallel_list (A # As) = (A ||| Parallel_list As)"
  by (simp add: Parallel_list_def)

lemma [simp]: "Out (A ||| B) = Out A @ Out B"
  by (simp add: Parallel_def)

lemma [simp]: "In (A ||| B) = In A ⊕ In B"
  by (simp add: Parallel_def)

lemma Type_OK_cons: "Type_OK (A # As) = (io_diagram A ∧ length (Out A) = 1 ∧ set (Out A) ∩ (⋃a∈set As. set (Out a)) = {} ∧ Type_OK As)"
  by (simp add: Type_OK_def io_diagram_def, auto)

    
lemma Out_Parallel: "Out (Parallel_list As) = concat (map Out As)"
  by (induction As, simp_all)

      lemma internal_cons: "internal (A # As) = {x. x ∈ set (Out A) ∧ (x ∈ set (In A) ∨ (∃B∈set As. x ∈ set (In B)))} ∪ {x . (∃Aa∈set As. x ∈ set (Out Aa) ∧ (x ∈ set (In A)))}
          ∪ internal As"
        by (auto simp add: internal_def)
          
      lemma Out_out: "length (Out A) = Suc 0 ⟹ Out A = [out A]"
        apply (simp add: out_def)
        by (case_tac "Out A", simp_all)

      lemma Type_OK_out: "Type_OK As ⟹ A ∈ set As  ⟹ Out A = [out A]"
        apply (simp add: out_def Type_OK_def)
        by (case_tac "Out A", simp_all, auto)


      lemma In_Parallel: "In (Parallel_list As) = op_list [] (⊕) (map In As)"
        by (induction As, simp_all)

      lemma [simp]: "set (op_list [] (⊕) xs) = ⋃ (set (map set xs))"
        apply (induction xs, simp_all)
        by (simp add: set_addvars)

      lemma internal_VarFB: "Type_OK As ⟹ internal As = set (VarFB (Parallel_list As))"
        apply (induction As)
        apply (simp add: VarFB_def Var_def internal_def Parallel_list_def ParallelId_def)
        apply (subgoal_tac "Out a = [out a]")
        apply (simp add: Type_OK_cons VarFB_def Var_def set_inter set_addvars internal_cons Type_OK_out Out_Parallel, safe)
        apply (simp_all add: Type_OK_out subsetset_inter)
        apply (rule_tac x = Aa in bexI)
        apply (simp add: Type_OK_out, simp)
        apply (rule_tac x = xa in bexI)
        apply (simp add: Type_OK_out, simp)
        apply blast
        apply blast
        apply blast
                            apply (simp_all add: In_Parallel)
        by auto


      lemma map_Out_fb_less_step: "length (Out A) = 1 ⟹  map Out (fb_less_step A As) = map Out As"
        apply (induction As)
        apply (simp_all add: fb_less_step_def CompA_def Comp_def Let_def Var_def diff_inter_left, safe)
        by (case_tac "Out A", simp_all add: out_def)

      lemma mem_get_comp_out: "Type_OK As ⟹ A ∈ set As ⟹ get_comp_out (out A) As = A"
        apply (induction As, simp, auto)
         apply (simp add: Type_OK_def, auto)
          apply (metis (no_types, lifting) Out_out   list.set_intros(1))
         apply (simp add: Type_OK_def Out_out)
        prefer 2
        using Type_OK_cons apply blast
        proof -
          fix a :: "('var, 'a) Dgr" and Asa :: "('var, 'a) Dgr list"
          assume a1: "io_diagram a ∧ length (Out a) = Suc 0 ∧ (∀B∈set Asa. io_diagram B ∧ length (Out B) = Suc 0) ∧ distinct (Out a) ∧ distinct (concat (map Out Asa)) ∧ set (Out a) ∩ (⋃a∈set Asa. set (Out a)) = {}"
          assume a2: "A ∈ set Asa"
          assume "out A = out a"
          then have "¬ distinct (map out (a # Asa))"
            using a2 by (metis (no_types) distinct.simps(2) image_eqI list.map(2) set_map)
          then show "a = A"
            using a1 by (metis (no_types) One_nat_def Type_OK_cons Type_OK_def Type_OK_simp)
        qed
 
      lemma map_Out_fb_out_less_step: "A ∈ set As ⟹ Type_OK As ⟹ a = out A ⟹ map Out (fb_out_less_step a As) = map Out (get_other_out a As)"
        apply (induction As, simp add: fb_out_less_step_def fb_less_step_def)
        apply simp
        apply safe
        apply (simp add: fb_out_less_step_def)
        apply (subst map_Out_fb_less_step)
        apply (simp add: Type_OK_def)
        apply simp
        apply (simp add: fb_out_less_step_def)
        apply (subst map_Out_fb_less_step, simp_all)
          apply (simp add: Type_OK_def)
          using Out_out apply force
        apply (simp add: fb_out_less_step_def)
           apply (subst map_Out_fb_less_step, simp_all)
            
            using Type_OK_cons apply auto[1]
            apply (simp add: Type_OK_cons)
              by (simp add: Type_OK_simp fb_out_less_step_def map_Out_fb_less_step mem_get_comp_out)


lemma [simp]: "Type_OK (A # As) ⟹ Type_OK As"
        by (simp add: Type_OK_cons)

      lemma Type_OK_Out: "Type_OK (A # As) ⟹ Out A = [out A]"
        by (rule Type_OK_out, simp_all, auto)

      lemma  concat_map_Out_get_other_out: "Type_OK As ⟹ concat (map Out (get_other_out a As)) = (concat (map Out As) ⊖ [a])"
        apply (induction As, simp_all)
        by (simp_all add: union_diff Type_OK_Out)
      thm Out_out
      lemma VarFB_cons_out: "Type_OK As ⟹ VarFB (Parallel_list As) = a # L ⟹ ∃ A ∈ set As . out A = a"
        apply (cut_tac As = As in internal_VarFB, simp_all)
        apply (simp add: internal_def)
        apply (unfold set_eq_iff)
        apply (drule_tac x = a in spec, simp_all add: Out_out, safe)
        apply (subst (asm) Out_out)
         apply (simp add: Type_OK_def)
        by auto
          


      lemma VarFB_cons_out_In: "Type_OK As ⟹ VarFB (Parallel_list As) = a # L ⟹ ∃ B ∈ set As . a ∈ set (In B)"
        apply (cut_tac As = As in internal_VarFB, simp_all)
        apply (simp add: internal_def)
        apply (unfold set_eq_iff)
        by (drule_tac x = a in spec, simp_all)


      (*todo: find better names to next lemmas*)
      lemma AAA_a: "Type_OK (A # As) ⟹ A ∉ set As"
        apply (simp add: Type_OK_def, auto)
        by (case_tac "Out A", simp_all, auto)


      lemma AAA_b: "(∀ A ∈ set As. a ∉ set (Out A)) ⟹ get_other_out a As = As"
        by (induction As, simp_all)

     
      lemma AAA_d: "Type_OK (A # As) ⟹ ∀Aa∈set As. out A ≠ out Aa"
        apply (simp add: Type_OK_def)
        apply (unfold set_eq_iff)
        apply (case_tac "Out A", simp_all, safe)
        apply (drule_tac x = "a" in spec, safe, auto)
        apply (drule_tac x = Aa in bspec, simp_all)
        apply (drule_tac x = Aa in bspec, simp_all)
        apply (case_tac "Out Aa", simp_all, auto)
        by (simp add: out_def)

      lemma  mem_get_other_out: "Type_OK As ⟹ A ∈ set As ⟹ get_other_out (out A) As = (As ⊖ [A])"
        apply (induction As)
        apply simp
        apply simp
        apply safe   
        apply simp_all
        apply (subst AAA_c)
        apply (subst AAA_a, simp_all)
            apply (subst AAA_b, simp_all)
          
        using Type_OK_cons apply blast
          
           apply (simp add: Type_OK_Out)
          
        using Type_OK_cons apply blast
          
         apply (simp add: Out_out Type_OK_simp)
        using AAA_a by blast

(*
lemma In_CompA: "In (A ⊳ B) = (if set (Out A) ⊆ set (In B) then In A ⊕ (In B ⊖ Out A) else In B)"
  by (simp add: CompA_def Comp_def Let_def Var_def diff_inter_right)
*)

lemma In_CompA: "In (A ⊳ B) = (if out A ∈ set (In B) then In A ⊕ (In B ⊖ Out A) else In B)"
  by (simp add: CompA_def Comp_def Let_def Var_def diff_inter_right)
      
  
lemma union_set_In_CompA: "⋀ B . length (Out A) = 1 ⟹ B ∈ set As ⟹ out A ∈ set (In B) 
    ⟹ (⋃x∈set As. set (In (CompA A x))) = set (In A) ∪ ((⋃ B ∈ set As . set (In B)) - {out A})"
  proof (induction As)
    case Nil
    then show ?case by simp
  next
    case (Cons a As)
    have [simp]: "out A ∈ set (In B)"
      by (simp add: Cons.prems(3))
    have [simp]: "Out A = [out A]"
      by (simp add: Cons.prems(1) Out_out)
    show ?case
      proof (cases "∀ C ∈ set As . out A ∉ set (In C)")
        case True
        have [simp]: "a = B"
          using Cons.prems(2) Cons.prems(3) True by auto
        from True show ?thesis
          by (auto simp add:  In_CompA set_addvars set_diff)
      next
        case False
        from this obtain C where [simp]: "C ∈ set As" and [simp]: "out A ∈ set (In C)"
          by blast
        show ?thesis
          apply simp
          apply (subst Cons(1) [of C])
          by (auto simp add:  In_CompA set_addvars set_diff)
      qed
    qed

lemma BBBB_e: "Type_OK As ⟹ VarFB (Parallel_list As) = out A # L ⟹ A ∈ set As ⟹ out A ∉ set L"
  apply (simp add: VarFB_def Var_def Out_Parallel Type_OK_def, safe)
  by (drule_tac y = "In (Parallel_list As)" in distinct_inter, simp)

lemma BBBB_f: "loop_free As ⟹
     Type_OK As ⟹ A ∈ set As  ⟹ B ∈ set As ⟹ out A ∈ set (In B) ⟹ B ≠ A"
        apply (simp add: loop_free_def)
        apply (drule_tac x = "out A" in spec)
        apply (simp add: IO_Rel_def io_rel_def)
        apply (case_tac "B = A", simp_all)
          apply (subgoal_tac "(out A, out A) ∈ (⋃x∈set As. set (Out x) × set (In x))+", simp)
          
        apply (rule r_into_trancl')
        apply simp  
        apply (rule_tac x = A in bexI)
        by (simp_all add: Type_OK_out)
          
      thm union_set_In_CompA
        
lemma [simp]: "x ∈ set (Out (get_comp_out x As))"
  by (induction As, auto simp add: out_def)

lemma comp_out_in: "A ∈ set As ⟹ a ∈ set (Out A) ⟹ (get_comp_out a As) ∈ set As"
  apply (induction As, simp)
  by auto
    
lemma  [simp]: "a ∈ internal As ⟹ get_comp_out a As ∈ set As"
  apply (simp_all add: internal_def)
   using comp_out_in by blast
    
lemma out_CompA: "length (Out A) = 1 ⟹ out (CompA A B) = out B"
  apply (simp add: CompA_def)
  apply (simp add: Comp_def Let_def Var_def out_def)
  by (case_tac "Out A", simp_all)
    
lemma Type_OK_loop_free_elem: "Type_OK As ⟹ loop_free As ⟹ A ∈ set As ⟹ out A ∉ set (In A)"
        apply (simp add: loop_free_def)
        apply (drule_tac x = "out A" in spec)
        apply (simp add: IO_Rel_def io_rel_def)
        apply (case_tac "out A ∈ set (In A)", simp_all)
        apply (drule_tac P =  "(out A, out A) ∈ (⋃x∈set As. set (Out x) × set (In x))+" in notE, simp_all)
        apply (rule r_into_trancl')
        apply simp
        apply (rule_tac x = A in bexI)
  by (simp_all add: Type_OK_out)
    
      lemma BBB_a: "length (Out A) = 1 ⟹ Out (CompA A B) = Out B"
        apply (simp add: CompA_def, safe)
        apply (simp add: Comp_def Let_def Var_def diff_inter_left out_def)
        by (case_tac "Out A", simp_all)

      lemma BBB_b: "length (Out A) = 1 ⟹ map (Out ∘ CompA A) As = map Out As"
        apply (induction As, simp_all)
        by (simp add: BBB_a)
  
lemma VarFB_fb_out_less_step_gen:
  assumes "loop_free As"
    assumes "Type_OK As"
    and internal_a: "a ∈ internal As"
    shows "VarFB (Parallel_list (fb_out_less_step a As)) = (VarFB (Parallel_list As)) ⊖ [a]"
proof -
  define A where "A = get_comp_out a As"
  have [simp]: "A ∈ set As"
    using A_def internal_a by auto [1]
      
  from this have "length (Out A) = 1"
    using ‹Type_OK As› by (unfold Type_OK_def, simp) 
  from this have "Out A = [out A]"
    by (simp add: Out_out)
      
  have "a ∈ set (Out A)"
    by (simp add: ‹A ≡ get_comp_out a As›)
      
  have Out_a: "out A = a"
    using ‹Out A = [out A]› ‹a ∈ set (Out A)› by auto
      
  have [simp]: "get_other_out a As = As ⊖ [A]"
    using Out_a ‹A ∈ set As› assms(2) mem_get_other_out by blast
      
  from internal_a obtain C where [simp]: "C ∈ set As" and [simp]: "a ∈ set (In C)" and [simp]: "C ≠ A"
    apply (unfold internal_def, safe)
    by (metis Out_a Type_OK_loop_free_elem assms(1) assms(2))
      
  have a_not_in_A: "a ∉ set (In A)"
    using BBBB_f Out_a ‹A ∈ set As› assms(1) assms(2) by blast
 
  have [simp]: "⋀ A . A ∈ set As ⟹ Out A = [out A]"
    using Type_OK_out assms(2) by blast

  have [simp]: "concat (map Out (As ⊖ [A])) = (concat (map Out As) ⊖ [a])"
    by (metis ‹get_other_out a As = As ⊖ [A]› assms(2) concat_map_Out_get_other_out)

  have [simp]: "(⋃x∈set (As ⊖ [A]). set (In (A ⊳ x))) = set (op_list [] (⊕) (map In As) ⊖ [a])"
    apply (simp add: set_diff, safe)
      apply (case_tac "out A ∈ set (In xa)")
       apply (simp add: CompA_def Comp_def Let_def set_addvars set_diff)
       apply auto[2]
     apply (case_tac "out A ∈ set (In xa)")
      apply (simp add: CompA_def Comp_def Let_def set_addvars set_diff)
      apply (simp add: a_not_in_A Var_def)
    using CompA_def apply auto[1]
    apply (case_tac "a ∈ set (In xa)", simp_all)
       apply (simp add: Out_a CompA_def Comp_def Let_def set_addvars set_diff)
      apply (simp add: Out_a Var_def a_not_in_A)
       apply (simp add: Out_a CompA_def Comp_def Let_def set_addvars set_diff)
    apply (case_tac "xa = A", simp_all)
     apply (drule_tac x = C in bspec)
      apply simp_all
     apply (simp add: CompA_def Comp_def Let_def set_addvars set_diff Out_a)
    apply (drule_tac x = xa in bspec, simp)
      apply (case_tac "a ∈ set (In xa)")
     by (simp_all add: CompA_def Comp_def Let_def set_addvars set_diff Out_a Var_def)
      
  show "VarFB (Parallel_list (fb_out_less_step a As)) = (VarFB (Parallel_list As)) ⊖ [a]"
    apply (simp add: VarFB_def Var_def Out_Parallel In_Parallel fb_out_less_step_def A_def [THEN sym] fb_less_step_def)
    apply (subst BBB_b, simp_all)
    apply (simp add: listinter_diff)
    apply (rule set_listinter)
    by simp
qed
  
thm internal_VarFB
thm VarFB_fb_out_less_step_gen
  

lemma VarFB_fb_out_less_step: "loop_free As ⟹ Type_OK As ⟹ VarFB (Parallel_list As) = a # L ⟹ VarFB (Parallel_list (fb_out_less_step a As)) = L"
  apply (subst VarFB_fb_out_less_step_gen, simp_all)
   apply (simp add: internal_VarFB)
  apply (subgoal_tac "distinct (VarFB (Parallel_list As))")
   apply (metis AAA_c distinct.simps(2))
  by (metis Out_Parallel Type_OK_def VarFB_def Var_def distinct_inter)
    
                
lemma Parallel_list_cons:"Parallel_list (a # As) = a ||| Parallel_list As"
  by simp

lemma io_diagram_parallel_list: "Type_OK As ⟹ io_diagram (Parallel_list As)"
        apply (induction As)
        apply (simp add: ParallelId_def io_diagram_def)
        apply (simp only: Parallel_list_cons)
        apply (subst io_diagram_Parallel)
        by (simp_all add: Type_OK_def Out_Parallel)

      lemma BBB_c: "distinct (map f As) ⟹ distinct (map f (As ⊖ Bs))"
        by (induction As, simp_all add: image_def set_diff)

      lemma io_diagram_CompA: "io_diagram A ⟹ length (Out A) = 1 ⟹ io_diagram B ⟹ io_diagram (CompA A B)"
        apply (simp add: CompA_def, safe)
        apply (subst Comp_in_out)
           apply simp_all

        using Out_out apply fastforce
        by (simp add: Let_def Var_def diff_inter_left diff_inter_right io_diagram_def addvars_def set_diff)


      lemma Type_OK_fb_out_less_step_aux: "Type_OK As ⟹ A ∈ set As ⟹  Type_OK (fb_less_step A (As ⊖ [A]))"
        apply (unfold fb_less_step_def)
        apply (subst Type_OK_def, safe, simp_all add: image_def, safe)
        apply (subst io_diagram_CompA, simp_all)
        apply (simp add: Type_OK_def)
        apply (simp add: Type_OK_def)
        apply (simp add: Type_OK_def set_diff)
        apply (subst BBB_a)
        apply (simp add: Type_OK_def)
        apply (simp add: Type_OK_def set_diff)
        apply (subst BBB_b)
        apply (simp add: Type_OK_def)
        apply (subst concat_map_out)
        apply (simp add: Type_OK_def set_diff)
        by (simp add: Type_OK_simp BBB_c)

    
          
      thm VarFB_cons_out
        
theorem Type_OK_fb_out_less_step_new: "Type_OK As ⟹
      a ∈ internal As ⟹
      Bs = fb_out_less_step a As ⟹ Type_OK Bs"
  apply (simp add: internal_def, safe)
  apply (simp add: fb_out_less_step_def)
    apply (subgoal_tac "Out A = [out A]", simp) 
  apply (subgoal_tac "(get_comp_out (out A) As) = A", simp_all)
  apply (subgoal_tac "get_other_out (out A) As = (As ⊖ [A])", simp_all)
  apply (rule Type_OK_fb_out_less_step_aux, simp_all)
  using mem_get_other_out apply blast
  using mem_get_comp_out apply blast
  by (simp add: Type_OK_def Out_out)
    
theorem Type_OK_fb_out_less_step: "loop_free As ⟹ Type_OK As ⟹
        VarFB (Parallel_list As) = a # L ⟹ Bs = fb_out_less_step a As ⟹ Type_OK Bs"
  apply (rule Type_OK_fb_out_less_step_new, simp_all)
  by (simp add: internal_VarFB)


lemma perm_FB_Parallel[simp]: "loop_free As ⟹ Type_OK As
      ⟹ VarFB (Parallel_list As) = a # L ⟹ Bs = fb_out_less_step a As 
      ⟹ perm (In (FB (Parallel_list As))) (In (FB (Parallel_list Bs)))"
  apply (frule VarFB_cons_out, simp_all, safe)
  apply (frule VarFB_cons_out_In, simp_all, safe)
  apply (rule set_perm)
    apply (drule io_diagram_parallel_list)
        apply (drule Type_ok_FB)
        apply (simp add: io_diagram_def)
        apply (frule Type_OK_fb_out_less_step, simp_all)
        apply (drule_tac As = "(fb_out_less_step (out A) As)" in io_diagram_parallel_list)
        apply (drule Type_ok_FB)
        apply (simp add: io_diagram_def)
        apply (frule VarFB_fb_out_less_step, simp_all)
        apply (simp add: FB_def Let_def In_Parallel )
        apply (simp add: VarFB_def)
        apply (simp add: set_diff fb_out_less_step_def fb_less_step_def)
        apply (simp add: mem_get_other_out mem_get_comp_out)
        apply (subst union_set_In_CompA, simp_all)
        apply (simp add: Type_OK_def)
        apply (simp add: set_diff)
         apply (rule BBBB_f, simp_all)
        apply (simp add: set_diff)
        apply (unfold set_eq_iff, auto)
        by (simp add: Type_OK_loop_free_elem)


      lemma [simp]: "loop_free As ⟹ Type_OK As ⟹
          VarFB (Parallel_list As) = a # L ⟹  
          Out (FB (Parallel_list (fb_out_less_step a As))) = Out (FB (Parallel_list As))"
        apply (frule VarFB_cons_out, simp_all, safe)
        apply (frule VarFB_fb_out_less_step, simp_all)
        apply (simp add: FB_def Let_def VarFB_def)
        apply (simp add: Out_Parallel)
        apply (subst map_Out_fb_out_less_step, simp_all)
        apply (simp add: concat_map_Out_get_other_out)
        by (metis diff_cons)

      lemma TI_Parallel_list: "(∀ A ∈ set As . io_diagram A) ⟹ TI (Trs (Parallel_list As)) = TVs (op_list [] (⊕) (map In As))"
        apply (induction As)
        apply simp
        apply (simp add: ParallelId_def)
        apply (simp add: Parallel_def)
        apply (subst TI_comp)
        apply simp_all
        apply (simp_all add: In_Parallel)
        by (simp add: io_diagram_def)

      lemma TO_Parallel_list: "(∀ A ∈ set As . io_diagram A) ⟹ TO (Trs (Parallel_list As)) = TVs (concat (map Out As))"
        apply (induction As, simp_all)
        apply (simp add: Parallel_def)
        apply (subst TO_comp)
        apply simp_all
        apply (simp_all add: In_Parallel TI_Parallel_list)
        by (simp_all add: io_diagram_def)

      lemma fbtype_aux: "(Type_OK As) ⟹ loop_free As ⟹ VarFB (Parallel_list As) = a # L ⟹
            fbtype ([L @ (In (Parallel_list (fb_out_less_step a As)) ⊖ L) ↝ In (Parallel_list (fb_out_less_step a As))] oo Trs (Parallel_list (fb_out_less_step a As)) oo
              [Out (Parallel_list (fb_out_less_step a As)) ↝ L @ (Out (Parallel_list (fb_out_less_step a As)) ⊖ L)])
              (TVs L) (TO [In (Parallel_list As) ⊖ a # L ↝ In (Parallel_list (fb_out_less_step a As)) ⊖ L]) (TVs (Out (Parallel_list (fb_out_less_step a As)) ⊖ L))"
        apply (frule Type_OK_fb_out_less_step, simp_all)
        apply (simp add: fbtype_def, safe)
        apply (subst TI_comp, simp_all)
        apply (subst TO_comp, simp_all)
        apply (simp add: In_Parallel)
        apply (subst TI_Parallel_list)
        apply (simp add: Type_OK_def)
        apply simp
        apply (simp add: Out_Parallel)
        apply (subst TO_Parallel_list)
        apply (simp add: Type_OK_def)
        apply simp
        apply (subst TI_comp, simp_all)
        apply (simp add: In_Parallel)
        apply (subst TI_Parallel_list)
        apply (simp add: Type_OK_def)
        apply simp
        apply (subst TO_comp, simp_all)
        apply (subst TO_comp, simp_all)
        apply (simp add: In_Parallel)
        apply (subst TI_Parallel_list)
        apply (simp add: Type_OK_def)
        apply simp
        apply (simp add: Out_Parallel)
        apply (subst TO_Parallel_list)
        apply (simp add: Type_OK_def)
        by simp
 

      lemma fb_indep_left_a: "fbtype S tsa (TO A) ts ⟹ A oo (fb^^(length tsa)) S = (fb^^(length tsa)) ((ID tsa ∥ A) oo S)" 
        by (simp add: fb_indep_left)


      lemma parallel_list_cons: "parallel_list (A # As) = A ∥ parallel_list As"
        by (simp add: parallel_list_def)
  
      lemma TI_parallel_list: "(∀ A ∈ set As . io_diagram A) ⟹ TI (parallel_list (map Trs As)) = TVs (concat (map In As))"
        apply (induction As)
        by (simp_all add: parallel_list_def io_diagram_def)
  
      lemma TO_parallel_list: "(∀ A ∈ set As . io_diagram A) ⟹TO (parallel_list (map Trs As)) = TVs (concat (map Out As))"
        apply (induction As)
        by (simp_all add: parallel_list_def io_diagram_def)


      lemma Trs_Parallel_list_aux_a: "Type_OK As ⟹ io_diagram a ⟹
            [In a ⊕ In (Parallel_list As) ↝ In a @ In (Parallel_list As)] oo Trs a ∥ ([In (Parallel_list As) ↝ concat (map In As)] oo parallel_list (map Trs As)) =
            [In a ⊕ In (Parallel_list As) ↝ In a @ In (Parallel_list As)] oo ([In a ↝ In a ] ∥ [In (Parallel_list As) ↝ concat (map In As)] oo Trs a ∥ parallel_list (map Trs As))"
        apply (subst comp_parallel_distrib)
        apply (simp add:   io_diagram_def)
        apply (simp )
        apply (subst TI_parallel_list)
        apply (simp add: Type_OK_def)
        apply simp
        apply (subst comp_id_switch) 
        by (simp_all add: io_diagram_def)
  
      lemma Trs_Parallel_list_aux_b :"distinct x ⟹ distinct y ⟹  set z ⊆ set y ⟹ [x ⊕ y ↝ x @ y] oo [x ↝ x] ∥ [y ↝ z] = [x ⊕ y ↝ x @ z]"
        by (subst switch_par_comp_Subst, simp_all add: distinct_addvars set_addvars Subst_eq)
  
  
      lemma Trs_Parallel_list: "Type_OK As ⟹ Trs (Parallel_list As) = [In (Parallel_list As) ↝ concat (map In As)] oo parallel_list (map Trs As)"
        apply (induction As)
        apply (simp add: Parallel_list_def ParallelId_def parallel_list_def)
        apply (simp add: distinct_id)
        apply simp
        apply (simp add: Parallel_def Let_def parallel_list_cons)
        apply (simp add: Type_OK_cons)
        apply (simp add: Trs_Parallel_list_aux_a)
        apply (subst comp_assoc[THEN sym])
        apply (simp_all)
        apply (simp add: io_diagram_def)
        apply (subst TI_parallel_list)
        apply (simp add: Type_OK_def)
        apply simp
        apply (subst Trs_Parallel_list_aux_b)
        apply (simp add: io_diagram_def)
        using io_diagram_def io_diagram_parallel_list apply blast
        apply (subst In_Parallel)
        by auto
(*
CompA update
      lemma CompA_Id[simp]: "CompA A □ = □"
        by (simp add: CompA_def comp_def ParallelId_def)
*) 
          
lemma CompA_Id[simp]: "A ⊳ □ = □"
  by (simp add: CompA_def comp_def ParallelId_def)
    

lemma io_diagram_ParallelId[simp]: "io_diagram □"
  by (simp add: io_diagram_def ParallelId_def)

(*move*)
lemma in_equiv_aux_a :"distinct x ⟹ distinct y ⟹  set z ⊆ set x ⟹ [x ⊕ y ↝ x @ y] oo [x ↝ z] ∥ [y ↝ y] = [x ⊕ y ↝ z @ y]"
  by (subst switch_par_comp_Subst, simp_all add: distinct_addvars set_addvars Subst_eq)

(*move*)
lemma in_equiv_Parallel_aux_d: "distinct x ⟹ distinct y ⟹ set u ⊆ set x ⟹ perm y v
           ⟹ [x ⊕ y ↝ x @ v] oo [x ↝ u] ∥ [v ↝ v] = [x ⊕ y ↝ u @ v]"
        proof -
          assume [simp]: "distinct x"
          assume [simp]: "distinct y"
          assume [simp]: "set u ⊆ set x"
          assume [simp]: "perm y v"

          define v' where "v' ≡ newvars x (TVs v)"

          have [simp]: "distinct v"
            apply (subgoal_tac "perm y v")
            apply (subgoal_tac "distinct y")
            using dist_perm apply blast
            by simp_all

          have [simp]: "distinct v'"
            by (simp add: v'_def)

          have [simp]: "set x ∩ set v' = {}"
            by (simp add: v'_def)

          have [simp]: "distinct (x ⊕ y)"
            by (simp add: distinct_addvars)

          have [simp]: "set v' ∩ set u = {}"
            apply (subgoal_tac "set v' ∩ set x = {}")
            apply (subgoal_tac "set u ⊆ set x")
            apply blast
            apply simp
            using ‹set x ∩ set v' = {}› by blast

          have A: "TVs v' = TVs v"
            by (simp add: v'_def)
            
          have [simp]: "length v' = length v"
            by (metis ‹TVs v' = TVs v› length_TVs)

          have [simp]: "Subst (x @ v') (x @ v) (u @ v') = u @ v"
            apply (simp add: Subst_append)
            apply (subst Subst_not_in)
            apply (simp_all)
            apply (subst Subst_not_in_a)
            by (simp_all add: Subst_eq)

          have "[x ⊕ y ↝ x @ v] oo [x ↝ u] ∥ [v ↝ v] = [x ⊕ y ↝ x @ v] oo [x ↝ u] ∥ [v' ↝ v']"
            by (simp add: v'_def switch_newvars)
          also have "... = [x ⊕ y ↝ x @ v] oo [x @ v' ↝ u @ v']"
            apply (subst par_switch)
            by (simp_all)
          also have "... = [x ⊕ y ↝ u @ v]"
            apply (subst switch_comp_subst)
            apply (simp_all)
            apply (simp add: set_addvars)
            using ‹perm y v› perm_set_eq apply blast
            apply (simp add: le_supI1)
            by (simp add: v'_def)
          finally show ?thesis
            by simp
        qed

(*move*)
lemma comp_par_switch_subst: "distinct x ⟹ distinct y ⟹ set u ⊆ set x ⟹ set v ⊆ set y 
      ⟹ [x ⊕ y ↝ x @ y] oo [x ↝ u] ∥ [y ↝ v] = [x ⊕ y ↝ u @ v]"
        proof -
          assume [simp]: "distinct x"
          assume [simp]: "distinct y"
          assume [simp]: "set u ⊆ set x"
          assume [simp]: "set v ⊆ set y"
        
          define x' where "x' ≡ newvars (x@y) (TVs x)"

          have [simp]: "distinct x'"
            by (simp add: x'_def)

          have [simp]: "set x ∩ set x' = {}"
            by (metis Int_empty_right inf.commute inf.left_commute inf_sup_absorb newvars_old_distinct set_append x'_def)

          have [simp]: "TVs x = TVs x'"
            by (simp add: x'_def)

          have [simp]: "length x = length x'"
            by (metis ‹TVs x = TVs x'› length_TVs)

          have [simp]: "set x' ∩ set y = {}"
            by (metis Diff_disjoint diff_distinct diff_inter_left diff_union inf_bot_left newvars_old_distinct_a set_diff set_inter x'_def)            

          have [simp]: "set (Subst x x' u) ⊆ set x'"
            by (simp add: Subst_set_incl)

          have [simp]: "distinct (x ⊕ y)"
            by (simp add: distinct_addvars)

          have [simp]: "set y ∩ set (Subst x x' u) = {}"
            apply (subgoal_tac "set (Subst x x' u) ⊆ set x'")
            apply (subgoal_tac "set y ∩ set x' = {}")
            apply blast
            by (simp_all add: Int_commute)

          have [simp]: "set x' ∩ set v = {}"
            apply (subgoal_tac "set v ⊆ set y")
            apply (subgoal_tac "set x' ∩ set y = {}")
            apply blast
            by simp_all

          have [simp]: "Subst (x' @ y) (x @ y) ((Subst x x' u) @ v) = u @ v"
            apply (simp add: Subst_append)
            apply (subst Subst_not_in, simp_all)
            apply (subst Subst_not_in_a, simp_all)
            by (simp add: Subst_eq)
         

          have "[x ⊕ y ↝ x @ y] oo [x ↝ u] ∥ [y ↝ v] = [x ⊕ y ↝ x @ y] oo [Subst x x' x ↝ Subst x x' u] ∥ [y ↝ v]"
            apply (cut_tac u=x and v=x' and x=x and y=u in Subst_switch_more_general)
            apply simp_all
            by (simp add: Int_commute)
          also have "... = [x ⊕ y ↝ x @ y] oo [x' ↝ Subst x x' u] ∥ [y ↝ v]"
            by simp
          also have "... = [x ⊕ y ↝ x @ y] oo [x' @ y ↝ (Subst x x' u) @ v]"
            by (simp add: par_switch)
          also have "... = [x ⊕ y ↝ Subst (x' @ y) (x @ y) ((Subst x x' u) @ v)]"
            apply (subst switch_comp_subst, simp_all add: set_addvars)
            apply safe
            using ‹set (Subst x x' u) ⊆ set x'› apply blast
            using ‹set v ⊆ set y› by blast
          also have "... = [x ⊕ y ↝ u @ v]"
            by simp_all

          finally show ?thesis
            by simp
        qed
          
(*move*)
      lemma in_equiv_Parallel_aux_b :"distinct x ⟹ distinct y ⟹ perm u x ⟹ perm y v ⟹ [x ⊕ y ↝ x @ y] oo [x ↝ u] ∥ [y ↝ v] = [x ⊕ y ↝ u @ v]"
        by (subst comp_par_switch_subst, simp_all )

(*move*)
lemma [simp]: "set x ⊆ set (x ⊕ y)"
  by (simp add: set_addvars)
    
(*move*)
lemma [simp]: "set y ⊆ set (x ⊕ y)"
  by (simp add: set_addvars)

      declare distinct_addvars [simp]

lemma in_equiv_Parallel: "io_diagram B ⟹ io_diagram B' ⟹ in_equiv A B ⟹ in_equiv A' B' ⟹ in_equiv (A ||| A') (B ||| B')"
  apply (frule in_equiv_io_diagram, simp_all)
  apply (frule_tac A = A' in in_equiv_io_diagram, simp)
  apply (frule_tac A = A in in_equiv_io_diagram, simp)
  apply (simp add: in_equiv_def io_diagram_def, safe)
  apply (simp add: Parallel_def)
  apply (subst comp_parallel_distrib[THEN sym], simp_all)
  apply (subst comp_assoc[THEN sym], simp_all)
  apply (subst comp_par_switch_subst, simp_all)
  apply (subst comp_assoc[THEN sym], simp_all)
  by (simp add: switch_comp)


      (*todo: change name to Out_CompA*)
      thm local.BBB_a

      lemma map_Out_CompA: "length (Out A) = 1 ⟹ map (out ∘ CompA A) As = map out As"
        by (induction As, simp_all add: BBB_a out_def)

(*
lemma CompA_in[simp]: "length (Out A) = 1 ⟹ out A ∈ set (In B) ⟹ A ⊳ B = A ;; B"
  by (simp add: CompA_def)

lemma CompA_not_in[simp]: "length (Out A) = 1 ⟹ out A ∉ set (In B) ⟹ CompA A B = B"
  by (simp add: CompA_def out_def)
*)

lemma CompA_in[simp]: "out A ∈ set (In B) ⟹ A ⊳ B = A ;; B"
  by (simp add: CompA_def)

lemma CompA_not_in[simp]: "out A ∉ set (In B) ⟹ A ⊳ B = B"
  by (simp add: CompA_def out_def)

          
lemma in_equiv_CompA_Parallel_a: " deterministic (Trs A) ⟹ length (Out A) = 1 ⟹ io_diagram A ⟹ io_diagram B ⟹ io_diagram C 
  ⟹ out A ∈ set (In B) ⟹ out A ∈ set (In C) 
  ⟹ in_equiv ((A ⊳ B) ||| (A ⊳ C)) (A ⊳ (B ||| C))"
        apply (simp add: in_equiv_def, safe)
        apply (simp add: In_CompA set_addvars)
        apply (simp_all add: Comp_def CompA_def Parallel_def Let_def Var_def set_addvars diff_inter_right diff_inter_left)
        apply (simp_all add: Out_out par_empty_left)
        apply (simp add: addvars_assoc [THEN sym])
        apply (metis addvars_assoc addvars_minus perm_mset)
        apply (simp_all add: set_addvars)
        proof -
          assume [simp]: "deterministic (Trs A)"
          assume [simp]: "length (Out A) = Suc 0"
          assume [simp]: "io_diagram A"
          assume [simp]: "io_diagram B"
          assume [simp]: "io_diagram C"
          assume [simp]: "out A ∈ set (In B)"
          assume [simp]: "out A ∈ set (In C)"

          define IA where "IA ≡ In A"
          define IB where "IB ≡ In B"
          define IC  where "IC ≡ In C"
          define OA where "OA ≡ Out A"
          define IBA where "IBA ≡ IB ⊖ OA"
          define ICA where "ICA ≡ IC ⊖ OA"

          define IBA' where "IBA' ≡ newvars (IA @ OA @ ICA @ IBA) (TVs IBA)"
          define IA' where "IA' ≡ newvars (IBA' @ IA @ ICA) (TVs IA)"
          define ICA' where "ICA' ≡ newvars (IA' @ IBA' @ IA @ OA) (TVs ICA)"
          define OA' where "OA' ≡ newvars (OA @ IBA' @ ICA' @ IBA @ ICA @ IA) (TVs OA)"

          have [simp]: "TVs IA = TI (Trs A)"
            using ‹io_diagram A› io_diagram_def IA_def by fastforce

          have [simp]: "distinct IA"
            using ‹io_diagram A› io_diagram_def IA_def by fastforce

          have [simp]: "TVs OA = TO (Trs A)"
            using ‹io_diagram A› io_diagram_def OA_def by fastforce

          have [simp]: "distinct OA "
            using ‹io_diagram A› io_diagram_def OA_def by fastforce
            
          have [simp]: "TVs IB = TI (Trs B)"
            using ‹io_diagram B› io_diagram_def IB_def by fastforce

          have [simp]: "distinct IB"
            using ‹io_diagram B› io_diagram_def IB_def by fastforce

          have [simp]: "TVs IC = TI (Trs C)"
            using ‹io_diagram C› io_diagram_def IC_def by fastforce

          have [simp]: "distinct IC"
            using ‹io_diagram C› io_diagram_def IC_def by fastforce

          have [simp]: "distinct IBA"
            by (simp add: IBA_def)

          have [simp]: "distinct ICA"
            by (simp add: ICA_def)

          have [simp]: "distinct (IA ⊕ IBA)"
            by (simp)

          have [simp]: "distinct (IA ⊕ ICA)"
            by (simp)

          have [simp]: "distinct IBA'"
            by (simp add: IBA'_def)

          have [simp]: "set IBA' ∩ set IA = {}"
            by (metis IBA'_def Int_commute bot_eq_sup_iff inf_sup_distrib2 newvars_old_distinct_a set_append)

          have a[simp]: "set OA ∩ set IBA' = {}"
            by (metis IBA'_def bot_eq_sup_iff inf_sup_distrib2 newvars_old_distinct_a set_append)

          have [simp]: "set IBA' ∩ set ICA = {}"
            by (metis IBA'_def Int_commute bot_eq_sup_iff inf_sup_distrib2 newvars_old_distinct_a set_append)

          have [simp]: "TVs IBA' = TVs IBA"
            by (simp add: IBA'_def)

          have [simp]: "distinct IA'"
            by (simp add: IA'_def)

          have [simp]: "set IA' ∩ set IBA' = {}"
            by (metis IA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set IA' ∩ set IA = {}"
            by (metis IA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]:"distinct ICA'"
            by (simp add: ICA'_def)

          have [simp]: "set IA ∩ set ICA' = {}"
            by (metis ICA'_def Int_empty_right inf_commute inf_left_commute inf_sup_absorb inf_sup_aci(5) newvars_old_distinct set_append)

          have [simp]: "set IBA' ∩ set ICA' = {}"
            by (metis ICA'_def Int_empty_right inf_commute inf_left_commute inf_sup_absorb inf_sup_aci(5) newvars_old_distinct set_append)

          have [simp]: "set IA' ∩ set ICA' = {}"
            by (metis ICA'_def Int_empty_right inf_commute inf_left_commute inf_sup_absorb newvars_old_distinct set_append)

          have [simp]: "TVs (IA') = TI (Trs A) "
            by (simp add: IA'_def)

          have [simp]: "TVs ICA = TVs ICA'"
            by (simp add: ICA'_def)

          have [simp]: "length IA' = length IA"
            by (simp add: TVs_length_eq)

          have [simp]: "length IBA' = length IBA"
            by (metis ‹TVs IBA' = TVs IBA› length_TVs)

          have [simp]: "length ICA' = length ICA"
            by (metis ‹TVs ICA = TVs ICA'› length_TVs)

          have [simp]: "Subst (IA' @ IBA' @ IA @ ICA') (IA @ IBA @ IA @ ICA) IA' = IA"
            apply (subst Subst_not_in, simp_all)
            by (simp add: Int_commute)

          have [simp]: "Subst (IA' @ IBA' @ IA @ ICA') (IA @ IBA @ IA @ ICA) IA = IA"
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in_a, simp_all)
            by (subst Subst_not_in, simp_all add: Int_commute)

          have [simp]: "Subst (IA' @ IBA' @ IA @ ICA') (IA @ IBA @ IA @ ICA) IBA' = IBA"
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in, simp_all add: Int_commute)
            using ‹set IBA' ∩ set IA = {}› by blast

          have [simp]: "Subst (IA' @ IBA' @ IA @ ICA') (IA @ IBA @ IA @ ICA) ICA' = ICA"
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in_a, simp_all)
            by (subst Subst_not_in_a, simp_all)

          have [simp]: "Subst (IA' @ IBA' @ IA @ ICA') (IA @ IBA @ IA @ ICA) (IA' @ IA @ IBA' @ ICA') = IA @ IA @ IBA @ ICA"
            by (simp add: Subst_append)

          have [simp]: "distinct OA'"
            by (simp add: OA'_def)

          have [simp]: "TVs OA' = TO (Trs A)"
            by (simp add: OA'_def)

          have [simp]: "set OA' ∩ set OA = {}"
            by (metis OA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA' ∩ set IBA' = {}"
            by (metis OA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA' ∩ set ICA' = {}"
            by (metis OA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA' ∩ set IBA = {}"
            by (metis OA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA' ∩ set ICA = {}"
            by (metis OA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA ∩ set ICA' = {}"
            by (metis ICA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set IBA' ∩ set IBA = {}"
            by (metis IBA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set IBA ∩ set OA = {}"
            apply (simp add: IBA_def set_diff)
            by blast

          have [simp]: "length OA = length OA'"
            by (simp add: TVs_length_eq)

          have [simp]: "[IA ↝ IA @ IA] oo Trs A ∥ Trs A = Trs A oo [OA ↝ OA @ OA]"
            apply (subgoal_tac "deterministic (Trs A)")
            apply (simp add: deterministicE)
            by simp

          have [simp]: "Subst (OA' @ OA @ IBA' @ ICA') (OA @ OA @ IBA' @ ICA) OA' = OA"
            apply (subst Subst_not_in, simp_all)
            using ‹set OA' ∩ set IBA' = {}› ‹set OA' ∩ set ICA' = {}› ‹set OA' ∩ set OA = {}› by blast

          have [simp]: "Subst (OA' @ OA @ IBA' @ ICA') (OA @ OA @ IBA' @ ICA) IBA' = IBA'"
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in, simp_all)
            by (simp add: Int_commute)

          have [simp]: "Subst (OA' @ OA @ IBA' @ ICA') (OA @ OA @ IBA' @ ICA) OA = OA "
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in, simp_all)
            by (metis Int_commute Un_absorb ‹set OA ∩ set ICA' = {}› a inf_sup_distrib2)
            
          have [simp]: "Subst (OA' @ OA @ IBA' @ ICA') (OA @ OA @ IBA' @ ICA) ICA' = ICA"
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in_a, simp_all)
            by (subst Subst_not_in_a, simp_all)

          have [simp]: "Subst (OA' @ OA @ IBA' @ ICA') (OA @ OA @ IBA' @ ICA) (OA' @ IBA' @ OA @ ICA') = OA @ IBA' @ OA @ ICA"
            by (simp add: Subst_append)

          have [simp]: "distinct (IA ⊕ IBA ⊕ (IA ⊕ ICA))"
            by (simp)

          have [simp]: "perm (IA ⊕ IBA ⊕ (IA ⊕ ICA)) (IA ⊕ (IB ⊕ IC ⊖ OA))"
            apply (simp add: IBA_def ICA_def)
            by (metis diff_eq addvars_assoc addvars_def addvars_empty addvars_minus perm_tp perm_trans)

          have [simp]: "distinct (IB ⊕ IC ⊖ OA)"
            by (simp )

          have [simp]: "set OA ∩ set (IB ⊕ IC ⊖ OA) = {}"
            by (simp add: set_diff)

          have [simp]: "OA ⊗ IB = OA"
            by (simp add: OA_def IB_def Out_out)

          have [simp]: "OA ⊗ IC = OA"
            by (simp add: OA_def IC_def Out_out)

          have [simp]: "OA ⊗ (IB ⊕ IC) = OA"
            apply (simp add: addvars_def)
            by (metis (mono_tags, lifting) diff_eq Diff_Int_distrib ‹OA ⊗ IB = OA› ‹OA ⊗ IC = OA› empty_set inter_addvars_empty set_diff set_inter)
            
          have [simp]: "perm (OA @ (IB ⊕ IC ⊖ OA)) (IB ⊕ IC)"
            by (subst perm_aux_a, simp_all)

          have [simp]: "set OA' ∩ set IA = {}"
            by (metis OA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA' ∩ set (IA ⊕ IBA ⊕ (IA ⊕ ICA)) = {}"
            by (simp add: set_addvars)

          have [simp]: "Subst (OA @ IBA' @ ICA) (OA' @ IBA @ ICA) OA = OA'"
            apply (subst Subst_not_in, simp_all)
            by (metis Diff_disjoint ICA_def Int_Un_distrib2 Un_empty_left a inf_commute set_diff)

          have [simp]: "Subst (OA @ IBA' @ ICA) (OA' @ IBA @ ICA) IBA' = IBA"
            apply (subst Subst_not_in_a, simp_all)
            apply (subst Subst_not_in, simp_all)
            by (simp add: Int_commute)

          have [simp]: "Subst (OA @ IBA' @ ICA) (OA' @ IBA @ ICA) ICA = ICA"
            apply (subst Subst_not_in_a, simp_all)
            apply (simp add: ICA_def set_diff)
            by (subst Subst_not_in_a, simp_all)

          have [simp]: "Subst (OA @ IBA' @ ICA) (OA' @ IBA @ ICA) (OA @ IBA' @ OA @ ICA) = OA' @ IBA @ OA' @ ICA"
            by (simp add: Subst_append)

          have [simp]: "Subst (OA @ (IBA ⊕ ICA)) (OA' @ (IBA ⊕ ICA)) IB = Subst (OA @ IBA) (OA' @ IBA) IB"
            apply (subst Subst_cancel_left, simp_all)
            apply (simp add: IBA_def ICA_def set_addvars set_diff)
            apply (subst Subst_cancel_left, simp_all)
            by (simp add: IBA_def set_addvars set_diff)

          have [simp]: "Subst (OA @ (IBA ⊕ ICA)) (OA' @ (IBA ⊕ ICA)) IC = Subst (OA @ ICA) (OA' @ ICA) IC"
            apply (subst Subst_cancel_left, simp_all)
            apply (simp add: IBA_def ICA_def set_addvars set_diff)
            apply (subst Subst_cancel_left, simp_all)
            by (simp add: ICA_def set_addvars set_diff)
            
          have [simp]: "Subst (OA @ (IBA ⊕ ICA)) (OA' @ (IBA ⊕ ICA)) (IB @ IC) = (Subst (OA @ IBA) (OA' @ IBA ) IB) @ (Subst (OA @ ICA) (OA' @ ICA) IC)"
            by (simp add: Subst_append)

            
          have A: "[In A ⊕ (In B ⊖ [out A]) ⊕ (In A ⊕ (In C ⊖ [out A])) ↝ (In A ⊕ (In B ⊖ [out A])) @ (In A ⊕ (In C ⊖ [out A]))] oo
                ([In A ⊕ (In B ⊖ [out A]) ↝ In A @ (In B ⊖ [out A])] oo Trs A ∥ [In B ⊖ [out A] ↝ In B ⊖ [out A] ] oo [out A # (In B ⊖ [out A]) ↝ In B] oo Trs B) ∥
                ([In A ⊕ (In C ⊖ [out A]) ↝ In A @ (In C ⊖ [out A])] oo Trs A ∥ [In C ⊖ [out A] ↝ In C ⊖ [out A] ] oo [out A # (In C ⊖ [out A]) ↝ In C] oo Trs C) =
                [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo 
                ([OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
            proof -
              have "[In A ⊕ (In B ⊖ [out A]) ⊕ (In A ⊕ (In C ⊖ [out A])) ↝ (In A ⊕ (In B ⊖ [out A])) @ (In A ⊕ (In C ⊖ [out A]))] oo
                  ([In A ⊕ (In B ⊖ [out A]) ↝ In A @ (In B ⊖ [out A])] oo Trs A ∥ [In B ⊖ [out A] ↝ In B ⊖ [out A] ] oo [out A # (In B ⊖ [out A]) ↝ In B] oo Trs B) ∥
                  ([In A ⊕ (In C ⊖ [out A]) ↝ In A @ (In C ⊖ [out A])] oo Trs A ∥ [In C ⊖ [out A] ↝ In C ⊖ [out A] ] oo [out A # (In C ⊖ [out A]) ↝ In C] oo Trs C) =
                  [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA ⊕ IBA) @ (IA ⊕ ICA)] oo
                  ([IA ⊕ IBA ↝ IA @ IBA] oo Trs A ∥ [IBA ↝ IBA] oo [OA @ IBA ↝ IB] oo Trs B) ∥
                  ([IA ⊕ ICA ↝ IA @ ICA] oo Trs A ∥ [ICA ↝ ICA] oo [OA @ ICA ↝ IC] oo Trs C)"
                by (simp add: IA_def IB_def IC_def IBA_def ICA_def OA_def Out_out)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA ⊕ IBA) @ (IA ⊕ ICA)] oo
                  ([IA ⊕ IBA ↝ IA @ IBA] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo
                   (Trs A ∥ [IBA ↝ IBA]) ∥ (Trs A ∥ [ICA ↝ ICA]) oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C)"
                by (simp add: comp_parallel_distrib )
              also have "... = ([(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA ⊕ IBA) @ (IA ⊕ ICA)] oo [IA ⊕ IBA ↝ IA @ IBA] ∥ [IA ⊕ ICA ↝ IA @ ICA]) oo
                   (Trs A ∥ [IBA ↝ IBA]) ∥ (Trs A ∥ [ICA ↝ ICA]) oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_assoc )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   (Trs A ∥ [IBA ↝ IBA]) ∥ (Trs A ∥ [ICA ↝ ICA]) oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (subst comp_par_switch_subst)
                by (simp_all add: set_addvars)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   Trs A ∥ ([IBA ↝ IBA] ∥ Trs A) ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: par_assoc)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   Trs A ∥ ([IBA' ↝ IBA'] ∥ Trs A) ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: IBA'_def switch_newvars)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   Trs A ∥ ([IBA' @ IA ↝ IA @ IBA'] oo Trs A ∥ [IBA' ↝ IBA'] oo [OA @ IBA' ↝ IBA' @ OA]) ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (cut_tac y=IA and x="IBA'" and T="Trs A" and S="[IBA' ↝ IBA']" and u=OA and v="IBA'" in switch_par)
                by simp_all
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   ([IA ↝ IA] ∥ [IBA' @ IA ↝ IA @ IBA'] ∥ [ICA ↝ ICA] oo Trs A ∥ (Trs A ∥ [IBA' ↝ IBA']) ∥ [ICA ↝ ICA] oo [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA]) oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_parallel_distrib )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   [IA ↝ IA] ∥ [IBA' @ IA ↝ IA @ IBA'] ∥ [ICA ↝ ICA] oo 
                   Trs A ∥ (Trs A ∥ [IBA' ↝ IBA']) ∥ [ICA ↝ ICA] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_assoc  )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   [IA ↝ IA] ∥ [IBA' @ IA ↝ IA @ IBA'] ∥ [ICA ↝ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' ↝ IBA'] ∥ [ICA ↝ ICA] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: par_assoc)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   [IA' ↝ IA'] ∥ [IBA' @ IA ↝ IA @ IBA'] ∥ [ICA ↝ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' ↝ IBA'] ∥ [ICA ↝ ICA] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: IA'_def distinct_id)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   [IA' ↝ IA'] ∥ [IBA' @ IA ↝ IA @ IBA'] ∥ [ICA' ↝ ICA'] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' ↝ IBA'] ∥ [ICA ↝ ICA] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (metis (full_types) switch_newvars ICA'_def ‹distinct ICA›)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ (IA @ IBA) @ (IA @ ICA)] oo
                   [IA' @ IBA' @ IA @ ICA' ↝ IA' @ IA @ IBA' @ ICA'] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' ↝ IBA'] ∥ [ICA ↝ ICA] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (subst par_switch, simp_all)
                apply (subst par_switch, simp_all)
                by auto
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IA @ IBA @ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' ↝ IBA'] ∥ [ICA ↝ ICA] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (subst switch_comp_subst, simp_all )
                by (auto simp add: IA_def IBA_def IB_def OA_def ICA_def IC_def set_diff set_inter set_addvars)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IA @ IBA @ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' @ ICA  ↝ IBA' @ ICA ] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA ↝ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (simp add: par_assoc)
                by (subst par_switch, simp_all)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IA @ IBA @ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' @ ICA  ↝ IBA' @ ICA ] oo 
                   [OA ↝ OA] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA' ↝ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (metis (full_types) switch_newvars ICA'_def ‹distinct ICA›)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IA @ IBA @ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' @ ICA  ↝ IBA' @ ICA ] oo 
                   [OA' ↝ OA'] ∥ [OA @ IBA' ↝ IBA' @ OA] ∥ [ICA' ↝ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (metis switch_newvars  OA'_def ‹distinct OA›)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IA @ IBA @ ICA] oo 
                   (Trs A ∥ Trs A) ∥ [IBA' @ ICA  ↝ IBA' @ ICA ] oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (subst par_switch, simp_all)
                apply (subst par_switch, simp_all)
                by blast
              also have "... = ([(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo [IA ↝ IA @ IA] ∥ [IBA' @ ICA ↝ IBA' @ ICA]) oo 
                   (Trs A ∥ Trs A) ∥ [IBA' @ ICA  ↝ IBA' @ ICA ] oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (subst switch_par_comp_Subst, simp_all add: set_addvars Subst_eq )
                apply blast
                by blast
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   ([IA ↝ IA @ IA] ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo (Trs A ∥ Trs A) ∥ [IBA' @ ICA  ↝ IBA' @ ICA ]) oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_assoc  )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   (([IA ↝ IA @ IA] oo (Trs A ∥ Trs A)) ∥ [IBA' @ ICA ↝ IBA' @ ICA]) oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_parallel_distrib)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   ((Trs A oo [OA ↝ OA @ OA]) ∥ [IBA' @ ICA ↝ IBA' @ ICA]) oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                 by simp
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   (Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo [OA ↝ OA @ OA] ∥ [IBA' @ ICA ↝ IBA' @ ICA]) oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_parallel_distrib)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   (Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo [OA @ IBA' @ ICA ↝ OA @ OA @ IBA' @ ICA]) oo 
                   [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA'] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                apply (subst par_switch, simp_all)
                by (simp add: ICA_def set_diff)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo 
                   ([OA @ IBA' @ ICA ↝ OA @ OA @ IBA' @ ICA] oo [OA' @ OA @ IBA' @ ICA' ↝ OA' @ IBA' @ OA @ ICA']) oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by (simp add: comp_assoc  )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo 
                   [OA @ IBA' @ ICA ↝ Subst (OA' @ OA @ IBA' @ ICA') (OA @ OA @ IBA' @ ICA) (OA' @ IBA' @ OA @ ICA')] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                 apply (subst switch_comp_subst, simp_all)
                 by auto
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo 
                   [OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo
                   [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo
                   Trs B ∥ Trs C"
                by simp
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ IBA @ ICA] oo 
                   Trs A  ∥ [IBA' @ ICA ↝ IBA' @ ICA] oo 
                   ([OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"              
                by (simp add: comp_assoc  )
              finally show ?thesis
                by simp
            qed

          have B: "[In A ⊕ (In B ⊖ [out A]) ⊕ (In A ⊕ (In C ⊖ [out A])) ↝ In A ⊕ (In B ⊕ In C ⊖ [out A])] oo
              ([In A ⊕ (In B ⊕ In C ⊖ [out A]) ↝ In A @ (In B ⊕ In C ⊖ [out A])] oo Trs A ∥ [In B ⊕ In C ⊖ [out A] ↝ In B ⊕ In C ⊖ [out A] ] oo [out A # (In B ⊕ In C ⊖ [out A]) ↝ In B ⊕ In C] oo
              ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C)) =
               [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ IC ⊖ OA)] oo 
              Trs A ∥ [IB ⊕ IC ⊖ OA ↝ IB ⊕ IC ⊖ OA] oo 
              ([OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC] oo Trs B ∥ Trs C)"
            proof - 
              have "[In A ⊕ (In B ⊖ [out A]) ⊕ (In A ⊕ (In C ⊖ [out A])) ↝ In A ⊕ (In B ⊕ In C ⊖ [out A])] oo
                  ([In A ⊕ (In B ⊕ In C ⊖ [out A]) ↝ In A @ (In B ⊕ In C ⊖ [out A])] oo Trs A ∥ [In B ⊕ In C ⊖ [out A] ↝ In B ⊕ In C ⊖ [out A] ] oo [out A # (In B ⊕ In C ⊖ [out A]) ↝ In B ⊕ In C] oo
                  ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C)) =
                  [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA ⊕ (IB ⊕ IC ⊖ OA)] oo
                  ([IA ⊕ (IB ⊕ IC ⊖ OA) ↝ IA @ (IB ⊕ IC ⊖ OA)] oo Trs A ∥ [IB ⊕ IC ⊖ OA ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB ⊕ IC] oo
                  ([IB ⊕ IC ↝ IB @ IC] oo Trs B ∥ Trs C))"
                by (simp add: IA_def IB_def IC_def OA_def IBA_def ICA_def Out_out)
              also have "... = ([(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA ⊕ (IB ⊕ IC ⊖ OA)] oo [IA ⊕ (IB ⊕ IC ⊖ OA) ↝ IA @ (IB ⊕ IC ⊖ OA)]) oo 
                  Trs A ∥ [IB ⊕ IC ⊖ OA ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB ⊕ IC] oo
                  ([IB ⊕ IC ↝ IB @ IC] oo Trs B ∥ Trs C)"
                by (simp add: comp_assoc  )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ IC ⊖ OA)] oo 
                  Trs A ∥ [IB ⊕ IC ⊖ OA ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB ⊕ IC] oo
                  ([IB ⊕ IC ↝ IB @ IC] oo Trs B ∥ Trs C)"
                by (subst switch_comp, simp_all)
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ IC ⊖ OA)] oo 
                  Trs A ∥ [IB ⊕ IC ⊖ OA ↝ IB ⊕ IC ⊖ OA] oo 
                  (([OA @ (IB ⊕ IC ⊖ OA) ↝ IB ⊕ IC] oo [IB ⊕ IC ↝ IB @ IC]) oo Trs B ∥ Trs C)"
                by (simp add: comp_assoc  )
              also have "... = [(IA ⊕ IBA) ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ IC ⊖ OA)] oo 
                  Trs A ∥ [IB ⊕ IC ⊖ OA ↝ IB ⊕ IC ⊖ OA] oo 
                  ([OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC] oo Trs B ∥ Trs C)"
                by (subst switch_comp, simp_all)
              finally show ?thesis
                by simp
            qed

          have C: "[OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IBA @ ICA] oo [OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] =
                   [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ (Subst (OA @ IBA) (OA' @ IBA ) IB) @ (Subst (OA @ ICA) (OA' @ ICA) IC)]"
            proof -
              have "[OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IBA @ ICA] oo [OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] =
                    [OA' ↝ OA'] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IBA @ ICA] oo [OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC]"
                by (metis ‹distinct OA› OA'_def switch_newvars)
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ OA' @ IBA @ ICA ] oo [OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC]"
                apply (subst par_switch, simp_all add: set_addvars)
                by blast
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ OA' @ IBA @ OA' @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC]"
                apply (subst switch_comp_subst, simp_all)
                apply (simp_all add: ICA_def set_diff)
                by (auto simp add: set_addvars set_diff)
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ (OA' @ IBA) @ (OA' @ ICA)] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC]"
                by simp
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ (Subst (OA @ IBA) (OA' @ IBA ) IB) @ (Subst (OA @ ICA) (OA' @ ICA) IC)]"
                apply (subst switch_par_comp_Subst, simp_all)
                apply (simp add: IBA_def set_diff)
                apply (simp add: ICA_def set_diff)
                apply (simp_all add: set_addvars)
                apply blast
                apply blast
                by (simp_all add: IBA_def ICA_def set_diff)
              finally show ?thesis
                by simp
            qed
         
          have D: "[OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC] = 
                   [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ (Subst (OA @ IBA) (OA' @ IBA ) IB) @ (Subst (OA @ ICA) (OA' @ ICA) IC)]"
            proof -
              have "[OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC] = 
                    [OA' ↝ OA'] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC]"
                by (metis ‹distinct OA› OA'_def switch_newvars)
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ OA' @ (IB ⊕ IC ⊖ OA)] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC]"
                apply (subst par_switch, simp_all)
                apply (simp add: IBA_def ICA_def set_diff set_addvars)
                by blast
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA))  ↝ Subst (OA @ (IB ⊕ IC ⊖ OA)) (OA' @ (IB ⊕ IC ⊖ OA)) (IB @ IC)]"
                apply (subst switch_comp_subst, simp_all)
                by (auto simp add: set_addvars set_diff OA_def IBA_def IC_def ICA_def)
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ Subst (OA @ (IBA ⊕ ICA)) (OA' @ (IBA ⊕ ICA)) (IB @ IC)]"
                by (simp add: addvars_minus IBA_def[THEN symmetric] ICA_def [THEN symmetric])
              also have "... = [OA' @ (IA ⊕ IBA ⊕ (IA ⊕ ICA)) ↝ (Subst (OA @ IBA) (OA' @ IBA ) IB) @ (Subst (OA @ ICA) (OA' @ ICA) IC)]"
                by simp
              finally show ?thesis
                by simp
            qed

          have E: "[OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IBA @ ICA] oo ([OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C) =
                   [OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IB ⊕ IC ⊖ OA] oo ([OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC] oo Trs B ∥ Trs C)"
            apply (subgoal_tac "[OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IBA @ ICA] oo [OA @ IBA' @ ICA ↝ OA @ IBA' @ OA @ ICA] oo [OA @ IBA ↝ IB] ∥ [OA @ ICA ↝ IC] = [OA ↝ OA] ∥ [IA ⊕ IBA ⊕ (IA ⊕ ICA) ↝ IB ⊕ IC ⊖ OA] oo [OA @ (IB ⊕ IC ⊖ OA) ↝ IB @ IC]")
            apply (simp add: comp_assoc [THEN sym]  )
            by (simp add: C D)

          show "[In A ⊕ (In B ⊖ [out A]) ⊕ (In A ⊕ (In C ⊖ [out A])) ↝ (In A ⊕ (In B ⊖ [out A])) @ (In A ⊕ (In C ⊖ [out A]))] oo
              ([In A ⊕ (In B ⊖ [out A]) ↝ In A @ (In B ⊖ [out A])] oo Trs A ∥ [In B ⊖ [out A] ↝ In B ⊖ [out A] ] oo [out A # (In B ⊖ [out A]) ↝ In B] oo Trs B) ∥
              ([In A ⊕ (In C ⊖ [out A]) ↝ In A @ (In C ⊖ [out A])] oo Trs A ∥ [In C ⊖ [out A] ↝ In C ⊖ [out A] ] oo [out A # (In C ⊖ [out A]) ↝ In C] oo Trs C) =
              [In A ⊕ (In B ⊖ [out A]) ⊕ (In A ⊕ (In C ⊖ [out A])) ↝ In A ⊕ (In B ⊕ In C ⊖ [out A])] oo
              ([In A ⊕ (In B ⊕ In C ⊖ [out A]) ↝ In A @ (In B ⊕ In C ⊖ [out A])] oo Trs A ∥ [In B ⊕ In C ⊖ [out A] ↝ In B ⊕ In C ⊖ [out A] ] oo [out A # (In B ⊕ In C ⊖ [out A]) ↝ In B ⊕ In C] oo
              ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C))"
            apply (simp add: A B)
            apply (rule_tac v="OA" in par_switch_eq, simp_all add:   set_addvars set_diff)
            apply blast
            apply blast
            apply (simp add: IBA_def ICA_def set_diff)
            apply blast
            by (simp add: E)
        qed

      lemma in_equiv_CompA_Parallel_c: "length (Out A) = 1 ⟹ io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ out A ∉ set (In B) ⟹ out A ∈ set (In C) ⟹ 
              in_equiv (CompA A B ||| CompA A C) (CompA A (B ||| C))"
        apply (simp add: in_equiv_def, safe)
        apply (simp add: Comp_def Let_def In_CompA set_addvars Var_def diff_inter_left diff_inter_right)
        apply (simp add: addvars_minus diff_disjoint Out_out)
        apply (subst set_perm)
        apply (simp add:  io_diagram_def )
        apply (simp add:  io_diagram_def )
        apply (simp add: set_addvars set_diff)
        apply blast
        apply simp
        apply (simp_all add: Comp_def Let_def BBB_a Var_def)
        apply (simp_all add: Out_out)
        apply (simp add: Let_def Parallel_def In_CompA Var_def Comp_def par_empty_left set_addvars diff_inter_left diff_inter_right Out_out[THEN sym] diff_union)
        apply (simp add: Out_out set_addvars par_empty_left)
        apply (simp add: Out_out[THEN sym])
        proof -
          assume [simp]: "io_diagram A"
          assume [simp]: "io_diagram B"
          assume [simp]: "io_diagram C"
          assume [simp]: "length (Out A) = Suc 0"
          assume [simp]: "out A ∉ set (In B)"
          assume [simp]: "out A ∈ set (In C)"

          define IA where "IA ≡ In A"
          define IB where "IB ≡ In B"
          define IC where "IC ≡ In C"
          define OA where "OA ≡ Out A"

          define ICA where "ICA ≡ IC ⊖ OA"

          define IB' where "IB' ≡ newvars (IA @ OA @ ICA) (TVs IB)"

          define ICA' where "ICA' ≡ newvars (IA @ IB' @ OA @ ICA) (TVs ICA)"

          have [simp]: "TVs IB = TI (Trs B)"
            using IB_def ‹io_diagram B› io_diagram_def by blast

          have [simp]: "TVs IA = TI (Trs A)"
            using IA_def ‹io_diagram A› io_diagram_def by blast

          have [simp]: "TVs OA = TO (Trs A)"
            using OA_def ‹io_diagram A› io_diagram_def by blast

          have [simp]: "TVs IC = TI (Trs C)"
            using IC_def ‹io_diagram C› io_diagram_def by blast

          have [simp]: "distinct IB"
            using IB_def ‹io_diagram B› io_diagram_def by blast

          have [simp]: "distinct IB'"
            by (simp add: IB'_def)

          have [simp]: "distinct IA"
            using IA_def ‹io_diagram A› io_diagram_def by blast

          have [simp]: "distinct IC"
            using IC_def ‹io_diagram C› io_diagram_def by blast

          have [simp]: "set IB' ∩ set IA = {}"
            by (metis IB'_def UnCI disjoint_iff_not_equal newvars_old_distinct set_append)

          have [simp]: "distinct OA"
            using OA_def ‹io_diagram A› io_diagram_def by blast

          have [simp]: "set OA ∩ set IB' = {}"
            by (metis IB'_def UnCI disjoint_iff_not_equal newvars_old_distinct set_append)

          have [simp]: "distinct ICA"
            by (simp add: ICA_def )

          have [simp]: "TVs IB' = TI (Trs B)"
            by (simp add: IB'_def)

          have [simp]: "distinct (IA ⊕ ICA)"
            by (simp )

          have [simp]:"set IB' ∩ set (ICA) = {}"
            by (metis Diff_disjoint IB'_def diff_disjoint diff_union newvars_old_distinct_a set_diff)

          have [simp]: "set (IA ⊕ ICA) ∩ set IB' = {}"
            by (metis Int_commute ‹set IB' ∩ set ICA = {}› ‹set IB' ∩ set IA = {}› addvars_def empty_inter_diff inter_addvars_empty set_empty set_inter)

          have [simp]: "length IB' = length IB"
            by (simp add: TVs_length_eq)

          have [simp]: "length (IB' @ (IA ⊕ ICA)) = length (IB @ (IA ⊕ ICA))"
            by simp          

          have [simp]: "Subst (IB' @ (IA ⊕ ICA)) (IB @ (IA ⊕ ICA)) (IB' @ IA @ ICA) = IB @ IA @ ICA"
            by (simp add: Subst_append Subst_not_in Subst_not_in_a Subst_eq)

          have [simp]: "distinct (IB ⊕ (IA ⊕ (ICA)))"
            by (simp )

          have [simp]: "distinct (IB' @ (IA ⊕ ICA))"
            using ‹distinct (IA ⊕ ICA)› ‹distinct IB'› ‹set (IA ⊕ ICA) ∩ set IB' = {}› distinct_append by blast

          have [simp]: "distinct ICA'"
            by (simp add: ICA'_def)

          have [simp]: "set IA ∩ set ICA' = {}"
            by (metis ICA'_def append_is_Nil_conv empty_inter filter_append inter_filter newvars_old_distinct_a set_inter)

          have [simp]: "set IB' ∩ set ICA' = {}"
            by (metis ICA'_def append_is_Nil_conv empty_inter filter_append inter_filter newvars_old_distinct_a set_inter)

          have a: "TVs ICA = TVs ICA'"
            by (simp add: ICA_def ICA'_def)

          have [simp]: "length ICA' = length ICA"
            by (metis length_TVs a)


          have b: "Subst (IB' @ IA @ ICA') (IB @ IA @ ICA) IA = IA"
            apply (subst Subst_not_in_a)
            apply (simp_all)
            apply (subst Subst_not_in)
            by (simp_all add: Int_commute)
 
          have c: "Subst (IB' @ IA @ ICA') (IB @ IA @ ICA) IB' = IB"
            apply (subst Subst_not_in)
            apply simp_all
            using ‹set IB' ∩ set IA = {}› ‹set IB' ∩ set ICA' = {}› by blast

          have d: "Subst (IB' @ IA @ ICA') (IB @ IA @ ICA) ICA' = ICA"
            apply (cut_tac x="IB' @ IA " and x'="ICA'" and y="IB @ IA" and y'="ICA" and z="ICA'" in Subst_not_in_a)
            apply simp_all
            using ‹set IB' ∩ set ICA' = {}› ‹set IA ∩ set ICA' = {}› by blast

          have [simp]: "Subst (IB' @ IA @ ICA') (IB @ IA @ ICA) (IA @ IB' @ ICA') = IA @ IB @ ICA"
            by (simp add: Subst_append b c d)

          have [simp]: "set OA ∩ set ICA' = {}"
            by (metis ICA'_def Int_commute bot_eq_sup_iff inf_sup_distrib1 newvars_old_distinct_a set_append)

          have [simp]: "set OA ∩ set ICA = {}"
            by (simp add: ICA_def set_diff)

          have [simp]: "set IB' ∩ set OA = {}"
            using ‹set OA ∩ set IB' = {}› by blast

          have [simp]: "set IC ⊆ set OA ∪ set ICA"
            by (simp add: ICA_def set_diff)

          have [simp]: "set ICA' ∩ set ICA = {}"
            by (metis newvars_old_distinct_a ICA'_def Int_commute bot_eq_sup_iff inf_sup_distrib2 set_append)

          have e: "Subst ICA' ICA (OA @ IB' @ ICA') = OA @ IB' @ ICA"
            by (simp add: Subst_append)

          have f: "Subst ICA' ICA (IB' @ OA @ ICA') = IB' @ OA @ ICA"
            by (simp add: Subst_append)

          have [simp]: "set OA ∩ set (IB ⊕ ICA) = {}"
            apply (simp add: set_addvars)
            by (simp add: OA_def IB_def Out_out)

          have g: "IB ⊕ ICA = (IB ⊕ IC ⊖ OA)"
            apply (simp add: ICA_def addvars_def union_diff)
            apply (subgoal_tac "set IB ∩ set OA = {}")
            apply (simp add: diff_disjoint diff_sym)
            by (simp add: OA_def IB_def Out_out)


          have A: "[In B ⊕ (In A ⊕ (In C ⊖ Out A)) ↝ In B @ (In A ⊕ (In C ⊖ Out A))] oo
                      Trs B ∥ ([In A ⊕ (In C ⊖ Out A) ↝ In A @ (In C ⊖ Out A)] oo Trs A ∥ [In C ⊖ Out A ↝ In C ⊖ Out A] oo [out A # (In C ⊖ Out A) ↝ In C] oo Trs C) = 
                   [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo [OA @ IB' @ ICA ↝ IB' @ IC] oo Trs B ∥ Trs C"
            proof-
              have "[In B ⊕ (In A ⊕ (In C ⊖ Out A)) ↝ In B @ (In A ⊕ (In C ⊖ Out A))] oo
                    Trs B ∥ ([In A ⊕ (In C ⊖ Out A) ↝ In A @ (In C ⊖ Out A)] oo Trs A ∥ [In C ⊖ Out A ↝ In C ⊖ Out A] oo [out A # (In C ⊖ Out A) ↝ In C] oo Trs C) = 
                    [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    Trs B ∥ ([IA ⊕ ICA ↝ IA @ ICA] oo Trs A ∥ [ICA ↝ ICA] oo [OA @ ICA ↝ IC] oo Trs C)" (is "?lhs = ?T")
                by (simp add: IA_def IB_def IC_def ICA_def OA_def Out_out)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB ↝ IB] ∥ ([IA ⊕ ICA ↝ IA @ ICA] oo Trs A ∥ [ICA ↝ ICA] oo [OA @ ICA ↝ IC]) oo Trs B ∥ Trs C)"
                by (simp add: comp_parallel_distrib  )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    (([IB ↝ IB] ∥ ([IA ⊕ ICA ↝ IA @ ICA] oo Trs A ∥ [ICA ↝ ICA]) oo [IB ↝ IB] ∥ [OA @ ICA ↝ IC]) oo Trs B ∥ Trs C)"
                by (subst(2) comp_parallel_distrib, simp_all )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB ↝ IB] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo [IB ↝ IB] ∥ (Trs A ∥ [ICA ↝ ICA]) oo [IB ↝ IB] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
                by (simp add: comp_parallel_distrib  )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB ↝ IB] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo ([IB ↝ IB] ∥ Trs A) ∥ [ICA ↝ ICA] oo [IB ↝ IB] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
                by (simp add: par_assoc)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB' ↝ IB'] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo ([IB' ↝ IB'] ∥ Trs A) ∥ [ICA ↝ ICA] oo [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
                by (simp add: IB'_def distinct_id)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB' ↝ IB'] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo 
                    ([IB' @ IA ↝ IA @ IB'] oo Trs A ∥ [IB' ↝ IB'] oo [OA @ IB' ↝ IB' @ OA]) ∥ [ICA ↝ ICA] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
                apply (cut_tac S="[IB' ↝ IB']" and T ="Trs A" and x="IB'" and y="IA" and u="OA" and v="IB'" in switch_par)
                by simp_all
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB' ↝ IB'] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo 
                    (([IB' @ IA ↝ IA @ IB'] oo Trs A ∥ [IB' ↝ IB']) ∥ [ICA ↝ ICA]  oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA ↝ ICA]) oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
                by (subst(2) comp_parallel_distrib, simp_all add:   switch_comp)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    ([IB' ↝ IB'] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo 
                    (([IB' @ IA ↝ IA @ IB'] ∥ [ICA ↝ ICA] oo Trs A ∥ [IB' ↝ IB'] ∥ [ICA ↝ ICA]) oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA ↝ ICA]) oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C)"
                by (subst(2) comp_parallel_distrib, simp_all)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    [IB' ↝ IB'] ∥ [IA ⊕ ICA ↝ IA @ ICA] oo 
                    [IB' @ IA ↝ IA @ IB'] ∥ [ICA ↝ ICA] oo Trs A ∥ [IB' ↝ IB'] ∥ [ICA ↝ ICA] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA ↝ ICA] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: comp_assoc [THEN sym]  )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @ (IA ⊕ ICA)] oo
                    [IB' @ (IA ⊕ ICA) ↝ IB' @  (IA @ ICA)] oo 
                    [IB' @ IA ↝ IA @ IB'] ∥ [ICA ↝ ICA] oo Trs A ∥ [IB' ↝ IB'] ∥ [ICA ↝ ICA] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA ↝ ICA] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: par_switch set_addvars)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @  (IA @ ICA)] oo 
                    [IB' @ IA ↝ IA @ IB'] ∥ [ICA ↝ ICA] oo Trs A ∥ [IB' ↝ IB'] ∥ [ICA ↝ ICA] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA ↝ ICA] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: switch_comp_subst set_addvars)
    
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @  (IA @ ICA)] oo 
                    [IB' @ IA ↝ IA @ IB'] ∥ [ICA' ↝ ICA'] oo Trs A ∥ [IB' ↝ IB'] ∥ [ICA' ↝ ICA'] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA' ↝ ICA'] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: ICA'_def switch_newvars)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IB @  (IA @ ICA)] oo 
                    [IB' @ IA @ ICA'↝ IA @ IB' @ ICA'] oo Trs A ∥ [IB' ↝ IB'] ∥ [ICA' ↝ ICA'] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA' ↝ ICA'] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: par_switch)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' ↝ IB'] ∥ [ICA' ↝ ICA'] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA' ↝ ICA'] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                apply (subst switch_comp_subst, simp_all add: a)
                by (auto simp add: set_addvars set_diff)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo [OA @ IB' ↝ IB' @ OA] ∥ [ICA' ↝ ICA'] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: par_assoc par_switch)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo [OA @ IB'@ ICA' ↝ IB' @ OA @ ICA'] oo 
                    [IB' ↝ IB'] ∥ [OA @ ICA ↝ IC] oo Trs B ∥ Trs C"
                by (simp add: par_switch)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo [OA @ IB'@ ICA' ↝ IB' @ OA @ ICA'] oo 
                    [IB' @ OA @ ICA ↝ IB' @ IC] oo Trs B ∥ Trs C"
                by (subst par_switch, simp_all)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo 
                    ([OA @ IB'@ ICA' ↝ IB' @ OA @ ICA'] oo [IB' @ OA @ ICA ↝ IB' @ IC]) oo 
                    Trs B ∥ Trs C"
                by (simp add: comp_assoc a  )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo 
                    ([OA @ IB'@ ICA ↝ IB' @ OA @ ICA] oo [IB' @ OA @ ICA ↝ IB' @ IC]) oo 
                    Trs B ∥ Trs C"
                apply (cut_tac x="OA @ IB'@ ICA'" and y="IB' @ OA @ ICA'" and u="ICA'" and v="ICA" in Subst_switch_more_general)
                apply simp_all
                using ‹set IB' ∩ set ICA = {}› ‹set ICA' ∩ set ICA = {}› ‹set OA ∩ set ICA = {}› apply blast
                apply blast
                by (simp_all add: a e f)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo 
                    Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo 
                    [OA @ IB' @ ICA ↝ IB' @ IC] oo 
                    Trs B ∥ Trs C"
                apply (subst switch_comp, simp_all)
                  apply (metis append_assoc perm_append2 perm_append_swap)
                by (auto simp add: IC_def ICA_def set_addvars set_diff)
              finally show ?thesis
                by simp
            qed

          have [simp]: "distinct (IA ⊕ (IB ⊕ ICA))"
            by (simp )

          have [simp]: "perm (IB ⊕ (IA ⊕ ICA)) (IA ⊕ (IB ⊕ ICA))"
            apply (subst set_perm)
            apply simp_all
            apply (simp add: set_addvars)
            by blast

          have [simp]: "distinct (IB ⊕ ICA)"
            by (simp )

          have [simp]: "IC ⊗ OA = OA"
            apply (subgoal_tac "distinct IC")
            apply (simp add: IC_def OA_def Out_out)
            apply (subgoal_tac "out A ∈ set (In C)")
            apply (simp add: inter_subset_l1)
            by simp_all            

          have [simp]: "IB ⊗ OA = []"
            apply (simp add: IB_def OA_def Out_out)
            apply (subgoal_tac "out A ∉ set (In B)")
            apply (simp add: empty_inter)
            by simp            

          have [simp]: "perm (OA @ (IB ⊕ ICA)) (IB ⊕ IC)"
            apply (simp add: ICA_def addvars_def diff_sym)
            apply (subgoal_tac "perm (OA @ IB @ (IC ⊖ IB ⊖ OA)) (IB @ OA @ (IC ⊖ IB ⊖ OA))")
            apply (subgoal_tac "perm (OA @ (IC ⊖ IB ⊖ OA)) (IC ⊖ IB)")
            using perm_trans perm_union_right apply blast
            apply (subgoal_tac "OA = ((IC ⊖ IB) ⊗ OA)")
            apply (metis mset_inter_diff perm_mset union_code)
             apply (simp add: inter_diff_distrib diff_emptyset)
              by (metis append_assoc perm_append2 perm_append_swap)
            

          have B: "[In B ⊕ (In A ⊕ (In C ⊖ Out A)) ↝ In A ⊕ (In B ⊕ In C ⊖ Out A)] oo
                ([In A ⊕ (In B ⊕ In C ⊖ Out A) ↝ In A @ (In B ⊕ In C ⊖ Out A)] oo Trs A ∥ [In B ⊕ In C ⊖ Out A ↝ In B ⊕ In C ⊖ Out A] oo [out A # (In B ⊕ In C ⊖ Out A) ↝ In B ⊕ In C] oo
                ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C)) 
                = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo
                Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo 
                [OA @ (IB ⊕ ICA) ↝ IB @ IC]
                oo Trs B ∥ Trs C"
            proof-        
              have "[In B ⊕ (In A ⊕ (In C ⊖ Out A)) ↝ In A ⊕ (In B ⊕ In C ⊖ Out A)] oo
                    ([In A ⊕ (In B ⊕ In C ⊖ Out A) ↝ In A @ (In B ⊕ In C ⊖ Out A)] oo Trs A ∥ [In B ⊕ In C ⊖ Out A ↝ In B ⊕ In C ⊖ Out A] oo [out A # (In B ⊕ In C ⊖ Out A) ↝ In B ⊕ In C] oo
                    ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C)) =
                    [IB ⊕ (IA ⊕ ICA) ↝ IA ⊕ (IB ⊕ ICA)] oo
                    ([IA ⊕ (IB ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ (IB ⊕ IC)] oo
                    ([IB ⊕ IC ↝ IB @ IC] oo Trs B ∥ Trs C))"
                apply (simp only: g)
                by (simp add: IA_def IB_def ICA_def IC_def OA_def Out_out)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA ⊕ (IB ⊕ ICA)] oo
                    [IA ⊕ (IB ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ (IB ⊕ IC)] oo
                    [IB ⊕ IC ↝ IB @ IC] oo Trs B ∥ Trs C"
                by (simp add: comp_assoc[THEN sym]  )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo
                    Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ (IB ⊕ IC)] oo
                    [IB ⊕ IC ↝ IB @ IC] oo Trs B ∥ Trs C"
                by (subst switch_comp, simp_all)
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo
                    Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo 
                    ([OA @ (IB ⊕ ICA) ↝ (IB ⊕ IC)] oo [IB ⊕ IC ↝ IB @ IC])
                    oo Trs B ∥ Trs C"
                by (simp add: comp_assoc  )
              also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo
                    Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo 
                    [OA @ (IB ⊕ ICA) ↝ IB @ IC]
                    oo Trs B ∥ Trs C"
                by (subst switch_comp, simp_all)
              finally show ?thesis
                by simp
            qed

          have h: "Subst (OA @ IB' @ ICA) (OA @ IB @ ICA) IB' = IB"
            apply (subst Subst_not_in_a, simp_all)
            by (subst Subst_not_in, simp_all add: Int_commute)

          have i: "Subst (OA @ IB' @ ICA) (OA @ IB @ ICA) IC = IC"
            apply (subst Subst_cancel_right, simp_all)
            apply (subst Subst_not_in_a, simp_all)
            apply (metis ICA_def ‹set IB' ∩ set ICA = {}› ‹set IB' ∩ set OA = {}› inter_diff_empty set_inter)
            by (simp add: Subst_eq)
            

          have [simp]: "Subst (OA @ IB' @ ICA) (OA @ IB @ ICA) (IB' @ IC) = IB @ IC"
            by (simp add: Subst_append h i)

          have C: "[OA @ (IB ⊕ ICA) ↝ IB @ IC] = [OA @ (IB ⊕ ICA) ↝ OA @ IB @ ICA] oo [OA @ IB' @ ICA ↝ IB' @ IC]"
            apply (subst switch_comp_subst, simp_all)
            by (auto simp add: set_addvars set_diff IC_def ICA_def)

          from this have D: "[IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ IB @ IC]
            = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ OA @ IB @ ICA] oo [OA @ IB' @ ICA ↝ IB' @ IC]"
            apply simp
            by (simp add: comp_assoc  )

          have [simp]: "set OA ∩ set IB = {}"
            by (simp add: OA_def IB_def Out_out)

          define IA' where "IA' ≡ newvars (IB ⊕ ICA) (TVs IA)"

          have [simp]: "distinct IA'"
            by (simp add: IA'_def)

          have [simp]: "TI (Trs A) = TVs IA'"
            by (simp add: IA'_def)

          have [simp]: "set IA' ∩ set (IB ⊕ ICA) = {}"
            by (simp only: IA'_def newvars_old_distinct)

          have [simp]: "length IA' = length IA"
            by (metis TVs_length_eq ‹TI (Trs A) = TVs IA'› ‹TVs IA = TI (Trs A)›)

          have j: "Subst (IA' @ (IB ⊕ ICA)) (IA @ (IB ⊕ ICA)) IA' = IA"
            by (subst Subst_not_in, simp_all add: Int_commute)

          have [simp]: "set IA' ∩ set IB = {}"
            by (metis UnCI ‹set IA' ∩ set (IB ⊕ ICA) = {}› disjoint_iff_not_equal set_addvars)

          have [simp]: "set IA' ∩ set ICA = {}"
            by (metis UnCI ‹set IA' ∩ set (IB ⊕ ICA) = {}› disjoint_iff_not_equal set_addvars)

          have k: "Subst (IA' @ (IB ⊕ ICA)) (IA @ (IB ⊕ ICA)) (IB @ ICA) = IB @ ICA"
            by (simp add: Subst_not_in_a Subst_eq)

          have [simp]: " Subst (IA' @ (IB ⊕ ICA)) (IA @ (IB ⊕ ICA)) (IA' @ IB @ ICA) = IA @ IB @ ICA"
            apply (subst Subst_append)
            by (simp add: j k)

          have "[IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ OA @ IB @ ICA]
            = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA ↝ OA] ∥ [IB ⊕ ICA ↝ IB @ ICA]"
            by (subst par_switch, simp_all add: set_addvars)
          also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo (Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA ↝ OA] ∥ [IB ⊕ ICA ↝ IB @ ICA])"
            by (subst comp_assoc, simp_all add:  )
          also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB @ ICA]"
            by (subst comp_parallel_distrib, simp_all)
          also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo ([IA' ↝ IA'] oo Trs A) ∥ ([IB ⊕ ICA ↝ IB @ ICA] oo [IB' @ ICA' ↝ IB' @ ICA'])"
            apply (subst comp_id_switch, simp_all)
            apply (subst comp_switch_id, simp_all)
            by (simp add: a)
          also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo ([IA' @ (IB ⊕ ICA) ↝ IA' @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'])"
            apply (subst comp_parallel_distrib [THEN sym], simp_all add: a)
            by (subst par_switch, simp_all)
         also have "... = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo [IA' @ (IB ⊕ ICA) ↝ IA' @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA']"
           by (subst comp_assoc, simp_all add: comp_assoc  a)
         also have "... =  [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA']"
          apply (subst switch_comp_subst, simp_all)
          by (auto simp add: set_addvars set_diff)
            

         finally have E: "[IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] 
              = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ OA @ IB @ ICA]"
           by simp

          show "[In B ⊕ (In A ⊕ (In C ⊖ Out A)) ↝ In B @ (In A ⊕ (In C ⊖ Out A))] oo
              Trs B ∥ ([In A ⊕ (In C ⊖ Out A) ↝ In A @ (In C ⊖ Out A)] oo Trs A ∥ [In C ⊖ Out A ↝ In C ⊖ Out A] oo [out A # (In C ⊖ Out A) ↝ In C] oo Trs C) =
              [In B ⊕ (In A ⊕ (In C ⊖ Out A)) ↝ In A ⊕ (In B ⊕ In C ⊖ Out A)] oo
              ([In A ⊕ (In B ⊕ In C ⊖ Out A) ↝ In A @ (In B ⊕ In C ⊖ Out A)] oo Trs A ∥ [In B ⊕ In C ⊖ Out A ↝ In B ⊕ In C ⊖ Out A] oo [out A # (In B ⊕ In C ⊖ Out A) ↝ In B ⊕ In C] oo
              ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C))"
            apply (simp add: A B)
            apply (subgoal_tac " [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] oo [OA @ IB' @ ICA ↝ IB' @ IC] = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ IB @ IC]")
            apply (simp_all)
            apply (subst D)
            apply (subgoal_tac " [IB ⊕ (IA ⊕ ICA) ↝ IA @ IB @ ICA] oo Trs A ∥ [IB' @ ICA' ↝ IB' @ ICA'] = [IB ⊕ (IA ⊕ ICA) ↝ IA @ (IB ⊕ ICA)] oo Trs A ∥ [IB ⊕ ICA ↝ IB ⊕ ICA] oo [OA @ (IB ⊕ ICA) ↝ OA @ IB @ ICA]")
            apply simp_all
            by (simp add: E)
        qed



      lemmas distinct_addvars distinct_diff

lemma io_diagram_distinct: assumes A: "io_diagram A" shows [simp]: "distinct (In A)" 
  and [simp]: "distinct (Out A)" and [simp]: "TI (Trs A) = TVs (In A)" 
  and [simp]: "TO (Trs A) = TVs (Out A)"
  using A by (simp_all add: io_diagram_def)
    


      declare Subst_not_in_a  [simp]
      declare Subst_not_in  [simp]

      (*move*)
      lemma [simp]: "set x' ∩ set z = {} ⟹ TVs x = TVs y ⟹ TVs x' = TVs y' ⟹ Subst (x @ x') (y @ y') z = Subst x y z"
        by (metis Subst_not_in length_TVs)

      lemma [simp]: "set x ∩ set z = {} ⟹ TVs x = TVs y ⟹ TVs x' = TVs y' ⟹ Subst (x @ x') (y @ y') z = Subst x' y' z"
        by (metis Subst_not_in_a length_TVs)

      lemma [simp]: "set x ∩ set z = {} ⟹ TVs x = TVs y ⟹ Subst x y z = z"
        by (metis Subst_inex length_TVs)

      lemma [simp]: "distinct x ⟹ TVs x = TVs y ⟹ Subst x y x = y"
        by (metis Subst_all length_TVs)

      lemma "TVs x = TVs y ⟹ length x = length y"
        by (metis length_TVs)

        thm length_TVs

(*end simplification rules*)

      lemma in_equiv_switch_Parallel: "io_diagram A ⟹ io_diagram B ⟹ set (Out A) ∩ set (Out B) = {}  ⟹ 
        in_equiv (A ||| B) ((B ||| A) ;; [[ Out B @ Out A ↝ Out A @ Out B]])"
        apply (simp add: in_equiv_def Let_def Parallel_def Comp_def VarSwitch_def Var_def diff_inter_left diff_inter_right diff_eq par_empty_left par_empty_right)
        apply safe
        apply (metis addvars_def perm_switch perm_tp perm_trans io_diagram_def)
        proof -
          assume [simp]: "io_diagram A"
          assume [simp]: "io_diagram B"

          assume [simp]: "set (Out A) ∩ set (Out B) = {}"
          from this have [simp]: "set (Out B) ∩ set (Out A) = {}"
            by blast

          have [simp]: "perm (In A ⊕ In B) (In B ⊕ In A)"
            by (rule distinct_perm_switch, simp_all)

         from paralle_switch obtain x y u v where
            B: "distinct (x @ y)" and C: "distinct (u @ v)" and [simp]: "TVs x = TI (Trs B)" and [simp]: "TVs u = TO (Trs B)" and [simp]: "TVs y = TI (Trs A)" 
            and [simp]: "TVs v = TO (Trs A)" and A: "Trs B ∥ Trs A = [x @ y ↝ y @ x] oo (Trs A ∥ Trs B) oo [v @ u ↝ u @ v]"
            by blast

          from C have [simp]: "distinct u" and [simp]: "distinct v" and [simp]: "set u ∩ set v = {}" and [simp]: "set v ∩ set u = {}"
            by auto

          from B have [simp]: "distinct x" and [simp]: "distinct y" and [simp]: "set x ∩ set y = {}" and [simp]: "set y ∩ set x = {}"
            by auto

          have [simp]: "Subst (x @ y) (In B @ In A) (y @ x) = In A @ In B"
            by (simp add: Subst_append)

          have [simp]: "Subst (Out B @ Out A) (u @ v) (Out A @ Out B) = v @ u"
            by (simp add: Subst_append)


            thm comp_id_left
          have "[In A ⊕ In B ↝ In B ⊕ In A] oo ([In B ⊕ In A ↝ In B ⊕ In A] oo ([In B ⊕ In A ↝ In B @ In A] oo Trs B ∥ Trs A) oo [Out B @ Out A ↝ Out B @ Out A] oo [Out B @ Out A ↝ Out A @ Out B])
            = [In A ⊕ In B ↝ In B ⊕ In A] oo ([In B ⊕ In A ↝ In B @ In A] oo Trs B ∥ Trs A oo [Out B @ Out A ↝ Out B @ Out A] oo [Out B @ Out A ↝ Out A @ Out B])"
          by (simp add: distinct_id)
          also have "... = ([In A ⊕ In B ↝ In B ⊕ In A] oo [In B ⊕ In A ↝ In B @ In A]) oo Trs B ∥ Trs A oo ([Out B @ Out A ↝ Out B @ Out A] oo [Out B @ Out A ↝ Out A @ Out B])"
            by (simp add: comp_assoc)

          also have "... = [In A ⊕ In B ↝ In B @ In A] oo Trs B ∥ Trs A oo [Out B @ Out A  ↝ Out A @ Out B]"
            apply (subst switch_comp)
            by (auto simp add: set_addvars set_diff)

          also have "... = [In A ⊕ In B ↝ In B @ In A] oo ([x @ y ↝ y @ x] oo (Trs A ∥ Trs B) oo [v @ u ↝ u @ v]) oo [Out B @ Out A  ↝ Out A @ Out B]"
            by (simp add: A)
          also have "... = ([In A ⊕ In B ↝ In B @ In A] oo [x @ y ↝ y @ x]) oo Trs A ∥ Trs B oo ([v @ u ↝ u @ v] oo [Out B @ Out A  ↝ Out A @ Out B])"
            using B C by (simp add: comp_assoc)

          also have "... = [In A ⊕ In B ↝ In A @ In B] oo Trs A ∥ Trs B"
            using B C by (simp add: switch_comp_subst distinct_id set_addvars set_diff)

          finally show "[In A ⊕ In B ↝ In A @ In B] oo Trs A ∥ Trs B 
                      = [In A ⊕ In B ↝ In B ⊕ In A] oo ([In B ⊕ In A ↝ In B @ In A] oo Trs B ∥ Trs A oo [Out B @ Out A ↝ Out B @ Out A] oo [Out B @ Out A ↝ Out A @ Out B])"
          by simp
       qed

lemma in_out_equiv_Parallel: "io_diagram A ⟹ io_diagram B ⟹ set (Out A) ∩ set (Out B) = {}  ⟹  in_out_equiv (A ||| B) (B ||| A)"
    apply (frule in_equiv_switch_Parallel, simp_all)
    apply (simp add: in_equiv_def in_out_equiv_def Parallel_def VarSwitch_def Let_def Comp_def Var_def par_empty_left par_empty_right, safe)
    using distinct_perm_switch io_diagram_distinct(1) apply blast
    using perm_tp apply blast
    apply (unfold io_diagram_def)
    apply (simp add: comp_assoc)
    by (subst switch_comp, auto)


      declare Subst_eq [simp]

lemma assumes "in_equiv A A'" shows [simp]: "perm (In A) (In A')" 
  using assms in_equiv_def by blast
    

lemma Subst_cancel_left_type: "set x ∩ set z = {} ⟹ TVs x = TVs y ⟹ Subst (x @ z) (y @ z) w = Subst x y w"
  by (metis Subst_cancel_left length_TVs)
    

lemma diff_eq_set_right: "set y = set z ⟹ (x ⊖ y) = (x ⊖ z)"
  by (induction x, simp_all)

      lemma [simp]: "set (y ⊖ x) ∩ set x = {}"
        by (auto simp add: set_diff)

lemma in_equiv_Comp: "io_diagram A' ⟹ io_diagram B' ⟹ in_equiv A A' ⟹ in_equiv B B' ⟹ in_equiv (A ;; B) (A' ;; B')"
        proof -
          assume [simp]: "io_diagram A'"
          assume [simp]: "io_diagram B'"
          assume [simp]: "in_equiv A A'"
          assume [simp]: "in_equiv B B'"

          have [simp]: "io_diagram A"
            using ‹in_equiv A A'› ‹io_diagram A'› in_equiv_io_diagram by blast
          have [simp]: "io_diagram B"
            using ‹in_equiv B B'› ‹io_diagram B'› in_equiv_io_diagram by blast

          have [simp]: "Out A = Out A'"
            using ‹in_equiv A A'› in_equiv_def by blast

          have [simp]: "Out B = Out B'"
            using ‹in_equiv B B'› in_equiv_def by blast

          from ‹in_equiv A A'› have [simp]: "Trs A = [In A ↝ In A'] oo Trs A'"
            by (simp add: in_equiv_def)

          from ‹in_equiv B B'› have [simp]: "Trs B = [In B ↝ In B'] oo Trs B'"
            by (simp add: in_equiv_def)

          have [simp]: "set (In A') = set (In A)"
            using ‹in_equiv A A'› in_equiv_def perm_set_eq by blast
    
          have [simp]: "set (In B') = set (In B)"
            using ‹in_equiv B B'› in_equiv_def perm_set_eq by blast

          have [simp]: "(Out A' ⊖ In B') = (Out A' ⊖ In B)"
            by (rule diff_eq_set_right, simp)

          define v where "v ≡ newvars (In A @ In B) (TVs (Out A'))"

          have [simp]: "distinct v"
            by (simp add: v_def)

          have U: "set v ∩ set (In A @ In B) = {}"
            using newvars_old_distinct v_def by blast



        have [simp]:" set (In A ⊕ (In B ⊖ Out A')) ∩ set v = {}"
          using U by (unfold set_addvars set_diff, auto)

        have [simp]:" set v ∩ set (In A ⊕ (In B ⊖ Out A')) = {}"
          using U by (unfold set_addvars set_diff, auto)
          
          from U have [simp]: "set v ∩ set (In A) = {}"
            by simp
          from U have [simp]: "set v ∩ set (In B) = {}"
            by simp
          
        have [simp]: "TVs v = TVs (Out A')"
          by (simp add: v_def)


        have [simp]:"set (In A') ⊆ set (In A ⊕ (In B ⊖ Out A'))"
          by (simp add: set_diff set_addvars)

        have [simp]:"set (In B ⊖ Out A') ⊆ set (In A ⊕ (In B ⊖ Out A'))"
          by (simp add: set_diff set_addvars)

        have [simp]:"set (In B' ⊖ Out A') ⊆ set (In A ⊕ (In B ⊖ Out A'))"
          by (simp add: set_diff set_addvars)


        have A: "([In A ↝ In A'] oo Trs A') ∥ [In B ⊖ Out A' ↝ In B ⊖ Out A'] = [In A ↝ In A'] ∥ [In B ⊖ Out A' ↝ In B ⊖ Out A'] oo Trs A' ∥ [In B ⊖ Out A' ↝ In B ⊖ Out A']"
          by (simp add: comp_parallel_distrib)

        have [simp]: "[Out A' ⊖ In B ↝ Out A' ⊖ In B] ∥ ([In B ↝ In B'] oo Trs B') = [(Out A' ⊖ In B) ↝ (Out A' ⊖ In B)] ∥ [In B ↝ In B'] oo [Out A' ⊖ In B ↝ Out A' ⊖ In B] ∥ Trs B'"
          by (simp add: comp_parallel_distrib)

        have [simp]: "... = [(Out A' ⊖ In B) @ In B ↝ (Out A' ⊖ In B) @ In B'] oo [Out A' ⊖ In B ↝ Out A' ⊖ In B] ∥ Trs B'"
          by (subst par_switch, simp_all)

        have "[In A ⊕ (In B ⊖ Out A') ↝ In A @ (In B ⊖ Out A')] oo ([In A ↝ In A'] oo Trs A') ∥ [In B ⊖ Out A' ↝ In B ⊖ Out A'] 
              oo ([Out A' @ (In B ⊖ Out A') ↝ (Out A' ⊖ In B) @ In B] oo [(Out A' ⊖ In B) @ In B ↝ (Out A' ⊖ In B) @ In B'])
                =
              [In A ⊕ (In B ⊖ Out A') ↝ In A' ⊕ (In B' ⊖ Out A')] oo
              [In A' ⊕ (In B' ⊖ Out A') ↝ In A' @ (In B' ⊖ Out A')] oo Trs A' ∥ [In B' ⊖ Out A' ↝ In B' ⊖ Out A'] 
              oo [Out A' @ (In B' ⊖ Out A') ↝ (Out A' ⊖ In B) @ In B']"

          apply (subst switch_comp_a, simp_all)
          apply (auto simp add: set_diff) [1]
          apply (subst A, simp add: comp_assoc [THEN sym])
          apply (subst switch_par_comp_Subst, simp_all)
          apply (subst switch_comp, simp_all)
          apply (simp add: set_diff set_addvars)
          apply (rule_tac v = v in par_switch_eq_dist, simp_all)
          apply (subst switch_comp_subst, simp_all)
          apply (auto simp add: set_diff set_addvars)
          apply (subst switch_comp_subst, simp_all)
          apply (auto simp add: set_diff set_addvars)
          by (simp add: Subst_append Subst_cancel_left_type)

         thm par_switch_eq_dist
         from this show "in_equiv (A ;; B) (A' ;; B')"
          apply (simp add: in_equiv_def Comp_def Let_def Var_def diff_inter_left diff_inter_right, simp)
          by (simp add: comp_assoc [THEN sym])
      qed


      lemma "io_diagram A' ⟹ io_diagram B' ⟹ in_equiv A A' ⟹ in_equiv B B' ⟹ in_equiv (CompA A  B) (CompA A' B')"
        apply (simp add: CompA_def, safe)
        apply (rule in_equiv_Comp, simp_all)
        apply (metis in_equiv_def out_def perm_set_eq)
        by (metis in_equiv_def out_def perm_set_eq)

      thm in_equiv_tran

      thm in_equiv_CompA_Parallel_c

      lemma comp_parallel_distrib_a: "TO A = TI B ⟹ (A oo B) ∥ C = (A ∥ (ID (TI C))) oo (B ∥ C)"
        by (subst comp_parallel_distrib, simp_all)

      lemma comp_parallel_distrib_b: "TO A = TI B ⟹ C ∥ (A oo B) = ((ID (TI C)) ∥ A) oo (C ∥ B)"
        by (subst comp_parallel_distrib, simp_all)


      thm switch_comp_subst

      lemma CCC_d: "distinct x ⟹ distinct y' ⟹ set y ⊆ set x ⟹ set z ⊆ set x ⟹ set u ⊆ set y' ⟹ TVs y = TVs y' ⟹ 
        TVs z = ts ⟹ [x ↝ y @ z] oo [y' ↝ u] ∥ (ID ts) = [x ↝ Subst y' y u @ z]"
        proof -
        assume [simp]: "distinct x"
        assume [simp]: "distinct y'"
        assume [simp]: "set y ⊆ set x"
        assume [simp]: "set z ⊆ set x"
        assume [simp]: "set u ⊆ set y'"
        assume [simp]: "TVs y = TVs y'"
        assume [simp]: "TVs z = ts"
        define z' where "z' ≡ newvars y' (TVs z)"

        have [simp]: "set y' ∩ set z' = {}"
          by (simp add: z'_def)
        have [simp]: "set z' ∩ set y' = {}"
          by (simp add: z'_def)
        have [simp]: "set u ∩ set z' = {}"
          using ‹set u ⊆ set y'› ‹set y' ∩ set z' = {}› by blast
        have [simp]: "set z' ∩ set u = {}"
          using ‹set u ⊆ set y'› ‹set y' ∩ set z' = {}› by blast
        have [simp]: "TVs z' = TVs z"
          by (simp add: z'_def)
        have [simp]: "distinct z'"
          by (simp add: z'_def)

        have " [x ↝ y @ z] oo [y' ↝ u] ∥ (ID ts) =  [x ↝ y @ z] oo [y' ↝ u] ∥ [z' ↝ z']"
          by (subst distinct_id, simp_all add: z'_def)
        also have "... =  [x ↝ y @ z] oo [y' @ z' ↝ u @ z']"
          by (subst par_switch, simp_all add: z'_def)
        also have "... = [x ↝ Subst y' y u @ z]"
          apply (subst switch_comp_subst, simp_all add: Subst_append)
          by (simp add: le_supI1)

        finally show ?thesis
          by simp
     qed

      lemma CCC_e: "distinct x ⟹ distinct y' ⟹ set y ⊆ set x ⟹ set z ⊆ set x ⟹ set u ⊆ set y' ⟹ TVs y = TVs y' ⟹ 
        TVs z = ts ⟹ [x ↝ z @ y] oo (ID ts) ∥ [y' ↝ u] = [x ↝ z @ Subst y' y u]"
        proof -
        assume [simp]: "distinct x"
        assume [simp]: "distinct y'"
        assume [simp]: "set y ⊆ set x"
        assume [simp]: "set z ⊆ set x"
        assume [simp]: "set u ⊆ set y'"
        assume [simp]: "TVs y = TVs y'"
        assume [simp]: "TVs z = ts"
        define z' where "z' ≡ newvars y' (TVs z)"

        have [simp]: "set y' ∩ set z' = {}"
          by (simp add: z'_def)
        have [simp]: "set z' ∩ set y' = {}"
          by (simp add: z'_def)
        have [simp]: "set u ∩ set z' = {}"
          using ‹set u ⊆ set y'› ‹set y' ∩ set z' = {}› by blast
        have [simp]: "set z' ∩ set u = {}"
          using ‹set u ⊆ set y'› ‹set y' ∩ set z' = {}› by blast
        have [simp]: "TVs z' = TVs z"
          by (simp add: z'_def)
        have [simp]: "distinct z'"
          by (simp add: z'_def)

        have " [x ↝ z @ y] oo ID ts ∥ [y' ↝ u] =  [x ↝ z @ y] oo [z' ↝ z'] ∥ [y' ↝ u]"
          by (subst distinct_id, simp_all add: z'_def)
        also have "... =  [x ↝ z @ y] oo [z' @ y' ↝ z' @ u]"
          by (subst par_switch, simp_all add: z'_def)
        also have "... = [x ↝ z @ Subst y' y u]"
          apply (subst switch_comp_subst, simp_all add: Subst_append)
          by (simp add: sup.coboundedI2)
        finally show ?thesis
          by simp
     qed


lemma CCC_a: "distinct x ⟹ distinct y ⟹ set y ⊆ set x ⟹ set z ⊆ set x ⟹ set u ⊆ set y ⟹ TVs z = ts 
    ⟹ [x ↝ y @ z] oo [y ↝ u] ∥ (ID ts) = [x ↝ u @ z]"
  by (subst CCC_d, simp_all)
    
        

lemma CCC_b: "distinct x ⟹ distinct z ⟹ set y ⊆ set x ⟹ set z ⊆ set x ⟹ set u ⊆ set z 
    ⟹ TVs y = ts ⟹ [x ↝ y @ z] oo  (ID ts) ∥ [z ↝ u] = [x ↝ y @ u]"
  by (subst CCC_e, simp_all)
    


      thm par_switch_eq_dist

      lemma in_equiv_CompA_Parallel_b: "length (Out A) = 1 ⟹ io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ out A ∈ set (In B) 
        ⟹  out A ∉ set (In C) ⟹ in_equiv (CompA A B ||| CompA A C) (CompA A (B ||| C))"
        proof simp
          assume [simp]: "length (Out A) = Suc 0"
          assume [simp]: "out A ∉ set (In C)"
          assume [simp]: "out A ∈ set (In B)"

          assume [simp]: "io_diagram A"
          assume [simp]: "io_diagram B"
          assume [simp]: "io_diagram C"
        
          have [simp]: "CompA A (B ||| C) = A ;; (B ||| C)"
            apply (subgoal_tac "out A ∈ set (In (B ||| C))")
            by (simp_all add: set_addvars)

         have [simp]: "set (Out A) ∩ set (In C) = {}"
          by (subst Out_out, simp_all)

          have [simp]: "(In C ⊖ Out A) = In C"
            by (simp add: diff_distinct)

          have B: "(In A ⊕ (In B ⊖ Out A) ⊕ In C) = (In A ⊕ (In B ⊕ In C ⊖ Out A))"
            by (simp add: addvars_minus addvars_assoc)

          from B have [simp]: "perm (In A ⊕ (In B ⊖ Out A) ⊕ In C) (In A ⊕ (In B ⊕ In C ⊖ Out A))"
            by simp

          have A: "Out A = [out A]"
            by (subst Out_out, simp_all)

          have [simp]: "(Out A ⊖ In B ⊕ In C) = (Out A ⊖ In B)"
            by (simp add: A set_addvars)

         define v where "v ≡ newvars (In A @ In B @ In C) (TVs (Out A))"

         from this have "set v ∩ set (In A @ In B @ In C) = {}"
          using newvars_old_distinct by blast

         from this have [simp]: "set (In A ⊕ (In B ⊖ Out A) ⊕ In C) ∩ set v = {}"
           by (simp add: set_addvars set_diff, auto)

          from this have [simp]: "set v ∩ set (In A ⊕ (In B ⊖ Out A) ⊕ In C) = {}"
            by blast

         have [simp]: "distinct v"
          by (simp add: v_def)
         have [simp]: "TVs v = TVs (Out A)"
          by (simp add: v_def)


         have A: "[In A ⊕ (In B ⊖ Out A) ⊕ In C ↝ (In A ⊕ (In B ⊖ Out A)) @ In C] oo 
            [In A ⊕ (In B ⊖ Out A) ↝ In A @ (In B ⊖ Out A)] ∥ ID (TVs (In C)) oo Trs A ∥ [In B ⊖ Out A ↝ In B ⊖ Out A] ∥ ID (TVs (In C)) oo
              [Out A @ (In B ⊖ Out A) ↝ (Out A ⊖ In B) @ In B] ∥ ID (TVs (In C)) = 
            [In A ⊕ (In B ⊖ Out A) ⊕ In C ↝ In A ⊕ (In B ⊕ In C ⊖ Out A)] oo [In A ⊕ (In B ⊕ In C ⊖ Out A) ↝ In A @ (In B ⊕ In C ⊖ Out A)] 
              oo Trs A ∥ [In B ⊕ In C ⊖ Out A ↝ In B ⊕ In C ⊖ Out A] oo
              [Out A @ (In B ⊕ In C ⊖ Out A) ↝ (Out A ⊖ In B) @ (In B ⊕ In C)] oo
              ID (TVs (Out A ⊖ In B)) ∥ [In B ⊕ In C ↝ In B @ In C]"
          apply (subst CCC_a, simp_all)
          apply (subst switch_comp, simp_all)
          apply (simp add: distinct_id)
          apply (simp add: par_assoc)
          apply (simp add: comp_assoc)
          apply (subst CCC_b, simp_all add: set_addvars set_diff)
          apply auto [1]
          apply (simp add: comp_assoc [THEN sym])
          apply (rule_tac v = v in par_switch_eq_dist_a, simp_all)
          apply (simp_all add: set_addvars set_diff)
          apply auto [3]
          apply (subst switch_comp_subst, simp_all)
          apply (auto simp add: set_addvars set_diff) [1]
          apply (auto simp add: set_addvars set_diff) [1]
          apply (subst append_assoc [THEN sym])
          apply (subst CCC_d, simp_all)
          apply (simp_all add: set_addvars set_diff)
          apply auto [3]
          apply (simp add: Subst_cancel_left_type)
          by (simp add: Subst_append)

         have "[In A ⊕ (In B ⊖ Out A) ⊕ In C ↝ (In A ⊕ (In B ⊖ Out A)) @ In C] oo
            ([In A ⊕ (In B ⊖ Out A) ↝ In A @ (In B ⊖ Out A)] oo Trs A ∥ [In B ⊖ Out A ↝ In B ⊖ Out A] 
            oo [Out A @ (In B ⊖ Out A) ↝ (Out A ⊖ In B) @ In B] oo [Out A ⊖ In B ↝ Out A ⊖ In B] ∥ Trs B) ∥ Trs C 
            =
            [In A ⊕ (In B ⊖ Out A) ⊕ In C ↝ In A ⊕ (In B ⊕ In C ⊖ Out A)] oo
            ([In A ⊕ (In B ⊕ In C ⊖ Out A) ↝ In A @ (In B ⊕ In C ⊖ Out A)] oo Trs A ∥ [In B ⊕ In C ⊖ Out A ↝ In B ⊕ In C ⊖ Out A] 
            oo [Out A @ (In B ⊕ In C ⊖ Out A) ↝ (Out A ⊖ In B) @ (In B ⊕ In C)] oo
             [Out A ⊖ In B ↝ Out A ⊖ In B] ∥ ([In B ⊕ In C ↝ In B @ In C] oo Trs B ∥ Trs C))"
           apply (simp add: comp_parallel_distrib_a comp_parallel_distrib_b)
           apply (simp add: comp_assoc [THEN sym] par_assoc [THEN sym])
           by (simp add: A) 
          
          from this show "in_equiv ((A ;; B) ||| C) (CompA A (B ||| C))"
            apply (simp)
            by (simp add: in_equiv_def Comp_def Let_def Var_def diff_inter_left diff_inter_right  Parallel_def)
        qed

      lemma in_equiv_CompA_Parallel_d: "length (Out A) = 1 ⟹ io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ out A ∉ set (In B) ⟹ out A ∉ set (In C) ⟹ 
              in_equiv (CompA A B ||| CompA A C) (CompA A (B ||| C))"
        by (simp add: in_equiv_def In_CompA set_addvars BBB_a Parallel_def )

lemma in_equiv_CompA_Parallel: " deterministic (Trs A) ⟹ length (Out A) = 1 ⟹ io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹
          in_equiv ((A ⊳ B) ||| (A ⊳ C)) (A ⊳ (B ||| C))"
        apply (case_tac "out A ∈ set (In B)")
        apply (case_tac "out A ∈ set (In C)")
        apply (rule in_equiv_CompA_Parallel_a, simp)
        apply simp
        apply simp
        apply simp
        apply simp
        apply simp
        apply simp
        apply (rule in_equiv_CompA_Parallel_b, simp)
        apply simp
        apply simp
        apply simp
        apply simp
        apply simp
        apply simp
        apply (case_tac "out A ∈ set (In C)")
        apply (cut_tac in_equiv_CompA_Parallel_c, simp_all)
        by(cut_tac A = A and B = B and C = C in in_equiv_CompA_Parallel_d, simp_all)
 

lemma fb_less_step_compA: "deterministic (Trs A) ⟹ length (Out A) = 1 ⟹ io_diagram A ⟹ Type_OK As 
  ⟹ in_equiv (Parallel_list (fb_less_step A As)) (CompA A (Parallel_list As))"
        apply (induction As)
        apply (simp_all add: fb_less_step_def in_equiv_eq)
        apply (rule_tac B = "(CompA A a ||| CompA A (Parallel_list As))" in in_equiv_tran)
        apply (rule io_diagram_CompA, simp_all)
        apply (rule io_diagram_Parallel)
        apply (simp add: Type_OK_simp)
        apply (rule io_diagram_parallel_list)
        apply (simp add: Type_OK_simp, safe)
        apply (simp add: Out_Parallel BBB_a Type_OK_out)
        apply (simp add: Type_OK_simp image_def)
        apply (rule in_equiv_Parallel)
        apply (rule io_diagram_CompA, simp_all)
        apply (simp add: Type_OK_simp)
        apply (rule io_diagram_CompA, simp_all)
        apply (rule io_diagram_parallel_list, simp)
        apply (rule in_equiv_eq)
        apply (rule io_diagram_CompA, simp_all)
        apply (simp add: Type_OK_simp)
        apply (rule in_equiv_CompA_Parallel, simp_all)
        apply (simp add: Type_OK_simp)
        by (rule io_diagram_parallel_list, simp)
      

(*simp rules*)

          (*move*)
lemma switch_eq_Subst: "distinct x ⟹ distinct u ⟹ set y ⊆ set x ⟹ set v ⊆ set u ⟹ TVs x = TVs u 
    ⟹ Subst x u y = v ⟹ [x ↝ y] = [u ↝ v]"
  using Subst_switch_a by blast

(*move*)
lemma [simp]: "set y ⊆ set y1 ⟹ distinct x1 ⟹ TVs x1 = TVs y1 ⟹ Subst x1 y1 (Subst y1 x1 y) = y"
  by (metis Subst_Subst_inv length_TVs)
    
(*move*)
lemma [simp]: "set z ⊆ set x ⟹ TVs x  = TVs y ⟹ set (Subst x y z) ⊆ set y"
  by (metis Subst_set_incl length_TVs)
    

      thm distinct_Subst

(*move*)
      lemma distinct_Subst_aa: "⋀ y . 
            distinct y ⟹ length x = length y ⟹ a ∉ set y ⟹ set z ∩ (set y - set x) = {} ⟹ a ≠ aa 
      ⟹ a ∉ set z ⟹ aa ∉ set z ⟹ distinct z  ⟹ aa ∈ set x 
      ⟹ subst x y a ≠ subst x y aa"
        apply (induction x, simp_all)
        apply (case_tac y, simp_all, safe)
        apply (metis subst_in_set subst_notin)
        apply (simp add: subst_in_set)
        apply (metis subst_subst_inv subst_notin) 
        by (metis subst_subst_inv subst_notin)

lemma distinct_Subst_ba: "distinct y ⟹ length x = length y ⟹ set z ∩ (set y - set x) = {}  
    ⟹ a ∉ set z ⟹ distinct z  ⟹ a ∉ set y ⟹ subst x y a ∉ set (Subst x y z)"
        apply (induction z, simp_all, safe)
        apply (simp add: distinct_Subst_a)
        by (simp add: distinct_Subst_aa)

lemma distinct_Subst_ca: "distinct y ⟹ length x = length y ⟹ set z ∩ (set y - set x) = {} 
    ⟹ a ∉ set z ⟹ distinct z ⟹ a ∈ set x ⟹ subst x y a ∉ set (Subst x y z)"
        apply (induction z, simp_all, safe)
        apply (metis distinct_Subst_aa)
        by (metis subst_subst_inv)

lemma [simp]: "set z ∩ (set y - set x) = {} ⟹  distinct y ⟹ distinct z ⟹ length x = length y 
  ⟹ distinct (Subst x y z)"
        apply (induction z, simp_all, safe)
        apply (simp add: distinct_Subst_ba)
        by (simp add: distinct_Subst_ca)

(*end simp rules*)



lemma deterministic_Comp: "io_diagram A ⟹ io_diagram B ⟹ deterministic (Trs A) ⟹ deterministic (Trs B) 
  ⟹ deterministic (Trs (A ;; B))"
        apply (simp add: Comp_def Let_def)
        apply (rule deterministic_comp)
        apply (rule deterministic_comp)
        apply (rule deterministic_comp)
        apply (rule deterministic_switch, simp_all)

        apply (rule deterministic_par, simp_all)
        apply (rule deterministic_switch, simp_all)
        apply (rule deterministic_switch, simp_all)

        apply (simp add: set_diff set_addvars Var_def set_inter)
        apply auto [1]
        apply (simp add: set_diff set_addvars Var_def set_inter)
        apply auto [1]

        apply (rule deterministic_par)
        apply (rule deterministic_switch)
        by simp_all

lemma deterministic_CompA: "io_diagram A ⟹ io_diagram B ⟹ deterministic (Trs A) ⟹ deterministic (Trs B) 
  ⟹ deterministic (Trs (A ⊳ B))"
        by (simp add: CompA_def deterministic_Comp)


      lemma parallel_list_empty[simp]: "parallel_list [] = ID []"
        by (simp add: parallel_list_def)

      lemma parallel_list_append: "parallel_list (As @ Bs) = parallel_list As ∥ parallel_list Bs"
        apply (induction As)
        apply (simp_all)
        by (simp add: parallel_list_cons par_assoc)

          (*move*)
lemma par_swap_aux: "distinct p ⟹ distinct (v @ u @ w) ⟹ 

          TI A = TVs x ⟹ TI B = TVs y ⟹ TI C = TVs z ⟹
          TO A = TVs u ⟹ TO B = TVs v ⟹ TO C = TVs w ⟹
          set x ⊆ set p ⟹ set y ⊆ set p ⟹ set z ⊆ set p ⟹ set q ⊆ set (u @ v @ w) ⟹
          [p ↝ x @ y @ z] oo (A ∥ B ∥ C) oo [u @ v @ w ↝ q] = [p ↝ y @ x @ z] oo (B ∥ A ∥ C) oo [v @ u @ w ↝ q]"
        proof -
          define x' where "x' ≡ newvars [] (TI A)"
          define y' where "y' ≡ newvars x' (TI B)"
          define z' where "z' ≡ newvars (x' @ y') (TI C)"
          assume " distinct (v @ u @ w)"
          from this have [simp]: "distinct u" and [simp]: "distinct v" and [simp]: "distinct w"
            and [simp]: "set u ∩ set w = {}" and [simp]: "set v ∩ set u = {}" and [simp]: "set v ∩ set w = {}"
            by simp_all
          assume [simp]: "TI A = TVs x" and [simp]: "TI B = TVs y" and [simp]: "TI C = TVs z"
          assume [simp]: "TO A = TVs u" and [simp]: "TO B = TVs v" and [simp]: "TO C = TVs w"
          assume [simp]: "distinct p"
          assume [simp]: "set x ⊆ set p" and [simp]:"set y ⊆ set p" and [simp]: "set z ⊆ set p" and "set q ⊆ set (u @ v @ w)"

          have A: "distinct (x' @ y' @ z')"
            by (metis newvars_distinct newvars_old_distinct_a append_assoc distinct_append x'_def y'_def z'_def)

          have [simp]: "set x' ∩ set y' = {}"
            by (simp add: y'_def)

          have [simp]: "length x' = length x"
            by (simp add: x'_def newvars_length )

          have [simp]: "length y' = length y"
            by (simp add: y'_def newvars_length )

          have [simp]: "length z' = length z"
            by (simp add: z'_def newvars_length )

          have [simp]: "set z' ∩ set y' = {}"
            using A by auto

          have [simp]: "distinct y'"
            using A by auto

          have [simp]: "distinct x'"
            using A by auto

          have [simp]: "distinct z'"
            using A by auto

          have [simp]: "set x' ∩ set z' = {}"
            using A by auto
            

          have [simp]: "Subst (x' @ y' @ z') (x @ y @ z) y' = y"
            by (simp )

          have [simp]: "Subst (x' @ y' @ z') (x @ y @ z) x' = x"
            apply (subst Subst_not_in)
            apply simp_all
            by (metis A Int_commute distinct_append set_append)

          have [simp]: "Subst (x' @ y' @ z') (x @ y @ z) z' = z"
            apply (simp )
            apply (subst Subst_not_in_a)
            apply simp_all
            using ‹set z' ∩ set y' = {}› by blast
            

          have [simp]: "Subst (x' @ y' @ z') (x @ y @ z) (y' @ x' @ z') = y @ x @ z"
            by (simp add: Subst_append)

          have "[p ↝ x @ y @ z] oo (A ∥ B ∥ C) oo [u @ v @ w ↝ q] = [p ↝ x @ y @ z] oo (([x' @ y' ↝ y' @ x'] oo B ∥ A oo [v @ u ↝ u @ v]) ∥ C) oo [u @ v @ w ↝ q]"
            by (subst switch_par [THEN sym], simp_all add: x'_def y'_def)
          also have "... = [p ↝ x @ y @ z] oo (([x' @ y' ↝ y' @ x'] oo B ∥ A oo [v @ u ↝ u @ v]) ∥ ([z' ↝ z'] oo C oo [w ↝ w])) oo [u @ v @ w ↝ q]"
            by (simp add: z'_def)
          also have "... = [p ↝ x @ y @ z] oo ([x' @ y' ↝ y' @ x'] ∥ [z' ↝ z'] oo B ∥ A ∥ C oo [v @ u ↝ u @ v] ∥ [w ↝ w]) oo [u @ v @ w ↝ q]"
            by (simp add: comp_parallel_distrib x'_def y'_def z'_def)
          also have "... = [p ↝ x @ y @ z] oo ([x' @ y' @ z' ↝ y' @ x' @ z'] oo B ∥ A ∥ C oo [v @ u @ w ↝ u @ v @ w]) oo [u @ v @ w ↝ q]"
            apply (subst par_switch, simp_all)
            apply (metis newvars_old_distinct_a append_assoc distinct_append newvars_distinct x'_def y'_def z'_def)
            by (subst par_switch, simp_all)
          also have "... = ([p ↝ x @ y @ z] oo [x' @ y' @ z' ↝ y' @ x' @ z']) oo B ∥ A ∥ C oo ([v @ u @ w ↝ u @ v @ w] oo [u @ v @ w ↝ q])"
            by (simp add: comp_assoc y'_def x'_def z'_def )
          also have "... = ([p ↝ x @ y @ z] oo [x' @ y' @ z' ↝ y' @ x' @ z']) oo B ∥ A ∥ C oo [v @ u @ w ↝ q]"
            apply (subst switch_comp, simp_all add:)
              apply (metis append.assoc perm_tp perm_union_left)
            using ‹set q ⊆ set (u @ v @ w)› by auto
            
(*
            by (metis ‹distinct (v @ u @ w)› append_assoc perm_tp perm_union_left switch_comp)
*)
          also have "... =  [p ↝ y @ x @ z] oo B ∥ A ∥ C oo [v @ u @ w ↝ q]"
            apply (cut_tac A, subst switch_comp_subst, simp_all)
            apply auto [1]
            by (simp add: x'_def y'_def z'_def)

          finally show "[p ↝ x @ y @ z] oo (A ∥ B ∥ C) oo [u @ v @ w ↝ q] = [p ↝ y @ x @ z] oo (B ∥ A ∥ C) oo [v @ u @ w ↝ q]"
            by simp
        qed

      lemma Type_OK_distinct: "Type_OK As ⟹ distinct As"
        by (induction As, simp_all add: Type_OK_simp, auto)
          
      lemma TI_parallel_list_a: "TI (parallel_list As) = concat (map TI As)"
        by (induction As, simp_all add: parallel_list_cons)


      lemma fb_CompA_aux: "Type_OK As ⟹ A ∈ set As ⟹ out A = a ⟹ a ∉ set (In A) ⟹
        InAs = In (Parallel_list As) ⟹ OutAs = Out (Parallel_list As) ⟹ perm (a # y) InAs ⟹ perm (a # z) OutAs ⟹
        InAs' = In (Parallel_list (As ⊖ [A])) ⟹
        fb ([a # y ↝  concat (map In As)] oo parallel_list (map Trs As) oo [OutAs ↝ a # z]) =
                [y ↝ In A @ (InAs' ⊖ [a])] 
                oo (Trs A ∥ [(InAs' ⊖ [a]) ↝  (InAs' ⊖ [a])])
                oo [a # (InAs' ⊖ [a]) ↝ InAs'] oo Trs (Parallel_list (As ⊖ [A])) 
                oo [OutAs ⊖ [a] ↝ z]" (is "_⟹ _ ⟹ _ ⟹ _ ⟹ _ ⟹ _ ⟹ _  ⟹ _ ⟹ _  ⟹ fb ?Ta = ?Tb")
        proof -
          assume [simp]:"Type_OK As"
          assume [simp]:"A ∈ set As"
          assume X[simp]: "out A = a"
          assume InAs': "InAs' = In (Parallel_list (As ⊖ [A]))"

          assume InAs: "InAs = In (Parallel_list As)"
          assume OutAs: "OutAs = Out (Parallel_list As)"

          assume permInAs: "perm (a # y) InAs"
          assume PermOutAs: "perm (a # z) OutAs"

          assume [simp]: "a ∉ set (In A)"
          
          obtain Cs Ds where A: "As = Cs @ (A # Ds)" by (cut_tac split_list, auto)

          from OutAs have OutAs_simp: "OutAs = concat (map Out As)"
            by (simp add: OutAs Out_Parallel)

          have [simp]: "distinct InAs"
            using InAs ‹Type_OK As› io_diagram_def io_diagram_parallel_list by blast

          have "distinct OutAs"
            using Type_OK_def OutAs_simp ‹Type_OK As› by blast

          have distinctAs: "distinct As"
            by (rule Type_OK_distinct, simp)

          from distinctAs have Ba: "As ⊖ [A] = Cs @ Ds"
            apply (simp add: A union_diff)
            by (simp add: AAA_c)

          have [simp]: "Type_OK (Cs @ Ds)"
            apply (subgoal_tac "Type_OK As")
            apply (unfold Type_OK_simp A) [1]
            by (simp_all)


          have [simp]: "distinct InAs'"
            apply (simp add: InAs' Ba)
            using ‹Type_OK (Cs @ Ds)› io_diagram_def io_diagram_parallel_list by blast


          define C where "C ≡ parallel_list (map Trs Cs)"
          define D where "D ≡ parallel_list (map Trs Ds)"
          define InCs where "InCs ≡ concat (map In Cs)"
          define InDs where "InDs ≡ concat (map In Ds)"
          define OutCs where "OutCs ≡ Out (Parallel_list Cs)"
          define OutDs where "OutDs ≡ Out (Parallel_list Ds)"

          have [simp]: "Out A = [a]"
            using Type_OK_out ‹A ∈ set As› ‹Type_OK As› ‹out A = a› by blast
        
          from A have [simp]: "parallel_list (map Trs As) = C ∥ Trs A ∥ D"
            by (simp add: parallel_list_append parallel_list_cons C_def D_def par_assoc)


          from A have [simp]: "concat (map In As) = InCs @ In A @ InDs"
            by (simp add:  InCs_def InDs_def par_assoc) 

          from A have [simp]: "OutAs = OutCs @ [a] @ OutDs"
            by (simp add:  OutCs_def OutDs_def par_assoc OutAs Out_Parallel)

          have [simp]:"a ∉ set y" and [simp]: "distinct y"
            apply (meson ‹distinct InAs› dist_perm distinct.simps(2) permInAs perm_sym)
            by (meson ‹distinct InAs› dist_perm distinct.simps(2) permInAs perm_sym)
    
          have [simp]: "distinct OutCs"
            by (metis Type_OK_def OutAs_simp ‹OutAs = OutCs @ [a] @ OutDs› ‹Type_OK As› distinct_append)

          have [simp]: " a ∉ set OutDs"
            by (metis OutAs_simp Out_Parallel ‹OutAs = OutCs @ [a] @ OutDs› ‹Type_OK As› append.simps(2) disjoint_iff_not_equal distinct_append list.set_intros(1) io_diagram_def io_diagram_parallel_list)
  
          have [simp]: " distinct OutDs "
            by (metis Type_OK_def OutAs_simp ‹OutAs = OutCs @ [a] @ OutDs› ‹Type_OK As› distinct_append)

          have [simp]: " a ∉ set OutCs "
            by (metis OutAs_simp Out_Parallel ‹OutAs = OutCs @ [a] @ OutDs› ‹Type_OK As› append.simps(2) disjoint_iff_not_equal distinct_append list.set_intros(1) io_diagram_def io_diagram_parallel_list)

          have [simp]: "set OutCs ∩ set OutDs = {}"
            by (metis Type_OK_def OutAs_simp ‹OutAs = OutCs @ [a] @ OutDs› ‹Type_OK As› append_assoc dist_perm distinct_append perm_tp)

          have Type_OK_Cs: "Type_OK Cs"
            apply (subgoal_tac "Type_OK As")
            apply (unfold A Type_OK_simp) [1]
            by simp_all

          from this have [simp]: " TI C = TVs InCs"
            apply (simp add: C_def InCs_def)
            apply (subst TI_parallel_list)
            by (simp add: Type_OK_def, simp)

          have Type_OK_Ds: "Type_OK Ds"
            apply (subgoal_tac "Type_OK As")
            apply (unfold A Type_OK_simp) [1]
            by simp_all

          from this have [simp]: " TI D = TVs InDs"
            apply (simp add: D_def InDs_def)
            apply (subst TI_parallel_list)
            by (simp add: Type_OK_def, simp)


          from Type_OK_Cs have [simp]: " TO C = TVs OutCs"
            apply (simp add: C_def OutCs_def)
            apply (subst TO_parallel_list)
            apply (simp add: Type_OK_def)
            by (simp add: Out_Parallel)

          from Type_OK_Ds have [simp]: "TO D = TVs OutDs"
            apply (simp add: D_def OutDs_def)
            apply (subst TO_parallel_list)
            apply (simp add: Type_OK_def)
            by (simp add: Out_Parallel)

          from ‹Type_OK As› have [simp]: "io_diagram A"
            by (unfold Type_OK_def, simp)

          have B: "?Ta = [a # y ↝ In A @ InCs @ InDs] oo (Trs A ∥ C ∥ D) oo [ [ a ] @ OutCs @ OutDs ↝ a # z]"
            apply (subst par_swap_aux, simp_all)
            apply (cut_tac ‹perm (a#y) InAs›)
            apply (drule perm_set_eq, simp add: InAs In_Parallel)
            apply auto [1]
            apply (cut_tac ‹perm (a#y) InAs›)
            apply (drule perm_set_eq, simp add: InAs InCs_def A In_Parallel)
            apply auto [1]
            apply (cut_tac ‹perm (a#y) InAs›)
            apply (drule perm_set_eq, simp add: InAs InDs_def A In_Parallel)
            apply auto [1]
            apply (cut_tac ‹perm (a # z) OutAs›)
            by (drule perm_set_eq, simp add: OutCs_def OutDs_def A Out_Parallel In_Parallel, auto)

            

          define E where "E ≡ C ∥ D"
          define InE where "InE ≡ InCs @ InDs"
          define OutE where "OutE ≡ OutCs @ OutDs"

          from B have C: "?Ta = [a # y ↝ In A @ InE] oo (Trs A ∥ E) oo [ [a ] @ OutE ↝ a # z]"
            by (unfold E_def InE_def OutE_def par_assoc, simp)

          define y' where "y' ≡ newvars (a#y) (TVs y)"

          have [simp]: "a ∉ set y'"
            by (metis newvars_old_distinct_a IntI distinct.simps(2) distinct_singleton list.set(1) list.set_intros(1) y'_def)

          have [simp]: "distinct y'"
            by (simp add: y'_def)

          have [simp]: "set y ∩ set y' = {}"
            by (metis Int_insert_right_if0 ‹a ∉ set y'› inf.commute list.set(2) newvars_old_distinct y'_def)

          have [simp]: "TVs y' = TVs y"
            by (simp add: y'_def)

          have [simp]: "length y' = length y"
            apply (simp add: y'_def)
            by (simp add: newvars_length)

          have [simp]: "Subst (y @ y') (y @ y) y = y"
            by (simp add: inf_aci(1))

          have [simp]: "Subst (y @ y') (y @ y) y' = y"
            using Subst_cons_aux_a ‹TVs y' = TVs y› ‹distinct y'› ‹distinct y› ‹set y ∩ set y' = {}› TVs_length_eq by blast

          have [simp]: "Subst (a # y @ y') (a # y @ y) (y @ a # y') = y @ a # y"
            by (simp add: Subst_append)

          have Au: "set InAs = set InCs ∪ (set (In A) ∪ set InDs)"
            by (simp add: InAs In_Parallel A InCs_def InDs_def, auto)

          have Av: "set InAs = insert a (set y)"
            using ListProp.perm_set_eq permInAs by fastforce

          have [simp]: "set (In A) ⊆ set y"
            by (metis Au Av Un_left_commute Un_upper1 ‹a ∉ set (In A)› subset_insert)
            

          have [simp]: "set (In A) ∩ set y' = {}"
            using ‹set (In A) ⊆ set y› ‹set y ∩ set y' = {}› by blast

          have [simp]: "Subst (y @ a # y') (y @ a # y) (In A) = In A"
            by (simp add: Subst_cancel_right)

          have [simp]: "set InCs ⊆ insert a (set y)"
            using Au Av by auto

          have [simp]: "Subst (a # y') (a # y) (Subst (a # y) (a # y') InCs) = InCs"
            by (subst Subst_Subst_id, simp_all) 

          from this have [simp]: "Subst y' y (Subst y y' InCs) = InCs"
            by (simp add: Subst_cancel_right_a)

          have [simp]: "set InDs ⊆ insert a (set y)"
            using Au Av by auto

          from this have [simp]: "Subst (a # y') (a # y) (Subst (a # y) (a # y') InDs) = InDs"
            by (subst Subst_Subst_id, simp_all)

          from this have [simp]: "Subst y' y (Subst y y' InDs) = InDs"
            by (simp add: Subst_cancel_right_a)

          have [simp]: "Subst (y @ a # y') (y @ a # y) (In A @ Subst (a # y) (a # y') InE) = In A @ InE"
            by (simp add: InE_def Subst_append Subst_cancel_right)
            
          have [simp]: "a ∉ set OutE"
            by (simp add: OutE_def)

          have [simp]: "distinct OutE"
            by (simp add: OutE_def)

          have [simp]: "set z ⊆ set OutE"
              proof -
                have "insert a (set z) = insert a (set OutE)"
                  using OutE_def PermOutAs perm_set_eq by fastforce
                then show ?thesis
                  by (metis (no_types) Diff_insert_absorb PermOutAs ‹a ∉ set OutE› ‹distinct OutAs› dist_perm distinct.simps(2) equalityE perm_sym)
              qed

          have [simp]: " TI E = TVs (Subst (a # y) (a # y') InE)"
            by (simp add: InE_def E_def Subst_append)

          have [simp]: "TO E = TVs OutE"
            by (simp add: OutE_def E_def)


          define w where "w ≡ InAs' ⊖ [a]"
          have [simp]: "a ∉ set w"
            by (simp add: w_def set_diff)
          have [simp]:"distinct w"
            by (simp add: w_def )

          have [simp]:"TVs (Subst y y' w) = TVs w"
            by simp

          have [simp]: "TVs (Subst (a # w) (a # Subst y y' w) InAs') = TVs InAs'"
            by simp

          have [simp]: "set w ⊆ set y"
            using Av by (simp add: w_def set_diff InAs' In_Parallel InAs, auto)

          have [simp]: "set InAs' ⊆ insert a (set w)"
            using Av by (simp add: w_def set_diff InAs' In_Parallel InAs, auto)

          have [simp]: "set InE ⊆ set InAs'"
            using ‹distinct As›
            by (simp add: InE_def InAs' In_Parallel InCs_def InDs_def A set_diff)

          have [simp]: "set (Subst (a # y) (a # y') InE) ⊆ insert a (set y')"
            apply (cut_tac x = "a # y" and y = "a # y'" and z = InE in Subst_set_incl)
            apply simp_all
            apply (rule_tac y = " set InAs'" in order_trans, simp_all)
            apply (rule_tac y = "insert a (set w)"  in order_trans, simp_all)
            by (rule_tac y = "(set y)"  in order_trans, auto)

          have [simp]: "Subst InAs' (Subst (a # w) (a # Subst y y' w) InAs') InE = Subst (a # y) (a # y') InE"
            proof -
              have "Subst InAs' (Subst (a # w) (a # Subst y y' w) InAs') InE = Subst InAs' (Subst (a # w) (Subst y y' (a # w)) InAs') InE"
                by simp
              also have "... = Subst InAs' (Subst y y' InAs') InE"
                by (subst Subst_Subst, simp_all)
              also have "... =  Subst y y' InE"
                by (subst Subst_Subst, simp_all)
              also have "... = Subst (a # y) (a # y') InE"
                by (simp add: Subst_cancel_right_a)
              finally show ?thesis by simp
            qed

          have [simp]: "TVs (Subst (a # y) (a # y') InE) = TVs InE"
            using E_def InE_def ‹TI E = TVs (Subst (a # y) (a # y') InE)› by auto


          have [simp]: "set (Subst y y' w) ⊆ set y'"
            by (simp add: Subst_set_incl)

          have [simp]: "Subst (y @ y') (y @ y) (In A @ Subst y y' w) = In A @ w"
            by (simp add: Subst_append Subst_cancel_right)
          
          have Aa: "OutCs @ a # OutDs ⊖ [a] = OutE"
            by (simp add: AAA_c OutE_def union_diff)


          from Ba have Ab: "[InAs' ↝ InE] oo E = Trs (Parallel_list (As ⊖ [A]))"
            by (simp add: E_def Trs_Parallel_list parallel_list_append C_def D_def InE_def InCs_def InDs_def InAs')

          have bb: "Subst y' y (Subst y y' InE) = InE"
            by (simp add: InE_def Subst_append)

          have D: "[a # y' ↝ Subst (a # y) (a # y') InE] = [a # y' ↝ a # (Subst y y' w)] oo [a # w ↝ InAs'] oo [InAs' ↝ InE]" (is "_ = ?Tx")
            apply (subst switch_comp_subst, simp_all)
            apply (simp add: subset_insertI2)
            apply (subst switch_comp_subst, simp_all)
            apply (cut_tac ‹ perm (a # y) InAs›)
            apply (drule perm_set_eq)
            apply (simp add:  w_def )
            apply (rule set_SubstI, simp_all)
            apply (subgoal_tac "set (Subst y y' (InAs' ⊖ [a])) ⊆ insert a (set y')", simp)
            apply (auto simp add: InAs' set_diff) [1]
            apply (rule set_SubstI, simp_all)
            by (simp add: InAs InAs' set_diff In_Parallel, auto)

          have aa: "Subst y' y (In A) = In A"
            proof -
              have f1: "set y ∩ set y' = {}"
                by (metis (no_types) insert_disjoint(1) list.set(2) newvars_old_distinct_a y'_def)
              have "set y ∩ set (In A) = set (In A)"
                using ‹set (In A) ⊆ set y› by blast
              then have "set y' ∩ set (In A) = {}"
                using f1 by blast
              then show ?thesis
                by (simp add: TVs_def newvars_length)
            qed


          have cc: "Subst y' y (In A @ Subst y y' InE) = In A @ InE"
            by (simp add: Subst_append aa bb)

          have [simp]: "set (In A) ⊆ insert a (set y ∪ set y')"
            apply (cut_tac ‹ perm (a # y) InAs›)
            apply (drule perm_set_eq)
            by (simp add: InAs In_Parallel, auto)

          have [simp]: "set InE - insert a (set y) ⊆ insert a (set y ∪ set y')"
            apply (cut_tac ‹ perm (a # y) InAs›)
            apply (drule perm_set_eq)
            by (simp add: InE_def InAs A InCs_def InDs_def In_Parallel, auto)

          have [simp]: "set (Subst (a # y) (a # y') InE) ⊆ insert a (set y ∪ set y')"
            by (rule set_SubstI, simp_all, auto)

          have [simp]: "set (In A) ⊆ set y ∪ set y'"
            apply (cut_tac ‹ perm (a # y) InAs›)
            apply (drule perm_set_eq)
            apply (simp add: InAs In_Parallel)
            apply (subst (asm) set_eq_iff, auto)
            by (drule_tac x = x in spec, auto)

          have [simp]: "set (Subst y y' w) ⊆ set y ∪ set y'"
            apply (rule set_SubstI, simp_all)
            apply (simp add: w_def)
            apply (cut_tac ‹ perm (a # y) InAs›)
            apply (drule perm_set_eq)
            by (simp add: set_diff InAs InAs' In_Parallel, auto)


          have "[a # y ↝ In A @ InE] = [a # y ↝ a # y @ y] oo [a # y @ y' ↝ y @ a # y'] oo [y @ a # y' ↝ In A @ (Subst (a # y) (a # y') InE)]" (is "?Tc = ?Td")
            by (simp add: switch_comp_subst cc)
            

          from this have "fb ?Ta = fb (?Td oo (Trs A ∥ E) oo [ [a] @ OutE ↝ a # z])"
            by (subst C, simp)
          also have "... =  fb ([ [a]↝ [a] ] ∥ [y ↝ y @ y] oo [a # y @ y' ↝ y @ a # y'] oo [y @ a # y' ↝ In A @ Subst (a # y) (a # y') InE] oo Trs A ∥ E oo [ [a] ↝ [a] ] ∥ [OutE ↝ z])"
            by (simp add: par_switch)
          also have "... = fb  ([ [a]↝ [a] ] ∥ [y ↝ y @ y] oo ([a # y @ y' ↝ y @ a # y'] oo ([y @ a # y' ↝ In A @ Subst (a # y) (a # y') InE] oo Trs A ∥ E)) oo [ [a] ↝ [a] ] ∥ [OutE ↝ z])"
            by (simp add: comp_assoc )
          also have "... =  [y ↝ y @ y] oo fb  ( ([a # y @ y' ↝ y @ a # y'] oo ([y @ a # y' ↝ In A @ Subst (a # y) (a # y') InE] oo Trs A ∥ E))) oo [OutE ↝ z]"
            apply (subgoal_tac "[ [a] ↝ [a] ] = ID ([TV a])", simp)
            apply (subst fb_comp_fbtype, simp_all)
            apply (simp add: fbtype_def )
            by (simp add: distinct_id)
          also have "... =  [y ↝ y @ y] oo fb  ( ([a # y @ y' ↝ y @ a # y'] oo ([y ↝ In A] ∥ [a # y' ↝ Subst (a # y) (a # y') InE] oo Trs A ∥ E))) oo [OutE ↝ z]"
            by (subst par_switch, simp_all)
          also have "... = [y ↝ y @ y] oo (fb ^^ (length [a]))  ([ [a] @ y @ y' ↝ y @ [a] @ y'] oo ([y ↝ In A] oo Trs A ) ∥ ([ [a] @ y' ↝ Subst (a # y) (a # y') InE] oo E)) oo [OutE ↝ z]"
            by (simp add: comp_parallel_distrib)
          also have "... = [y ↝ y @ y] oo (([y ↝ In A] oo Trs A) ∥ ID (TVs y) oo ([a # y' ↝ Subst (a # y) (a # y') InE] oo E)) oo [OutE ↝ z]"
            apply (subst fb_par_serial [of _ _ _ "[]"])
            by (simp_all)
          also have "... = [y ↝ y @ y] oo (([y ↝ In A] oo Trs A) ∥ [y ↝ y] oo ([a # y' ↝ Subst (a # y) (a # y') InE] oo E)) oo [OutE ↝ z]"
            by (simp add: distinct_id)
          also have "... = [y ↝ y @ y] oo ([y ↝ In A] oo Trs A) ∥ [y ↝ y] oo [a # y' ↝ Subst (a # y) (a # y') InE] oo E oo [OutE ↝ z]"
            by (simp add: comp_assoc )
          also have "... = [y ↝ y @ y] oo ([y ↝ In A] oo Trs A) ∥ [y ↝ y] oo ?Tx oo E oo [OutE ↝ z]"
            by (simp add: D)
          also have "... = [y ↝ y @ y] oo (([y ↝ In A] oo Trs A) ∥ [y ↝ y] oo [a # y' ↝ a # Subst y y' w]) oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: comp_assoc)
          also have "... = [y ↝ y @ y] oo (([y ↝ In A] oo Trs A) ∥ [y' ↝ y'] oo [a # y' ↝ a # Subst y y' w]) oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: distinct_id)
          also have "... = [y ↝ y @ y] oo (([y ↝ In A] oo Trs A) ∥ [y' ↝ y'] oo [ [a] ↝ [a] ] ∥ [y' ↝ Subst y y' w]) oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: par_switch)
          also have "... = [y ↝ y @ y] oo (([y ↝ In A] oo Trs A) ∥ [y' ↝ Subst y y' w]) oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: comp_parallel_distrib)
          also have "... = [y ↝ y @ y] oo ([y ↝ In A] ∥ [y' ↝ Subst y y' w] oo Trs A ∥ [w ↝w]) oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: comp_parallel_distrib)

          also have "... = [y ↝ y @ y] oo ([y @ y' ↝ In A @ Subst y y' w] oo Trs A ∥ [w ↝w]) oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: par_switch)

          also have "... = [y ↝ y @ y] oo [y @ y' ↝ In A @ Subst y y' w] oo Trs A ∥ [w ↝w] oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (simp add: comp_assoc)

          also have "... = [y ↝ In A @ w] oo Trs A ∥ [w ↝w] oo [a # w ↝ InAs'] oo ([InAs' ↝ InE] oo E) oo [OutE ↝ z]"
            by (subst switch_comp_subst, simp_all)
            
            
          also have "... = ?Tb"
            by (simp add: w_def Aa Ab)

          finally show "fb ?Ta = ?Tb"
            by simp
        qed

      lemma [simp]: "perm (a # x) (a # y) = perm x y"
        by (simp add: perm_mset)

(*used in fb_Parallel_list_fb_out_less_step - Feedbackless.thy*)
lemma fb_CompA: "Type_OK As ⟹ A ∈ set As ⟹ out A = a ⟹ a ∉ set (In A) ⟹ C = A ⊳ (Parallel_list (As ⊖ [A])) ⟹
         OutAs = Out (Parallel_list As) ⟹ perm y (In C) ⟹ perm z (Out C) ⟹ B ∈ set As - {A} ⟹ a ∈ set (In B) ⟹
         fb ([a # y ↝ concat (map In As)] oo parallel_list (map Trs As) oo [OutAs ↝ a # z]) = [y ↝ In C] oo Trs C oo [Out C ↝ z]"

         proof -
          assume [simp]: "Type_OK As"
          assume [simp]: "a ∉ set (In A)"
          assume [simp]: "A ∈ set As"
          assume [simp]: "out A = a"
          assume [simp]: "OutAs = Out (Parallel_list As)"
          assume C: "C = CompA A  (Parallel_list (As ⊖ [A]))"
          assume Au: "perm y (In C)"
          assume Av: "perm z (Out C)"
          assume "B ∈ set As - {A}" and "a ∈ set (In B)"

          from this have [simp]: "∃x∈set As - {A}. a ∈ set (In x)"
            by blast

          from this have A[simp]: "a ∈ set (In (Parallel_list (As ⊖ [A])))"
            by (subst In_Parallel, simp add: set_diff)

          thm perm_trans
          have [simp]: "length (Out A) = Suc 0"
            using ‹Type_OK As› ‹A ∈ set As› by (simp add: Type_OK_def)

          have [simp]: "Var A (Parallel_list (As ⊖ [A])) = [a]"
            by (simp add: Var_def In_Parallel Out_out set_diff)



          define InAs' where "InAs' ≡ In (Parallel_list (As ⊖ [A]))"

          have Ax: "io_diagram A"
            using ‹Type_OK As› ‹A ∈ set As› by (unfold Type_OK_def, simp)
            
          from Ax have [simp]: "TI (Trs A) = TVs (In A)"
            by simp

          from Ax have [simp]: "TO (Trs A) = [TV a]"
            by (simp add:  Out_out)

          have "Type_OK (As ⊖ [A])"
            using ‹Type_OK As› by (unfold Type_OK_simp, simp add: set_diff BBB_c)

          from this have Ay: "io_diagram (Parallel_list (As ⊖ [A]))"
            using io_diagram_parallel_list by blast
            

          from this have [simp]: "TI (Trs (Parallel_list (As ⊖ [A]))) = TVs InAs'"
            by (simp add:  In_Parallel Trs_Parallel_list InAs'_def)

          obtain Cs Ds where A: "As = Cs @ (A # Ds)" by (cut_tac split_list, auto)

          have distinctAs: "distinct As"
            by (rule Type_OK_distinct, simp)

          from distinctAs have [simp]: "Cs ⊖ [A] = Cs"
            apply (simp add: A, safe)
            by (simp add: AAA_c)

          from distinctAs have [simp]: "Ds ⊖ [A] = Ds"
            apply (simp add: A, safe)
            by (simp add: AAA_c)

          from distinctAs and ‹Type_OK As› have [simp]: "∀aa∈set Cs. a ∉ set (Out aa)"
            by (simp add: A Type_OK_simp Out_out, auto)

         from distinctAs and ‹Type_OK As› have [simp]: "∀aa∈set Ds. a ∉ set (Out aa)"
            by (simp add: A Type_OK_simp Out_out, auto)

          have [simp]: "Out (Parallel_list (As ⊖ [A])) = (Out (Parallel_list As) ⊖ [a])"
            by (simp add: Out_Parallel A Out_out union_diff AAA_c)

          have io_diagram_C: "io_diagram C"
            apply (simp add: C)
            apply (subst io_diagram_Comp, simp_all)
            using Ax Ay apply simp_all
            by (simp add: Out_out Out_Parallel set_diff)

          have [simp]: "perm (a # z) (Out (Parallel_list As))"
            using Av apply (rule_tac y = "a # Out C" in perm_trans, simp_all)
            apply (subst set_perm, simp_all, safe)
            apply (simp add: C Comp_def Let_def Out_Parallel set_diff)
            using ‹Type_OK As› apply (simp add: A Type_OK_simp Out_out)
            apply auto [1]
            using ‹io_diagram C› io_diagram_def apply blast
            using Type_OK_def  Out_Parallel apply fastforce
            apply (simp_all add: Out_Parallel A Out_out union_diff AAA_c)
            apply (simp_all add: C Comp_def Let_def Out_Parallel set_diff Out_out)
            apply auto [1]
            apply (simp_all add: A)
            apply auto
            apply (metis Un_Diff Un_insert_left ‹(Cs ⊖ [A]) = Cs› ‹(Ds ⊖ [A]) = Ds› insert_Diff insert_iff list.set(1) list.simps(15) set_diff)
            by (metis Un_Diff Un_iff ‹(Ds ⊖ [A]) = Ds› empty_set list.simps(15) set_diff)
            

          from io_diagram_C have dist_C: "distinct (In C)"
            by (simp)
            
          from dist_C and Au have [simp]: "distinct y"
            using dist_perm perm_sym by blast

          have [simp]: "perm y (In A ⊕ (InAs' ⊖ [a]))"
            using Au by (simp add: InAs'_def C Comp_def Let_def)

          have Ay: "io_diagram (Parallel_list As)"
            using ‹Type_OK As› io_diagram_parallel_list by blast

          have [simp]: "perm (a # y) (In (Parallel_list As))"
            using Au apply (rule_tac y = "a # In C" in perm_trans, simp_all)
            apply (subst set_perm)
            using dist_C apply simp_all
            apply (simp add: C In_CompA Out_out Comp_def Let_def  set_diff set_addvars)
            using Ay apply (simp)
            using ‹B ∈ set As - {A}› ‹a ∈ set (In B)› apply (simp add: C In_CompA Out_out Comp_def Let_def In_Parallel set_diff set_addvars, auto)
            by (rule_tac x = A in bexI, simp_all)

          have [simp]: "[y ↝ In A @ (In (Parallel_list (As ⊖ [A])) ⊖ [a])] oo Trs A ∥ [In (Parallel_list (As ⊖ [A])) ⊖ [a] ↝ In (Parallel_list (As ⊖ [A])) ⊖ [a] ] oo
              [a # (In (Parallel_list (As ⊖ [A])) ⊖ [a]) ↝ In (Parallel_list (As ⊖ [A]))] oo
                Trs (Parallel_list (As ⊖ [A])) oo [Out (Parallel_list As) ⊖ [a] ↝ z] = [y ↝ In C] oo Trs C oo [Out C ↝ z]"
               apply (simp add: C CompA_def Let_def Comp_def)
               apply (simp add: InAs'_def [THEN symmetric] Out_out par_empty_left)
               apply (subgoal_tac "[y ↝ In A @ (InAs' ⊖ [a])] oo Trs A ∥ [InAs' ⊖ [a] ↝ InAs' ⊖ [a] ] oo [a # (InAs' ⊖ [a]) ↝ InAs'] oo Trs (Parallel_list (As ⊖ [A])) = 
                  [y ↝ In A ⊕ (InAs' ⊖ [a])] oo ([In A ⊕ (InAs' ⊖ [a]) ↝ In A @ (InAs' ⊖ [a])] oo Trs A ∥ [InAs' ⊖ [a] ↝ InAs' ⊖ [a] ] oo [a # (InAs' ⊖ [a]) ↝ InAs'] oo Trs (Parallel_list (As ⊖ [A])))")
               apply simp_all
               apply (simp add: comp_assoc [THEN sym])
               apply (subgoal_tac " [y ↝ In A @ (InAs' ⊖ [a])] = [y ↝ In A ⊕ (InAs' ⊖ [a])] oo [In A ⊕ (InAs' ⊖ [a]) ↝ In A @ (InAs' ⊖ [a])]")
               apply (simp_all)
               by (subst switch_comp, simp_all)

          show "fb ([a # y ↝ concat (map In As)] oo parallel_list (map Trs As) oo [OutAs ↝ a # z]) = [y ↝ In C] oo Trs C oo [Out C ↝ z]"
            by (subst fb_CompA_aux [of _ A], simp_all, simp_all)
       qed

(*is "_⟹ _ ⟹ _ ⟹ _ ⟹ _ ⟹ _ ⟹ _  ⟹ _ ⟹ _ ⟹ _  ⟹ fb ?Ta = ?Tb"*)

definition "Deterministic As = (∀ A ∈ set As . deterministic (Trs A))"
  
lemma Deterministic_fb_out_less_step: "Type_OK As ⟹ A ∈ set As ⟹ a = out A ⟹ Deterministic As ⟹ Deterministic (fb_out_less_step a As)"
  apply (simp add: fb_out_less_step_def mem_get_comp_out mem_get_other_out fb_less_step_def Deterministic_def set_diff, safe)
  by (simp add: Type_OK_simp deterministic_CompA)
    

      lemma in_equiv_fb_fb_less_step_TO_CHECK: "loop_free As ⟹ Type_OK As ⟹ Deterministic As ⟹
        VarFB (Parallel_list As) = a # L ⟹ Bs = fb_out_less_step a As 
        ⟹  in_equiv (FB (Parallel_list As)) (FB (Parallel_list Bs))"
        apply (frule VarFB_fb_out_less_step, simp_all)
        apply (simp add: in_equiv_def)
        apply (simp add: FB_def Let_def VarFB_def)
        apply (simp add: funpow_swap1)
        apply (cut_tac S = "([L @ (In (Parallel_list (fb_out_less_step a As)) ⊖ L) ↝ In (Parallel_list (fb_out_less_step a As))] oo
                  Trs (Parallel_list (fb_out_less_step a As)) oo
                  [Out (Parallel_list (fb_out_less_step a As)) ↝ L @ (Out (Parallel_list (fb_out_less_step a As)) ⊖ L)])"
              and A = "[In (Parallel_list As) ⊖ a # L ↝ In (Parallel_list (fb_out_less_step a As)) ⊖ L]"
              and tsa = "TVs L"
              and ts = "TVs (Out (Parallel_list (fb_out_less_step a As)) ⊖ L)"
            in fb_indep_left_a)
        apply (rule fbtype_aux, simp_all)
        apply (simp add: VarFB_def)
        apply (rule_tac f = "fb ^^ length L" in arg_cong)
        proof -
          assume [simp]: "loop_free As"
          assume [simp]: "Type_OK As"
          assume [simp]: "Var (Parallel_list As) (Parallel_list As) = a # L"
          assume " Deterministic As"

          from this have aux: "a # L = Var (Parallel_list As) (Parallel_list As)"
            by simp

          have aa: "distinct (Var (Parallel_list As) (Parallel_list As))"
            apply (subgoal_tac "Type_OK As")
            apply (simp add: Type_OK_def Var_def Out_Parallel In_Parallel)
            by simp 

          have bb[simp]: "distinct (a # L)"
            apply (subgoal_tac "distinct (Var (Parallel_list As) (Parallel_list As))")
            apply simp
            by (simp only: aa)

          have [simp]: "distinct L"
            apply (subgoal_tac "distinct (a # L)")
            apply simp
            by (simp only: bb)

          have [simp]: "a ∉ set L"
            apply (subgoal_tac "distinct (a # L)")
            apply simp
            by (simp only: bb)

          have [simp]: "⋀ A . A ∈ set As ⟹ io_diagram A"
            apply (subgoal_tac "Type_OK As")
            apply (simp add: Type_OK_def)
            by simp

          have [simp]: "⋀ A . A ∈ set (fb_out_less_step a As) ⟹ io_diagram A"
            by (metis Type_OK_def VarFB_def Type_OK_fb_out_less_step ‹Type_OK As› ‹loop_free As› aux)
           

          define InAs where "InAs ≡ In (Parallel_list As)"
          define InStAs where "InStAs ≡ In (Parallel_list (fb_out_less_step a As))"

          define OutAs where "OutAs ≡ Out (Parallel_list As)"
          define OutStAs where "OutStAs ≡ Out (Parallel_list (fb_out_less_step a As))"

          have [simp]: "distinct InAs"
            using InAs_def ‹Type_OK As› io_diagram_def io_diagram_parallel_list by blast

          have [simp]: " distinct (InAs ⊖ a # L)"
            apply (subst distinct_diff)
            apply (simp add: InAs_def)
            using ‹Type_OK As› io_diagram_def io_diagram_parallel_list apply blast
            by simp

          have [simp]: "set L ∩ set (InAs ⊖ a # L) = {}"
            apply (simp add: set_diff)
            by blast

          have PermInAs[simp]: "perm (a # L @ (InAs ⊖ a # L)) InAs"
            by (metis Var_def Cons_eq_appendI InAs_def ‹Type_OK As› aux diff_inter_right perm_switch_aux_f io_diagram_def io_diagram_parallel_list)


          obtain A where AAa[simp]: "A ∈ set As" and AAb: "a = out A"
            apply (subgoal_tac "Type_OK As")
            apply (subgoal_tac "VarFB (Parallel_list As) = a # L")
            apply (frule VarFB_cons_out, auto)
            by (simp add: VarFB_def)

          obtain B where AAc: "B ∈ set As" and AAd: "a ∈ set (In B)"
            apply (subgoal_tac "Type_OK As")
            apply (subgoal_tac "VarFB (Parallel_list As) = a # L")
            apply (frule VarFB_cons_out_In)
            apply auto
            by (simp add: VarFB_def)
         
          have [simp]: "B ≠ A"
            using AAa AAb AAd BBBB_f ‹Type_OK As› ‹loop_free As› by blast

          have [simp]: "length (Out A) = 1"
            using AAa Type_OK_simp ‹Type_OK As› by blast

          have [simp]:"out A ∈ set (In B)"
            using AAb AAd by auto

          have [simp]: "distinct InStAs"
            apply (simp add: InStAs_def)
            apply (subgoal_tac "io_diagram (Parallel_list (fb_out_less_step a As))")
            using io_diagram_def apply blast
            by (simp add: AAb Type_OK_fb_out_less_step_aux fb_out_less_step_def mem_get_comp_out mem_get_other_out io_diagram_parallel_list)

          have AAe:"((⋃B∈set As. set (In B))) = {a} ∪  set L ∪ ((⋃x∈set As. set (In x)) - insert (out A) (set L))"
            apply (cut_tac PermInAs)
            apply (subst (asm) distinct_perm_set_eq, simp_all)
            apply (simp add: set_diff)
            apply (simp add: InAs_def set_diff)
            by (simp add: In_Parallel AAb)


          have [simp]: "out A ∉ set (In A)"
            using AAa BBBB_f ‹Type_OK As› ‹loop_free As› by blast

          have [simp]: "perm (L @ (InAs ⊖ a # L)) InStAs"
            apply (rule set_perm, simp_all)
            apply (simp add: InAs_def InStAs_def set_diff)
            apply (simp add: In_Parallel)
            apply (simp add: fb_out_less_step_def mem_get_comp_out AAb mem_get_other_out fb_less_step_def)
            apply (cut_tac AAc)
            apply (cut_tac As = "As ⊖ [A]" and A = A and B = B in union_set_In_CompA)
            apply simp_all
            apply (simp_all add: set_diff)
            apply (subgoal_tac "set (In A) ∪ ((⋃x∈set As - {A}. set (In x)) - {out A}) = (⋃x∈set As . set (In x)) - {out A}")
            apply simp
            apply (subst (2) AAe)
            apply safe [1]
            apply simp_all
            apply (simp add: AAb [THEN sym])
            apply (simp add: AAb)
            apply safe  
            apply simp_all
            apply (rule_tac x = A in bexI, simp_all)
            by auto

          have [simp]: "Var (Parallel_list (fb_out_less_step a As)) (Parallel_list (fb_out_less_step a As)) = L"
            by (metis VarFB_def VarFB_fb_out_less_step ‹Type_OK As› ‹loop_free As› aux)

          have [simp]: "perm (InAs ⊖ a # L) (InStAs ⊖ L)"
            apply (simp add: InAs_def InStAs_def)
            apply (cut_tac As = As and a  = a and L = L in perm_FB_Parallel, simp_all)
            apply (simp add: VarFB_def)
            by (simp add: FB_def Let_def)

          have [simp]:  "set (InStAs ⊖ L) ⊆ set (InAs ⊖ a # L)"
            apply (subgoal_tac "perm (InStAs ⊖ L) (InAs ⊖ a # L)")
            by (simp_all add: perm_sym)


          have A: "ID (TVs L) ∥ [InAs ⊖ a # L ↝ InStAs ⊖ L] oo [L @ (InStAs ⊖ L) ↝ InStAs] = [L @ (InAs ⊖ a # L) ↝ InStAs]"
            apply (simp add: distinct_id [THEN sym])
            apply (subst par_switch, simp_all)
            apply (subst switch_comp, simp_all add: perm_union_right)
            by (simp add: set_diff)

          thm fb_out_less_step_def
          thm fb_less_step_def

          thm InAs_def
          thm InStAs_def

          define C where "C ≡ CompA A (Parallel_list (As ⊖ [A]))"


          have [simp]: "Type_OK (As ⊖ [A])"
            using ‹Type_OK As› 
            by (metis AAa Type_OK_def concat_map_Out_get_other_out distinct_diff inter_subset mem_get_other_out notin_inter)

          have "io_diagram C"
            apply (simp add: C_def)
            apply (rule io_diagram_CompA)
            using ‹Type_OK As›
            apply simp_all
            apply (rule io_diagram_parallel_list)
            by simp

          have [simp]: "out A ∈ set (In (Parallel_list (As ⊖ [A])))"
            apply (simp add: In_Parallel set_diff)
            using AAc ‹B ≠ A› ‹out A ∈ set (In B)› by blast

          have [simp]: "perm (L @ (InAs ⊖ out A # L)) (In C)"
            apply (rule set_perm, simp_all)
            using AAb ‹distinct (InAs ⊖ a # L)› ‹distinct L› ‹set L ∩ set (InAs ⊖ a # L) = {}› distinct_append apply blast
            using ‹io_diagram C› apply (simp)
            apply (simp add: C_def CompA_def Comp_def Let_def Var_def)
            apply (simp add: C_def set_diff InAs_def In_Parallel Comp_def CompA_def set_addvars set_inter)
            apply (subgoal_tac "set (a # L) = set (Var (Parallel_list As) (Parallel_list As))")
            apply (simp add: Var_def Out_Parallel In_Parallel set_inter)
            apply auto [1]
            apply (simp_all add: Out_out)
            using AAb ‹a ∉ set L› by blast
            

          have "set (a # L) = set (Var (Parallel_list As) (Parallel_list As))"
            by simp

          from this have [simp]: "perm (L @ (OutAs ⊖ out A # L)) (Out C)"
            apply (simp add: Var_def Out_Parallel In_Parallel set_inter)
            apply (rule set_perm, simp, safe)
            using OutAs_def ‹Type_OK As› distinct_diff io_diagram_def io_diagram_parallel_list apply blast
            apply (simp add: set_diff)
            using ‹io_diagram C› io_diagram_def apply auto[1]
            apply (simp_all add: C_def Comp_def Let_def)
            apply (simp_all add: Out_Parallel Var_def set_diff set_inter OutAs_def Out_out)
            apply (safe, simp_all)
            apply (unfold set_eq_iff)
            apply (simp)
               apply (drule_tac x = x in spec, simp_all, safe)
                
            apply (rule_tac x = xa in bexI, auto)
            apply (simp_all add: Out_out)
            using AAb ‹a ∉ set L› apply auto
            apply (rule_tac x = xa in bexI, auto)
            apply (simp_all add: Out_out)
            using ‹Type_OK As›
            apply (unfold Type_OK_simp, safe)
            apply (simp add: Out_out)
            by (metis AAa ‹Type_OK As› mem_get_comp_out)

          have Ub: "fb ([a # L @ (InAs ⊖ a # L) ↝ concat (map In As)] oo parallel_list (map Trs As) oo [OutAs ↝ a # L @ (OutAs ⊖ a # L)]) 
            = [L @ (InAs ⊖ a # L) ↝ In C] oo Trs C oo [Out C ↝ L @ (OutAs ⊖ a # L)]"
            apply (rule fb_CompA [of As A a C OutAs "L @ (InAs ⊖ a # L)" " L @ (OutAs ⊖ a # L)" B])
            apply (simp_all add: AAb)
            apply (simp add: C_def)
            apply (simp add: OutAs_def)
            using ‹B ∈ set As› by simp

          thm fb_less_step_compA [of A "(As ⊖ [A])"]

          thm fb_CompA_aux [of As A a InAs OutAs "L @ (InAs ⊖ a # L)" " L @ (OutAs ⊖ a # L)" InStAs]
          thm fb_less_step_compA

          thm fb_out_less_step_def

          have Ua: "fb_out_less_step a As = fb_less_step A (As ⊖ [A])"
            apply (simp add: fb_out_less_step_def)
            by (simp add: AAb mem_get_comp_out mem_get_other_out)

          define D where "D ≡ Parallel_list (fb_less_step A (As ⊖ [A]))"

          have Va: "L @ (OutAs ⊖ a # L) = L @ (OutStAs ⊖ L)"
             using ‹Type_OK As› ‹A ∈ set As› ‹a = out A› apply (simp only: OutAs_def OutStAs_def Out_Parallel map_Out_fb_out_less_step mem_get_other_out)
             apply simp
             by (metis AAa ‹Type_OK As› concat_map_Out_get_other_out diff_cons mem_get_other_out)


          have [simp]: "Out A ⊗ In (Parallel_list (As ⊖ [A])) = [a]"
            using  ‹a = out A› by (simp add: Out_out)


          thm map_Out_fb_out_less_step
          have Vb: "Out C = OutStAs"
             using ‹Type_OK As› ‹A ∈ set As› ‹a = out A› apply (simp only: C_def OutStAs_def Out_Parallel )
             apply (subst map_Out_fb_out_less_step, simp_all)
             by (simp add: CompA_def Comp_def Let_def Var_def Out_out mem_get_other_out Out_Parallel)
          

          have Vc: "InStAs = In D"
            by (simp add: InStAs_def D_def Ua)

          have [simp]: "TI (Trs C) = TVs (In C)"
            by (metis AAa AAb C_def Type_OK_def Type_OK_fb_out_less_step_aux Ua ‹Type_OK As› inter_subset map_Out_fb_out_less_step mem_get_other_out notin_inter io_diagram_CompA io_diagram_def io_diagram_parallel_list)
            

          have [simp]: "perm (L @ (InAs ⊖ a # L)) (In D)"
            using Vc ‹perm (L @ (InAs ⊖ a # L)) InStAs› by blast

          have [simp]: "distinct (In (Parallel_list As) ⊖ a # L)"
            using InAs_def ‹distinct (InAs ⊖ a # L)› by auto

          have [simp]: "perm (a # L @ (In (Parallel_list As) ⊖ a # L)) (In (Parallel_list As))"
            using InAs_def PermInAs by blast

          have [simp]: "deterministic (Trs A)"
            using ‹Deterministic As› ‹A ∈ set As› by (simp add: Deterministic_def)


          have "in_equiv D C"
            apply (unfold C_def D_def)
            by (rule fb_less_step_compA [of A "As ⊖ [A]"], simp_all)
            
          from this have Ud: "[L @ (InAs ⊖ a # L) ↝ In C] oo Trs C oo [Out C ↝ L @ (OutAs ⊖ a # L)] 
                  = [L @ (InAs ⊖ a # L) ↝ InStAs] oo Trs D oo [OutStAs ↝ L @ (OutStAs ⊖ L)]"
            apply (unfold in_equiv_def, simp add: Va Vb Vc, safe)
            apply (subst comp_assoc [THEN sym], simp_all)
            apply (subgoal_tac "[L @ (InAs ⊖ a # L) ↝ In C] = [L @ (InAs ⊖ a # L) ↝ In D] oo [In D ↝ In C]", simp_all)
            by (subst switch_comp, simp_all)

          have Uc: "fb ([a # L @ (InAs ⊖ a # L) ↝  concat (map In As)] oo parallel_list (map Trs As) oo [OutAs ↝ a # L @ (OutAs ⊖ a # L)]) 
            = fb ([a # L @ (InAs ⊖ a # L) ↝ InAs] oo Trs (Parallel_list As) oo [OutAs ↝ a # L @ (OutAs ⊖ a # L)])"
            apply (simp add: Trs_Parallel_list)
            apply (simp add:  comp_assoc [THEN sym] InAs_def TI_parallel_list)
            apply (subgoal_tac "[a # L @ (In (Parallel_list As) ⊖ a # L) ↝ concat (map In As)] = [a # L @ (In (Parallel_list As) ⊖ a # L) ↝ In (Parallel_list As)] oo [In (Parallel_list As) ↝ concat (map In As)]")
            apply simp_all
            apply (subst switch_comp, simp_all, safe)
            apply (simp_all add: set_diff)
            by (simp add: In_Parallel, auto)


          from Ub Uc Ud have "fb ([a # L @ (InAs ⊖ a # L) ↝ InAs] oo Trs (Parallel_list As) oo [OutAs ↝ a # L @ (OutAs ⊖ a # L)]) =
                [L @ (InAs ⊖ a # L) ↝ InStAs] oo Trs (Parallel_list (fb_less_step A (As ⊖ [A]))) oo [OutStAs ↝ L @ (OutStAs ⊖ L)]"
            by (simp add: D_def)
          

          from Ua and this have B: "fb ([a # L @ (InAs ⊖ a # L) ↝ InAs] oo Trs (Parallel_list As) oo [OutAs ↝ a # L @ (OutAs ⊖ a # L)]) =
                [L @ (InAs ⊖ a # L) ↝ InStAs] oo Trs (Parallel_list (fb_out_less_step a As)) oo [OutStAs ↝ L @ (OutStAs ⊖ L)]"
           by simp

          have [simp]: "Type_OK (fb_out_less_step a As)"
            by (metis VarFB_def Type_OK_fb_out_less_step ‹Type_OK As› ‹Var (Parallel_list As) (Parallel_list As) = a # L› ‹loop_free As›)

          have "fb ([a # L @ (InAs ⊖ a # L) ↝ InAs] oo Trs (Parallel_list As) oo [OutAs ↝ a # L @ (OutAs ⊖ a # L)]) =
               ID (TVs L) ∥ [InAs ⊖ a # L ↝ InStAs ⊖ L] oo 
               ([L @ (InStAs ⊖ L) ↝ InStAs] oo Trs (Parallel_list (fb_out_less_step a As)) oo [OutStAs ↝ L @ (OutStAs ⊖ L)])"
            apply (subst B)
            apply (subst A [THEN sym])
            apply (subst comp_assoc, simp_all)
            apply (simp add: TI_Parallel_list InStAs_def In_Parallel)
            apply (subst comp_assoc, simp_all)
            apply (subst TI_comp, simp_all)
            apply (simp add: TI_Parallel_list InStAs_def In_Parallel)
            apply (subst TO_comp, simp_all)
            apply (simp add: TI_Parallel_list InStAs_def In_Parallel)
            by (simp add: TO_Parallel_list OutStAs_def Out_Parallel)

          from this show "fb ([a # L @ (In (Parallel_list As) ⊖ a # L) ↝ In (Parallel_list As)] oo Trs (Parallel_list As) 
                            oo [Out (Parallel_list As) ↝ a # L @ (Out (Parallel_list As) ⊖ a # L)]) =
                         ID (TVs L) ∥ [In (Parallel_list As) ⊖ a # L ↝ In (Parallel_list (fb_out_less_step a As)) ⊖ L] oo
                            ([L @ (In (Parallel_list (fb_out_less_step a As)) ⊖ L) ↝ In (Parallel_list (fb_out_less_step a As))] oo Trs (Parallel_list (fb_out_less_step a As)) oo
                            [Out (Parallel_list (fb_out_less_step a As)) ↝ L @ (Out (Parallel_list (fb_out_less_step a As)) ⊖ L)])"
            by (simp add: InAs_def OutAs_def InStAs_def OutStAs_def)
       qed
      

      lemma io_diagram_FB_Parallel_list: "Type_OK As ⟹ io_diagram (FB (Parallel_list As))"
        by (simp_all add:  Type_ok_FB io_diagram_parallel_list)


      lemma [simp]: "io_diagram A ⟹ ⦇In = In A, Out = Out A, Trs =  Trs A⦈ = A"
        by auto

      thm loop_free_def

      lemma io_rel_compA: "length (Out A) = 1 ⟹ io_rel (CompA A B) ⊆ io_rel B ∪ (io_rel B O io_rel A)"
        apply (simp add: CompA_def, safe)
        apply (simp add: Comp_def Let_def io_rel_def  set_addvars set_diff Var_def set_inter relcomp_def OO_def out_def)
        by (case_tac "Out A", simp_all)

      theorem loop_free_fb_out_less_step: "loop_free As ⟹ Type_OK As ⟹ A ∈ set As ⟹ out A = a ⟹ loop_free (fb_out_less_step a As)"
        proof (rule ccontr)
          assume D: "loop_free As"
          assume "Type_OK As"
          assume [simp]: "A ∈ set As"
          assume "out A = a"

          have [simp]: "fb_out_less_step a As = map (CompA A) (As ⊖ [A])"
            apply (simp add: fb_out_less_step_def fb_less_step_def)
            by (metis ‹A ∈ set As› ‹Type_OK As› ‹out A = a› mem_get_comp_out mem_get_other_out)

          assume "¬ loop_free (fb_out_less_step a As)"

          from this obtain x where C: "(x,x) ∈ (IO_Rel (map (CompA A) (As ⊖ [A])))+"
            by (simp add: loop_free_def, blast)

          have A: "⋀ B . B ∈ set As ⟹ io_rel B ⊆ (IO_Rel As)+"
            apply (rule_tac y = "IO_Rel As" in order_trans)
            apply (simp add: io_rel_def IO_Rel_def)
            by auto

          have B: "⋀ A B . A ∈ set As ⟹ B ∈ set As ⟹ io_rel B O io_rel A ⊆ (IO_Rel As)+"
            apply (rule_tac y = "(IO_Rel As)+ O (IO_Rel As)+" in order_trans)
            apply (simp add: A relcomp_mono)
            apply safe
            by (rule_tac y = y in trancl_trans, simp_all)

          have "⋀ B . B ∈ set As ⟹ io_rel (CompA A B) ⊆ (IO_Rel As)+"
            apply (rule_tac y = "io_rel B ∪ (io_rel B O io_rel A)" in order_trans)
            apply (rule io_rel_compA)
            using Type_OK_def ‹A ∈ set As› ‹Type_OK As› apply blast
            apply safe
            apply (cut_tac A) apply auto

            apply (subgoal_tac " io_rel B O io_rel A ⊆ (IO_Rel As)+")
            apply auto [1]
            by (rule B, simp_all)

          from this have "IO_Rel (map (CompA A) (As ⊖ [A])) ⊆ (IO_Rel As)+"
            apply (subst IO_Rel_def, safe)
            by (simp add: io_rel_def image_def set_diff, safe, auto)

          from this have "(IO_Rel (map (CompA A) (As ⊖ [A])))+ ⊆ (IO_Rel As)+"
            apply (rule trancl_Int_subset, safe)
            apply (rule_tac y = y in  trancl_trans )
            apply blast
            by blast

          from this and C and D show "False"
            by (simp add: loop_free_def, auto)
       qed

      
      theorem in_equiv_FB_fb_less_delete: "⋀ As . Deterministic As ⟹ loop_free As ⟹ Type_OK As ⟹ VarFB (Parallel_list As) = L ⟹  
                  in_equiv (FB (Parallel_list As)) (Parallel_list (fb_less L As)) ∧ io_diagram (Parallel_list (fb_less L As))"
        apply (induction L)
        apply (frule io_diagram_parallel_list)
        apply (simp add: FB_def VarFB_def diff_emptyset)
        apply (rule in_equiv_eq, simp, simp)
        proof -
          fix a:: 'var
          fix L :: "'var list"
          fix As:: "('var, 'a) Dgr list"
          assume A: "(⋀As ::('var, 'a) Dgr list. Deterministic As ⟹ loop_free As ⟹ Type_OK As ⟹ VarFB (Parallel_list As) = L ⟹ in_equiv (FB (Parallel_list As)) (Parallel_list (fb_less L As)) ∧ io_diagram (Parallel_list (fb_less L As)))"
          assume [simp]: "loop_free As"
          assume [simp]: "Type_OK As"
          assume [simp]: "VarFB (Parallel_list As) = a # L"
          assume [simp]: "Deterministic As"
  
          define Bs where "Bs ≡ fb_out_less_step a As"
  
          from this have Bs_simp: "Bs = fb_out_less_step a As"
            by simp

          obtain A where AAa[simp]: "A ∈ set As" and AAb: "a = out A"
            apply (subgoal_tac "Type_OK As")
            apply (subgoal_tac "VarFB (Parallel_list As) = a # L")
            by (frule VarFB_cons_out, auto)
  
          from AAb have [simp]: "Deterministic Bs"
            apply (simp only: Bs_simp)
            by (rule_tac A = A in  Deterministic_fb_out_less_step, simp_all)
  
          have [simp]: "loop_free Bs"
            apply (simp only: Bs_simp)
            by (rule_tac A = A and As = As in loop_free_fb_out_less_step, simp_all add: AAb)
  
          have [simp]: "Type_OK Bs"
            using Bs_def Type_OK_fb_out_less_step ‹VarFB (Parallel_list As) = a # L› ‹Type_OK As› ‹loop_free As› by blast
  
          from A have Aa: "(⋀As ::('var, 'a) Dgr list. Deterministic As ⟹ loop_free As ⟹ Type_OK As ⟹ VarFB (Parallel_list As) = L ⟹ in_equiv (FB (Parallel_list As)) (Parallel_list (fb_less L As)))"
            by simp
  
          from A have Ab: "(⋀As ::('var, 'a) Dgr list. Deterministic As ⟹ loop_free As ⟹ Type_OK As ⟹ VarFB (Parallel_list As) = L ⟹  io_diagram (Parallel_list (fb_less L As)))"
            by simp
  
  
          have [simp]: "VarFB (Parallel_list Bs) = L"
            apply (simp add: Bs_def)
            by (rule VarFB_fb_out_less_step, simp_all)
  
          have [simp]: "in_equiv (FB (Parallel_list Bs)) (Parallel_list (fb_less L Bs))"
            by (rule Aa, simp_all)
              
          have [simp]: "io_diagram (Parallel_list (fb_less L Bs))"
            by (rule Ab, simp_all)

          have [simp]: "in_equiv (FB (Parallel_list As)) (FB (Parallel_list Bs))"
            apply (rule in_equiv_fb_fb_less_step_TO_CHECK, simp_all)
            by (simp add: Bs_def)
 
          show "in_equiv (FB (Parallel_list As)) (Parallel_list (fb_less (a # L) As))  ∧ io_diagram (Parallel_list (fb_less (a # L) As))"
            apply (simp add: Bs_simp [THEN sym])
            apply (rule_tac B = "FB (Parallel_list Bs)" in in_equiv_tran)
            by (simp_all add: io_diagram_FB_Parallel_list)
        qed
                  
lemmas [simp] = diff_emptyset

  
lemma [simp]: "⋀ x . distinct x ⟹ distinct y ⟹ perm (((y ⊗ x) @ (x ⊖ y ⊗ x))) x"
  by (simp add: diff_inter_right perm_switch_aux_f)
  
lemma [simp]: "io_diagram X ⟹ perm (VarFB X @ (In X ⊖ VarFB X)) (In X)"
  by (simp add: VarFB_def Var_def)

  
lemma Type_OK_diff[simp]: "Type_OK As ⟹ Type_OK (As ⊖ Bs)"
  apply (simp add: Type_OK_def, safe)
    apply (simp_all add: set_diff)
  by (metis BBB_c One_nat_def Type_OK_def Type_OK_simp inter_subset notin_inter)
    

lemma internal_fb_out_less_step: 
  assumes [simp]: "loop_free As"
    assumes [simp]: "Type_OK As"
    and [simp]: "a ∈ internal As"
  shows "internal (fb_out_less_step a As) = internal As - {a}"
  apply (subst internal_VarFB)
   apply (rule Type_OK_fb_out_less_step_new, simp_all)
  apply (subst internal_VarFB, simp_all)
  by (subst VarFB_fb_out_less_step_gen, simp_all add: set_diff)
    
end

context BaseOperationFeedbacklessVars
begin

    
lemma [simp]: "Type_OK As ⟹ a ∈ internal As ⟹ out (get_comp_out a As) = a"
  apply (subgoal_tac "a ∈ set (Out (get_comp_out a As))")
   apply (subst (asm) Out_out)
    apply (simp add: Type_OK_def)
  by simp_all


    
lemma internal_Type_OK_simp: "Type_OK As ⟹ internal As = {a . (∃ A ∈ set As . out A = a ∧ (∃ B ∈ set As. a ∈ set (In B)))}"
  apply (subgoal_tac "⋀ A . A ∈ set As ⟹ Out A = [out A]")
   apply (simp add: internal_def)
   apply auto
  using Type_OK_out by blast
    
thm Type_OK_def

lemma  Type_OK_fb_less: "⋀ As . Type_OK As ⟹ loop_free As ⟹ distinct x ⟹ set x ⊆ internal As ⟹ Type_OK (fb_less x As)"
  proof (induction x)
    case Nil
    then show ?case by simp
  next
    case (Cons a x)
      
    have [simp]: "Type_OK As"
      by (simp add: Cons)
     
    have [simp]: "a ∈ internal As"
      using Cons(5) by simp
    from this obtain A where [simp]: "A ∈ set As" and [simp]: "out A = a"
      by (subst (asm) internal_Type_OK_simp,simp_all, blast)

    show ?case
      apply simp
      apply (rule Cons(1))
         apply (rule_tac As = As in Type_OK_fb_out_less_step_new, simp_all)
        apply (rule_tac A = A in loop_free_fb_out_less_step)
           apply (simp_all add: Cons)
      using ‹distinct (a#x)› apply simp
      apply (subst internal_fb_out_less_step, simp_all add: Cons)
      using Cons.prems(3) Cons.prems(4) by auto
  qed

  
    
lemma fb_Parallel_list_fb_out_less_step: 
  assumes [simp]: "Type_OK As"
    and "Deterministic As"
    and "loop_free As"
    and internal: "a ∈ internal As"
    and X: "X = Parallel_list As"
    and Y: "Y = (Parallel_list (fb_out_less_step a As))"
    and [simp]: "perm y (In Y)"
    and [simp]: "perm z (Out Y)"
  shows "fb ([a # y ↝ In X] oo Trs X oo [Out X ↝ a # z]) = [y ↝ In Y] oo Trs Y oo [Out Y ↝ z]" and "perm (a # In Y) (In X)"
proof -
  have [simp]: "⋀ A . A ∈ set As ⟹ io_diagram A"
    using Type_OK_def assms(1) by blast

  define A where "A = get_comp_out a As"
  from internal have [simp]: "A ∈ set As" and [simp]: "out A = a"
    by (simp_all add: A_def)
      
  have [simp]: "get_other_out a As = As ⊖[A]"
    using ‹A ∈ set As› ‹out A = a› assms(1) mem_get_other_out by blast
      
  have [simp]: "length (Out A) = 1"
    using ‹Type_OK As› Type_OK_def ‹A ∈ set As› by blast
  
  have [simp]: "a ∉ set (In A)"
    using Type_OK_loop_free_elem ‹A ∈ set As› ‹out A = a› assms(1) assms(3) by blast

  have "io_diagram Y"
    using Type_OK_fb_out_less_step_new Y assms(1) assms(3) internal io_diagram_parallel_list by blast
        
  from this have dist_a_Y: "distinct (a # In Y)"
    apply simp
    by (simp add: Y In_Parallel fb_out_less_step_def A_def [THEN sym] fb_less_step_def In_CompA set_addvars set_diff Out_out)
      
  have "io_diagram X"
    by (simp add: X io_diagram_parallel_list)
      
  from this have [simp]: "distinct (In X)"
    by (simp)
            
  from internal obtain B where [simp]: "B ∈ set As" and [simp]: "a ∈ set (In B)"
    by (simp add: internal_def, auto)
      
  have [simp]: "B ≠ A"
    using ‹a ∈ set (In B)› ‹a ∉ set (In A)› by blast
      
      
  show "perm (a # In Y) (In X)"
    apply (rule set_perm)
    using dist_a_Y apply simp
      apply simp
    apply (simp add: X Y)
    apply (simp add: In_Parallel )
    apply (simp add: fb_out_less_step_def A_def [THEN sym])
    apply (simp add: fb_less_step_def In_CompA, safe)
      apply (auto simp add: set_diff set_addvars)
    using internal apply (subst (asm) internal_Type_OK_simp, simp_all)
     apply (case_tac "a ∈ set (In xa)")
      apply (auto simp add: set_diff set_addvars)
      apply (case_tac "xa = A")
    apply (drule_tac x = B in bspec, simp_all add: set_diff set_addvars)
    apply (drule_tac x = xa in bspec, simp_all add: set_diff set_addvars)
    by (case_tac "a ∈ set (In xa)", simp_all add: set_diff set_addvars Out_out)
    

  from this have [simp]: "perm (a # y) (In X)"
    apply (rule_tac y = "a # In Y" in perm_trans)
     by simp_all
      
  from this have dist_a_y: "distinct (a # y)"
    using io_diagram_distinct(1) X assms(1) dist_perm perm_sym io_diagram_parallel_list by blast
      
    
  define Z where "Z =  A ⊳ (Parallel_list (As ⊖ [A]))"
      
  thm fb_less_step_compA
    
  have equiv_Y_Z: "in_equiv Y Z"
    apply (simp add: Y Z_def fb_out_less_step_def A_def[THEN sym])
    apply (rule fb_less_step_compA, simp_all)
    using Deterministic_def ‹A ∈ set As› assms(2) by blast

  from this have [simp]: "perm (In Y) (In Z)" and Y_Z: "Trs Y = [In Y ↝ In Z] oo Trs Z" and [simp]: "Out Z = Out Y"
    by (simp_all add: in_equiv_def)
      
  have [simp]: "perm y (In Z)"
    by (rule_tac y = "In Y" in perm_trans, simp_all)
      
  have [simp]: "io_diagram Z"
    by (metis Type_OK_def io_diagram_CompA Type_OK_diff Z_def ‹A ∈ set As› assms(1) io_diagram_parallel_list)

  have "fb ([a # y ↝ In X] oo Trs X oo [Out X ↝ a # z]) 
        = fb ([a # y ↝ In (Parallel_list As)] oo ([In X ↝ concat (map In As)] oo parallel_list (map Trs As)) oo [Out X ↝ a # z])"
    by (simp add: X Trs_Parallel_list)
  also have "... = fb (([a # y ↝ In X] oo [In X ↝ concat (map In As)]) oo parallel_list (map Trs As) oo [Out X ↝ a # z])"
    by (simp_all add: X comp_assoc TI_parallel_list TO_parallel_list Out_Parallel)
  also have "... = fb ([a # y ↝ concat (map In As)] oo parallel_list (map Trs As) oo [Out X ↝ a # z])"
    apply (subgoal_tac "[a # y ↝ In X] oo [In X ↝ concat (map In As)] = [a # y ↝ concat (map In As)]")
     apply simp
    apply (subst switch_comp)
    using dist_a_y apply blast
      apply simp
    by (simp add: X In_Parallel, auto)
  also have "... =  [y ↝ In Z] oo Trs Z oo [Out Z ↝ z]"
    thm fb_CompA
    apply (subst fb_CompA [of As A a Z _ _ _ B], simp_all add: X)
    by (simp add: Z_def)
  
  also have "... = [y ↝ In Y] oo Trs Y oo [Out Y ↝ z]"
    apply simp
    apply (rule_tac f = "λ X . X oo [Out Y ↝ z]" in arg_cong)
    apply (simp add: Y_Z)
    apply (simp add: comp_assoc[THEN sym])
    apply (subst switch_comp, simp_all)
    using dist_a_y by auto
      
  finally show "fb ([a # y ↝ In X] oo Trs X oo [Out X ↝ a # z]) = [y ↝ In Y] oo Trs Y oo [Out Y ↝ z]"
    by simp
qed


lemma internal_In_Parallel_list: "a ∈ internal As ⟹ a ∈ set (In (Parallel_list As))"
  by (simp add: In_Parallel internal_def)

lemma internal_Out_Parallel_list: "a ∈ internal As ⟹ a ∈ set (Out (Parallel_list As))"
  by (simp add: Out_Parallel internal_def)
  
    
theorem fb_power_internal_fb_less: "⋀ As X Y . Deterministic As ⟹ loop_free As ⟹ Type_OK As ⟹ set L ⊆ internal As 
  ⟹ distinct L ⟹
   X = (Parallel_list As) ⟹ Y = Parallel_list (fb_less L As) ⟹
   (fb ^^ length (L)) ([L @ (In X ⊖ L) ↝ In X] oo Trs X oo [Out X ↝ L @ (Out X ⊖ L)]) = [In X ⊖ L ↝ In Y] oo Trs Y
  ∧ perm (In X ⊖ L) (In Y)"
  proof (induction L)
    case Nil
    have [simp]: "io_diagram X"
      apply (simp add: Nil)
      by (simp add: Nil.prems(3) io_diagram_parallel_list)
    have [simp]: "Y = X"
      by (simp add: Nil)
    then show ?case
      by (simp_all add: InFB_def)
  next
    case (Cons a L)
    have type_As[simp]: "Type_OK As"
      by (simp add: Cons)
    have [simp]: "io_diagram X"
      apply (simp add: Cons)
      by (simp add: io_diagram_parallel_list)

    from type_As have [simp]: "⋀ A . A ∈ set As ⟹ io_diagram A"
      by (unfold Type_OK_def, simp)
        
   have internal_a[simp]: "a ∈ internal As"
     using Cons.prems(4) by auto

   have internal_a[simp]: "set L ⊆ internal As"
     using Cons.prems(4) by auto
        

   have "a ∈ set (In X)"
     apply (simp add: Cons)
     apply (rule internal_In_Parallel_list)
     by (simp add: Cons)
       
        
    have "set L ⊆ set (In X)"
     apply (simp add: Cons, safe)
      apply (rule internal_In_Parallel_list)
      using internal_a by blast
        
    have "distinct (In X)"
      by simp

    have perm_a[simp]: "perm (a # L @ (In X ⊖ (a # L))) (In X)"
      apply (subgoal_tac "perm ((a # L) @ (In X ⊖ (a # L))) (In X)")
       apply simp
      by (metis Cons.prems(5) ‹a ∈ set (In X)› ‹distinct (In X)› ‹set L ⊆ set (In X)› append_Nil diff.simps(2) diff_subset perm_switch)
        
    from this have Ba: "distinct (a # L @ (In X ⊖ (a # L)))"
      using io_diagram_distinct(1) BaseOperationFeedbacklessVars_axioms ‹io_diagram X› dist_perm perm_sym by blast

    from perm_a and this have [simp]: "perm (L @ (In X ⊖ (a # L))) (In X ⊖ [a])"
    proof -
      have f1: "distinct (In X ⊖ [a])"
        by (meson Ba dist_perm distinct_diff perm_a)
      have "{a} = set [a]"
        by (metis list.set(1) list.set(2))
      then show ?thesis
        using f1 by (metis (no_types) Ba Diff_insert_absorb distinct.simps(2) list.set(2) perm_a perm_set_eq set_diff set_perm)
    qed
      
   thm fb_Parallel_list_fb_out_less_step
     
   define Z where "Z = Parallel_list (fb_out_less_step a As)"
            
   have [simp]: "io_diagram Y"
     apply (unfold Cons)
     apply (rule io_diagram_parallel_list)
       apply (rule Type_OK_fb_less, simp_all)
     using Cons.prems(2) apply auto[1]
     using Ba by auto[1]
       
       
   have [simp]: "distinct (In X ⊖ (a # L))"
     by (simp)

   have "io_diagram Z"
     apply (simp add: Z_def)
     apply (subst io_diagram_parallel_list, simp_all)
     by (metis Cons.prems(4) Type_OK_fb_out_less_step_new ‹Type_OK As› insert_subset list.simps(15))
       
       
   from this have dist_InZ[simp]: "distinct (In Z)"
     by simp
       

   have dist_L_InFB_X: "distinct (L @ (In X ⊖ (a # L)))"
     apply (simp add: Cons, safe)
     using Ba apply auto[1]
     using Cons.prems(6) ‹distinct (In X ⊖ a # L)› apply blast
     by (simp add: InFB_def set_diff)
       
   have [simp]: "perm (a # In Z) (In X)"
     apply (rule_tac fb_Parallel_list_fb_out_less_step [of As _ _ _ "In Z" "Out Z"])
     by (simp_all add: Cons Z_def)
       
   have "distinct (In X)"
     using Ba dist_perm perm_a by blast
       
   have [simp]: " perm (L @ (In X ⊖ (a # L))) (In Z)"
     apply (rule_tac y = " (In X ⊖ [a])" in perm_trans)
      apply (simp add: InFB_def)
       apply (subst perm_sym, simp_all)
     using ‹distinct (In X)›
     by (rule distinct_perm_cons, simp)
       
   thm concat_map_Out_get_other_out
   thm map_Out_fb_out_less_step
   thm map_Out_fb_less_step
     
   have "distinct (Out X)"
     using ‹io_diagram X› io_diagram_def by blast
       
   have "set (a # L) ⊆ set (Out X)"
     apply (unfold Cons)
     apply (safe)
     apply (rule internal_Out_Parallel_list)
     using Cons.prems(4) by blast
     
   have "perm (a # L @ (Out X ⊖ (a # L))) (Out X)"
     by (metis Cons.prems(5) ‹distinct (Out X)› ‹set (a # L) ⊆ set (Out X)› append_Cons append_Nil diff_subset perm_switch)
       
   from this have "perm (L @ (Out X ⊖ (a # L))) (Out X ⊖ [a])"
     by (simp add: distinct_perm_cons)
       
   have [simp]: "distinct (Out Z)"
     by (simp add: ‹io_diagram Z›)
       
  define A where "A = get_comp_out a As"
     
  from internal_a have [simp]: "A ∈ set As" and [simp]: "out A = a"
    by (simp_all add: A_def)
      
  have get_other_out[simp]: "get_other_out a As = As ⊖[A]"
    using ‹A ∈ set As› ‹Type_OK As› ‹out A = a› mem_get_other_out by blast
 
  have [simp]: "perm (L @ (Out X ⊖ (a # L))) (Out Z)"
     apply (rule_tac y = "Out X ⊖ [a]" in perm_trans)
     using ‹perm (L @ (Out X ⊖ (a # L))) (Out X ⊖ [a])› apply blast
     apply (rule set_perm)
       apply simp_all
     apply (simp add: Cons Z_def Out_Parallel del:set_map)
     apply (subst map_Out_fb_out_less_step[of A], simp_all add: set_diff)
     apply safe
       apply simp_all
       apply (case_tac "a = x", simp)
       apply (drule_tac x = aa in bspec, simp_all)
       using Cons(4)
         apply (metis Type_OK_out ‹out A = a› empty_iff list.set(1) set_ConsD)
        apply blast
         using Cons(4)
         by (simp add: A_def Type_OK_out mem_get_comp_out)

       have set_Out_Z: "set (Out Z) = set L ∪ set (Out X ⊖ (a # L))"
         
         by (metis ListProp.perm_set_eq ‹L @ (Out X ⊖ a # L) <~~> Out Z› set_append)
      
       have set_In_Z: "set (In Z) = set L ∪ set (In X ⊖ (a # L))"
         by (metis ListProp.perm_set_eq ‹L @ (In X ⊖ a # L) <~~> In Z› set_append)
      
  have [simp]: "distinct L"
    using dist_L_InFB_X by auto

  have [simp]: "set L ⊆ internal (fb_out_less_step a As)"
    by (metis Cons.prems(2) Cons.prems(3) Cons.prems(4) Cons.prems(5) Diff_empty distinct.simps(2) insert_subset internal_fb_out_less_step list.simps(15) subset_Diff_insert)

  have [simp]: "perm (In X ⊖ (a # L)) (In Z ⊖ L)"
    apply (subgoal_tac "perm (L @ (In X ⊖ (a # L))) (L @ (In Z ⊖ L))")
     apply (metis add_left_cancel perm_mset union_code)
    apply (rule_tac y = "In Z" in perm_trans)
     apply simp
    by (metis ‹distinct L› append_Nil diff_subset dist_InZ perm_switch perm_sym set_In_Z sup_ge1)
      

  from internal_a have [simp]: "Deterministic (fb_out_less_step a As)"
    using Cons.prems(1) Deterministic_fb_out_less_step ‹A ∈ set As› ‹out A = a› type_As by blast
    
  from internal_a have [simp]: "loop_free (fb_out_less_step a As)"
    using Cons.prems(2) ‹A ∈ set As› ‹out A = a› loop_free_fb_out_less_step type_As by blast

  from internal_a have [simp]: "Type_OK (fb_out_less_step a As)"
    by (simp add: A_def Type_OK_fb_out_less_step_aux fb_out_less_step_def)
      
      
   have [simp]: "perm (In X ⊖ (a # L)) (In Y)"
    apply (rule_tac y = "In Z ⊖ L" in perm_trans, simp_all)
     apply (subst Cons(1) [of "fb_out_less_step a As" "Z" "Y"], simp_all)
      apply (simp add: Z_def)
     by (simp add: Cons)
       
   have [simp]: "set (In Y) ⊆ set (In Z ⊖ L)"
     by (metis ‹perm (In X ⊖ (a # L)) (In Y)› ‹perm (In X ⊖ (a # L)) (In Z ⊖ L)› order_refl perm_set_eq)

   have A: "(fb  ([a # L @ (In X ⊖ (a # L)) ↝ In X] oo Trs X oo [Out X ↝ a # L @ (Out X ⊖ (a # L))])) = [L @ (In X ⊖ (a # L)) ↝ In Z] oo Trs Z oo [Out Z ↝ L @ (Out X ⊖ (a # L))]"
     apply (subst fb_Parallel_list_fb_out_less_step [of As], simp_all add: Cons)
       apply (simp add: Z_def)
     by (simp_all add: Cons(7) [THEN sym])
     
   have OutFB_X_Z: "Out X ⊖ (a # L) = Out Z ⊖ L"
     apply (subst perm_diff_eq[of _ "a # L"])
      apply (simp add: Cons(5))
     apply (subst (2)  perm_diff_eq[of _ "L"])
      apply simp
     apply (simp add: Cons Z_def Out_Parallel)
     apply (subst map_Out_fb_out_less_step [of A], simp_all add: concat_map_Out_get_other_out del: get_other_out)
     by (meson diff_cons)
       
   have "(fb ^^ length (a # L)) ([(a # L) @ (In X ⊖ a # L) ↝ In X] oo Trs X oo [Out X ↝ (a # L) @ (Out X ⊖ a # L)]) 
      = (fb ^^ (length L)) (fb  ([a # L @ (In X ⊖ a # L) ↝ In X] oo Trs X oo [Out X ↝ a # L @ (Out X ⊖ (a # L))]))"
     by (simp add: funpow_swap1)
   also have "... = (fb ^^ length L) ([L @ (In X ⊖ a # L) ↝ In Z] oo Trs Z oo [Out Z ↝ L @ (Out X ⊖ (a # L))])"
     by (simp add: A)
   also have "... = (fb ^^ length L) (([L @ (In X ⊖ a # L) ↝ L @ (In Z ⊖ L)] oo [L @ (In Z ⊖ L) ↝ In Z]) oo Trs Z oo [Out Z ↝ L @ (Out X ⊖ (a # L))])"
     apply (subgoal_tac "[L @ (In X ⊖ a # L) ↝ L @ (In Z ⊖ L)] oo [L @ (In Z ⊖ L) ↝ In Z] = [L @ (In X ⊖ a # L) ↝ In Z]")
      apply simp
     by (subst switch_comp, simp_all add: set_diff, auto)

   also have "... = (fb ^^ length L) ([L @ (In X ⊖ a # L) ↝ L @ (In Z ⊖ L)] oo ([L @ (In Z ⊖ L) ↝ In Z] oo Trs Z oo [Out Z ↝ L @ (Out X ⊖ a # L)]))"
     using ‹io_diagram Z› by (simp add: comp_assoc)
   
   also have "... = (fb ^^ length L) ([L ↝ L] ∥ [(In X ⊖ a # L) ↝ In Z ⊖ L] oo ([L @ (In Z ⊖ L) ↝ In Z] oo Trs Z oo [Out Z ↝ L @ (Out X ⊖ a # L)]))"
     using dist_L_InFB_X par_switch by auto
     
       also have "... = [(In X ⊖ a # L) ↝ In Z ⊖ L] oo (fb ^^ length (TVs L)) ([L @ (In Z ⊖ L) ↝ In Z] oo Trs Z oo [Out Z ↝ L @ (Out X ⊖ a # L)])"
     apply (subst fb_indep_left [THEN sym])
     using ‹io_diagram Z› apply (simp add: fbtype_def )
     apply (subgoal_tac "[L ↝ L] = ID (TVs L)")
       apply (simp)
     using ‹distinct L› distinct_id by blast
  
   also have "... = [(In X ⊖ a # L) ↝ (In Z ⊖ L)] oo (fb ^^ length L) ([L @ (In Z ⊖ L) ↝ In Z] oo Trs Z oo [Out Z ↝ L @ (Out Z ⊖ L)])"
     by (simp add: OutFB_X_Z)
       
   also have "... = [(In X ⊖ a # L) ↝ In Z ⊖ L] oo ([In Z ⊖ L ↝ In Y] oo Trs Y)"
     apply (subst Cons(1) [of "fb_out_less_step a As" "Z" "Y"])
           apply (simp_all add: Cons)
     by (simp add: Z_def)
   also have "... = [(In X ⊖ a # L) ↝ In Z ⊖ L] oo [In Z ⊖ L ↝ In Y] oo Trs Y"
     by (simp add:  comp_assoc)
   also have "... = [(In X ⊖ a # L) ↝ In Y] oo Trs Y"
     by (subst switch_comp, simp_all)

    finally show ?case by simp
  qed
    
  thm fb_power_internal_fb_less

    
theorem FB_fb_less:
  assumes [simp]: "Deterministic As"
    and [simp]: "loop_free As" 
    and [simp]: "Type_OK As"
    and [simp]: "perm (VarFB X) L"
    and X: "X = (Parallel_list As)"
    and Y: "Y = Parallel_list (fb_less L As)"
  shows "(fb ^^ length (L)) ([L @ InFB X ↝ In X] oo Trs X oo [Out X ↝ L @ OutFB X]) = [InFB X ↝ In Y] oo Trs Y"
    and B: "perm (InFB X) (In Y)"
proof -
  have [simp]: "set L ⊆ internal As"
    using assms(4) X internal_VarFB by auto
      
  have "distinct (Out (Parallel_list As))"
    by (metis Out_Parallel Type_OK_def assms(3))
      
  from this have "distinct (VarFB X)"
    by (simp add: VarFB_def X)
      
  from this have [simp]: "distinct L"
    using assms(4) dist_perm by blast

  have [simp]: "(fb ^^ length L) ([L @ (In X ⊖ L) ↝ In X] oo Trs X oo [Out X ↝ L @ (Out X ⊖ L)]) = [In X ⊖ L ↝ In Y] oo Trs Y"
    and [simp]: "perm (In X ⊖ L) (In Y)"
     apply (subst fb_power_internal_fb_less, simp_all add: X Y)
    by (subst fb_power_internal_fb_less, simp_all)
      
  have [simp]: "InFB X = In X ⊖ L"
    by (simp add: InFB_def perm_diff_eq)
      
  have [simp]: "OutFB X = Out X ⊖ L"
    by (simp add: OutFB_def perm_diff_eq)
      
  show "(fb ^^ length (L)) ([L @ InFB X ↝ In X] oo Trs X oo [Out X ↝ L @ OutFB X]) = [InFB X ↝ In Y] oo Trs Y"
    by simp
  show "perm (InFB X) (In Y)"
    by simp
qed

    
definition "fb_perm_eq A = (∀ x. perm x (VarFB A) ⟶ 
  (fb ^^ length (VarFB A)) ([VarFB A @ InFB A ↝ In A] oo Trs A oo [Out A ↝ VarFB A @ OutFB A]) = 
  (fb ^^ length (VarFB A)) ([x @ InFB A ↝ In A] oo Trs A oo [Out A ↝ x @ OutFB A]))"
  
lemma fb_perm_eq_simp: "fb_perm_eq A = (∀ x. perm x (VarFB A) ⟶ 
  Trs (FB A) = (fb ^^ length (VarFB A)) ([x @ InFB A ↝ In A] oo Trs A oo [Out A ↝ x @ OutFB A]))"
  by (simp add: fb_perm_eq_def FB_def Let_def VarFB_def InFB_def OutFB_def)
  
lemma in_equiv_in_out_equiv: "io_diagram B ⟹ in_equiv A B ⟹ in_out_equiv A B"
  by (simp add: in_equiv_def in_out_equiv_def)

    
lemma [simp]: "distinct (concat (map f As)) ⟹ distinct (concat (map f (As ⊖ [A])))"
  apply (induction As, auto)
  by (simp add: set_diff, auto)
    

lemma set_op_list_addvars: "set (op_list [] (⊕) x) = (⋃ a ∈ set x . set a)"
  by (induction x, auto simp add: set_addvars)
    
          
end

context BaseOperationFeedbacklessVars

begin
  
(*
lemma [simp]: "out B ∉ set (In A) ⟹ CompA B A = A"
  by (simp add: CompA_def)

lemma [simp]: "out B ∈ set (In A) ⟹ CompA B A = B ;; A"
  by (simp add: CompA_def)
*)

lemma [simp]: "set (Out A) ⊆ set (In B) ⟹ Out ((A ;; B)) = Out B"
  by (simp add: Comp_def out_def Let_def Var_def diff_eq subsetset_inter)
    
    
lemma [simp]: "set (Out A) ⊆ set (In B) ⟹ out ((A ;; B)) = out B"
  by (simp add: Comp_def out_def Let_def Var_def diff_eq subsetset_inter)
    

lemma switch_par_comp3: 
  assumes [simp]: "distinct x" and
    [simp]: "distinct y"
    and [simp]: "distinct z" 
    and [simp]: "distinct u"
    and [simp]: "set y ⊆ set x"
    and [simp]: "set z ⊆ set x"
    and [simp]: "set u ⊆ set x"
    and [simp]: "set y' ⊆ set y"
    and [simp]: "set z' ⊆ set z" 
    and [simp]: "set u' ⊆ set u"
    shows "[x ↝ y @ z @ u] oo [y ↝ y'] ∥ [z ↝ z'] ∥ [u ↝ u'] = [x ↝ y' @ z' @ u']"
      proof -
        have [simp]: "[x ↝ y @ z @ u] = [x ↝ y @ x] oo [y ↝ y] ∥ [x ↝ z @ u]"
          by (subst switch_par_comp_Subst, simp_all add:)
        show "[x ↝ y @ z @ u] oo [y ↝ y'] ∥ [z ↝ z'] ∥ [u ↝ u'] = [x ↝ y' @ z' @ u']"
          apply simp
          apply (subst comp_assoc, simp_all add: par_assoc)
          apply (subst comp_parallel_distrib, simp_all)
          apply (simp add: switch_par_comp)
          apply (subst switch_par_comp, simp_all)
          using assms(10) assms(6) assms(7) assms(9) by blast
      qed
        
lemma switch_par_comp_Subst3: 
  assumes [simp]: "distinct x" and [simp]: "distinct y'" and [simp]: "distinct z'" and [simp]: "distinct t'"
    and [simp]: "set y ⊆ set x" and [simp]: "set z ⊆ set x" and [simp]: "set t ⊆ set x"
    and [simp]: "set u ⊆ set y'" and [simp]: "set v ⊆ set z'" and [simp]: "set w ⊆ set t'"
    and [simp]: "TVs y = TVs y'" and [simp]: "TVs z = TVs z'" and [simp]: "TVs t = TVs t'"
    
  shows "[x ↝ y @ z @ t] oo [y' ↝ u] ∥ [z' ↝ v] ∥ [t' ↝ w] = [x ↝ Subst y' y u @ Subst z' z v @ Subst t' t w]"
proof -
  have [simp]: "[x ↝ y @ z @ t] = [x ↝ y @ x] oo [y' ↝ y'] ∥ [x ↝ z @ t]"
    by (subst switch_par_comp_Subst, simp_all add:)
    show "[x ↝ y @ z @ t] oo [y' ↝ u] ∥ [z' ↝ v] ∥ [t' ↝ w] = [x ↝ Subst y' y u @ Subst z' z v @ Subst t' t w]"     
      apply simp
      apply (subst comp_assoc, simp_all add: par_assoc)
      apply (subst comp_parallel_distrib, simp_all)
      apply (simp add: switch_par_comp_Subst)
      apply (subst switch_par_comp_Subst, simp_all, safe)
      apply (metis Subst_set_incl assms(12) assms(6) assms(9) contra_subsetD length_TVs)
      by (metis Subst_set_incl assms(10) assms(13) assms(7) length_TVs subsetCE)
  qed
    
    
lemma Comp_assoc_single: "length (Out A) = 1 ⟹ length (Out B) = 1 ⟹ out A ≠ out B ⟹ io_diagram A 
  ⟹ io_diagram B ⟹ io_diagram C ⟹ out B ∉ set (In A) ⟹
    deterministic (Trs A) ⟹
    out A ∈ set (In B) ⟹ out A ∈ set (In C) ⟹ out B ∈ set (In C) ⟹ (A ;; (B ;; C)) = (A ;; B ;; (A ;; C))"
  
  apply (simp add: Comp_def Let_def Var_def , safe)
    (* using [[simp_trace=true]] *)
      apply (simp add: Out_out, safe)
             apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame diff_sym addvars_assoc [THEN sym])
      
            apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame diff_sym addvars_assoc [THEN sym])
      
           apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame diff_sym addvars_assoc [THEN sym] )
      
          apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame diff_sym addvars_assoc [THEN sym])
 
      apply (simp add: Out_out, safe)
      apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame diff_sym AAA_c addvars_assoc [THEN sym] )
      
   apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame  AAA_c diff_eq diff_addvars )
    
  apply (simp add: set_addvars set_diff set_inter addvars_minus addvars_addsame diff_sym diff_inter_left diff_inter_right addvars_assoc [THEN sym])
  apply (simp add: Out_out par_empty_left par_empty_right set_diff set_inter set_addvars)
  apply (simp add:  Out_out comp_assoc [THEN sym])
   apply (subgoal_tac " [In A ⊕ (In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ In A @ ((In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]))] oo
    Trs A ∥ [(In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ (In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B])] oo
    [out A # ((In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B])) ↝ In B ⊕ (In C ⊖ [out B])] oo
    [In B ⊕ (In C ⊖ [out B]) ↝ In B @ (In C ⊖ [out B])] oo
    Trs B ∥ [In C ⊖ [out B] ↝ In C ⊖ [out B] ] oo
    [out B # (In C ⊖ [out B]) ↝ In C]
    =
    [In A ⊕ (In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ (In A ⊕ (In B ⊖ [out A])) @ ((In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B]))] oo
    ([In A ⊕ (In B ⊖ [out A]) ↝ In A @ (In B ⊖ [out A])] oo Trs A ∥ [In B ⊖ [out A] ↝ In B ⊖ [out A] ] oo [out A # (In B ⊖ [out A]) ↝ In B] oo Trs B) ∥
    [(In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ (In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B])] oo
    [out B # ((In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B])) ↝ In A ⊕ (In C ⊖ [out A])] oo
    [In A ⊕ (In C ⊖ [out A]) ↝ In A @ (In C ⊖ [out A])] oo
    Trs A ∥ [In C ⊖ [out A] ↝ In C ⊖ [out A] ] oo
    [out A # (In C ⊖ [out A]) ↝ In C] ")
   apply simp
proof -
  assume [simp]: "length (Out A) = Suc 0"
  assume [simp]: "length (Out B) = Suc 0"
  assume Diff[simp]: "out A ≠ out B"
  assume [simp]: "io_diagram A"
  assume [simp]: "io_diagram B"
  assume [simp]: "io_diagram C"
  assume [simp]: "out A ∈ set (In B)"
  assume [simp]: "out A ∈ set (In C)"
  assume [simp]: "out B ∈ set (In C)"
  assume "out B ∉ set (In A)"
  assume det: "deterministic (Trs A)"
    
    have [simp]: " perm (In C ⊖ [out A] ⊖ [out B] ⊖ (In B ⊖ [out A])) (In C ⊖ [out B] ⊖ In B)"
              proof -
          have "In C ⊖ [out B] ⊖ [] ⊖ out A # (In B ⊖ [out A]) = In C ⊖ [out B] ⊖ [] ⊖ In B"
            by (meson BaseOperationFeedbacklessVars.diff_eq_set_right BaseOperationFeedbacklessVars.io_diagram_distinct(1) BaseOperationFeedbacklessVars_axioms ‹out A ∈ set (In B)› ‹io_diagram B› perm_dist_mem perm_set_eq)
          then show "perm (In C ⊖ [out A] ⊖ [out B] ⊖ (In B ⊖ [out A])) (In C ⊖ [out B] ⊖ In B)"
            by (metis (no_types) diff_cons diff_sym perm_refl)
        qed
          
        define a where "a = out A"
        define b where "b = out B"
        define c where "c = out C"
        define x where "x = In A"
        define y where "y = In B"
        define z where "z = In C"
        have [simp]: "distinct x"
          by (simp add: x_def)
        have [simp]: "distinct y"
          by (simp add: y_def)
        have [simp]: "distinct z"
          by (simp add: z_def)
            
        have [simp]: "b ∈ set z"
          by (simp add: b_def z_def)
        have [simp]: "b ≠ a"
          using Diff a_def b_def by (simp del: Diff)
            
        have X: "b ∉ set x"
          by (simp add: ‹out B ∉ set (In A)› b_def x_def)

        have A_det: "Trs A oo [ [a] ↝ [a,a] ] = [x↝ x @ x] oo Trs A ∥ Trs A"
          using det apply (subst deterministicE, simp_all add: x_def a_def)
          by (simp add: Out_out)
            
        define x' where "x' = newvars (x @ y @ z) (TVs x)"
          
        have [simp]: "set x' ∩ set x = {}" and [simp]: "set x' ∩ set y = {}" and [simp]: "set x' ∩ set z = {}" and [simp]: "distinct x'"
            and [simp]: "TVs x' = TVs x"
          using x'_def and newvars_old_distinct [of "(x @ y @ z)" "(TVs x)"] by auto

   have A: "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] 
        oo Trs A ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])] 
        oo [a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ y ⊕ (z ⊖ [b])] 
        oo [y ⊕ (z ⊖ [b]) ↝ y @ (z ⊖ [b])] 
        oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] 
        oo [b # (z ⊖ [b]) ↝ z] = 
    [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] 
        oo Trs A ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])] 
        oo ([a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ y ⊕ (z ⊖ [b])] 
        oo [y ⊕ (z ⊖ [b]) ↝ y @ (z ⊖ [b])]) 
        oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] 
        oo [b # (z ⊖ [b]) ↝ z]"
    by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
      
      have B: " ... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] 
        oo Trs A ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])] 
        oo [a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])]
        oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] 
        oo [b # (z ⊖ [b]) ↝ z]"
        apply (subgoal_tac "([a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ y ⊕ (z ⊖ [b])] 
        oo [y ⊕ (z ⊖ [b]) ↝ y @ (z ⊖ [b])]) = [a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])]")
            apply simp
         apply (simp add:  a_def b_def c_def x_def y_def z_def)
        apply (subst switch_comp, simp_all)
         apply (simp add: set_diff set_addvars set_inter)
        apply (simp add: addvars_def)
        apply (subgoal_tac "perm ((out A # (In B ⊖ [out A])) @ (In C ⊖ [out A] ⊖ [out B] ⊖ (In B ⊖ [out A]))) (In B @ (In C ⊖ [out B] ⊖ In B))")
          apply simp
          apply (rule perm_append)
         apply (simp add: perm_dist_mem)
        by simp
 
          
      have C: "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊕ (y ⊖ [a])) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))] 
         oo ([x ⊕ (y ⊖ [a]) ↝ x @ (y ⊖ [a])] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])]
         oo [b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x ⊕ (z ⊖ [a])] oo [x ⊕ (z ⊖ [a]) ↝ x @ (z ⊖ [a])] 
         oo Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] 
         oo [a # (z ⊖ [a]) ↝ z]
      =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊕ (y ⊖ [a])) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))] 
         oo ([x ⊕ (y ⊖ [a]) ↝ x @ (y ⊖ [a])] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])]
         oo ([b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x ⊕ (z ⊖ [a])] oo [x ⊕ (z ⊖ [a]) ↝ x @ (z ⊖ [a])])
         oo Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] 
         oo [a # (z ⊖ [a]) ↝ z]"
        by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
          
     have D: "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊕ (y ⊖ [a])) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))] 
         oo ([x ⊕ (y ⊖ [a]) ↝ x @ (y ⊖ [a])] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])]
         oo [b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])]
         oo Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] 
         oo [a # (z ⊖ [a]) ↝ z]"
       apply (subgoal_tac "([b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x ⊕ (z ⊖ [a])] oo [x ⊕ (z ⊖ [a]) ↝ x @ (z ⊖ [a])]) = [b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])]")
        apply simp
       apply (subst switch_comp, simp_all, safe)
        apply (simp add: set_diff set_addvars )
       apply (rule perm_cons)
         apply (simp add: set_addvars set_diff)
        apply (simp add: addvars_diff)
       by (simp add: addvars_minus)
         
     have E: "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊕ (y ⊖ [a])) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))] oo
    [x ⊕ (y ⊖ [a]) ↝ x @ (y ⊖ [a])] ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] 
    oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] oo
     [a # (y ⊖ [a]) ↝ y] ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] oo
     Trs B ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] oo
    [a # (z ⊖ [a]) ↝ z]"
       apply (subst par_id_comp, simp_all)
        apply (subst TO_comp, simp_all)
         apply (subst TO_comp, simp_all)
         apply (simp add: x_def)
         apply (simp add: a_def Out_out)
        apply (simp add: y_def)
       apply (subst par_id_comp, simp_all)
        apply (subst TO_comp, simp_all)
         apply (simp add: x_def)
         apply (simp add: a_def Out_out)
       apply (subst par_id_comp, simp_all)
         apply (simp add: x_def)
         by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
     have F: "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))]
    oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] oo
     [a # (y ⊖ [a]) ↝ y] ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] oo
     Trs B ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] oo
    [a # (z ⊖ [a]) ↝ z]"
         apply (subgoal_tac " [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊕ (y ⊖ [a])) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))] oo
    [x ⊕ (y ⊖ [a]) ↝ x @ (y ⊖ [a])] ∥ [(x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b])] = 
      [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ ((x ⊖ [b]) ⊕ (z ⊖ [a] ⊖ [b]))]")
        apply simp
       apply (subst switch_par_comp, simp_all)
       by (auto simp add: set_addvars set_diff)
         
     have "[b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] = 
        [b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ (b # x) @ (z ⊖ [a] ⊖ [b])] 
        oo [b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [x ↝ x] ∥ [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])]"
       apply (subst switch_par_comp, simp_all add: set_addvars set_diff X)
         apply auto [2]
       apply (subst switch_par_comp, simp_all add: set_addvars set_diff X)
         by auto
         
    from this have "Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] oo
    [a # (z ⊖ [a]) ↝ z] =  
    (Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ (b # x) @ (z ⊖ [a] ⊖ [b])]) 
    oo [b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo ([x ↝ x] ∥ [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ]) oo
    [a # (z ⊖ [a]) ↝ z]"
      apply simp
      by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
    also have "... =  (Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [ [b] ↝ [b] ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]) oo [b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])] oo
    [a # (z ⊖ [a]) ↝ z]"
      apply (subst comp_parallel_distrib)
        apply (simp_all add: x_def)
      apply (subst (2) par_switch, simp_all)
      apply (simp add: set_addvars set_diff)
      using X x_def by auto
    also have "... =  
    ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ ([x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) )) oo [b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])] oo
    [a # (z ⊖ [a]) ↝ z]"
      apply (subgoal_tac "Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo [ [b] ↝ [b] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]
        =  ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ ([x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) ))")
          apply simp
      apply (subst comp_parallel_distrib)
        apply (simp_all add: b_def Out_out)
      apply (subst comp_parallel_distrib)
        apply (simp_all add: y_def Out_out)
      apply (subst switch_par_comp)
      by (simp_all add: set_diff set_addvars)
    
    also have "... =  ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ ([x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) )) 
    oo [b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    (Trs A ∥ [ b # (z ⊖ [a] ⊖ [b]) ↝ b # (z ⊖ [a] ⊖ [b])] oo [ [a] ↝ [a] ] ∥  [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])]) oo
    [a # (z ⊖ [a]) ↝ z]"
      apply (subgoal_tac " Trs A ∥ [b # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [a] ] =  (Trs A ∥ [ b # (z ⊖ [a] ⊖ [b]) ↝ b # (z ⊖ [a] ⊖ [b])] oo [ [a] ↝ [a] ] ∥  [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])])")
       apply simp
        apply (subst comp_parallel_distrib)
        apply (simp_all add: a_def Out_out)
      by (subst switch_comp, simp_all add: set_diff, auto)
    also have "... = ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ ([x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) )) 
    oo ([b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ [ b # (z ⊖ [a] ⊖ [b]) ↝ b # (z ⊖ [a] ⊖ [b])]) oo ([ [a] ↝ [a] ] ∥  [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])] oo
    [a # (z ⊖ [a]) ↝ z])"
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)

    also have "... = ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ ([x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) )) 
    oo ([b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ ([ [b] ↝ [b] ] ∥  [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])])) oo ([a # b # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a]) ] oo
    [a # (z ⊖ [a]) ↝ z])"
      apply (subgoal_tac "[ [a] ↝ [a] ] ∥  [b # (z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a])] = [a # b # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a]) ]")
       apply simp
       apply (subgoal_tac "[b # (z ⊖ [a] ⊖ [b]) ↝ b # (z ⊖ [a] ⊖ [b])] = [ [b] ↝ [b] ] ∥  [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])]")
        apply simp
        apply (subst par_switch, simp_all add: set_diff)
      apply (subst par_switch, simp_all add: set_diff)
      using Diff a_def b_def by auto
        
    also have "... =  ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ ([x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) )) 
    oo ([b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ ([ [b] ↝ [b] ] ∥  [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])])) oo [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]"
      apply (subgoal_tac " ([a # b # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a]) ] oo [a # (z ⊖ [a]) ↝ z]) = [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]")
        apply simp
        apply (subst switch_comp, simp_all add: set_diff)
      using Diff a_def b_def apply simp
       apply (metis ‹b ≠ a› ‹distinct z› ‹out A ∈ set (In C)› ‹out B ∈ set (In C)› a_def b_def distinct_diff perm_dist_mem perm_set_eq set_ConsD z_def)
      by blast
    also have "... = ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ [x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] )) 
    oo ([b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ [ [b] ↝ [b] ] ∥  [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])]) oo [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]"
      by (simp add: par_assoc)
     also have "... = ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ [x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])
    oo (([b # x  ↝ x @ [b] ] oo Trs A ∥ [ [b] ↝ [b] ]) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo 
     [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]"
       apply (subgoal_tac " ([b # x  ↝ x @ [b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
    Trs A ∥ [ [b] ↝ [b] ] ∥  [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])]) =  (([b # x  ↝ x @ [b] ] oo Trs A ∥ [ [b] ↝ [b] ]) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])")
        apply simp
        apply (subst comp_parallel_distrib)
        by (simp_all add: x_def)
     also have "... =  ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ [x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])
    oo (([ [b] ↝ [b] ] ∥ Trs A oo [ [b,a] ↝ [a,b] ]) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo 
     [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]"
       apply (subgoal_tac "([b # x  ↝ x @ [b] ] oo Trs A ∥ [ [b] ↝ [b] ]) = ([ [b] ↝ [b] ] ∥ Trs A oo [ [b,a] ↝ [a,b] ])")
        apply simp
         thm switch_parallel_a
         apply (cut_tac x= "[b]" and y = x and u = "[b]" and v = "[a]" and T = "Trs A" and S = "[ [b] ↝ [b] ]" in switch_parallel_a)
               apply (simp_all)
           apply (simp add: X)
           by (simp_all add: x_def a_def Out_out)
      also have "... = ([ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ [x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])
    oo ([ [b] ↝ [b] ] ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [b,a] ↝ [a,b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo 
     [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]"
        apply (subgoal_tac "(([ [b] ↝ [b] ] ∥ Trs A oo [ [b,a] ↝ [a,b] ]) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) 
          = ([ [b] ↝ [b] ] ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [b,a] ↝ [a,b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])")
         apply simp
        apply (subst comp_parallel_distrib)
        by (simp_all add: a_def Out_out)
     also have "... =  [ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo (Trs B ∥ [x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
    oo [ [b] ↝ [b] ] ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo ([ [b,a] ↝ [a,b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo 
     [a # b # (z ⊖ [a] ⊖ [b]) ↝  z])"
       by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
         also have "... = [ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
             oo ([ [b,a] ↝ [a,b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝  z])"
        apply (subgoal_tac " (Trs B ∥ [x ↝ x] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
    oo [ [b] ↝ [b] ] ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) = Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]")
            apply simp
             apply (subst comp_parallel_distrib, simp_all add: x_def b_def Out_out)
           by (subst comp_parallel_distrib, simp_all add: x_def b_def Out_out)
             
    also have "... = [ y ↝ y ] ∥ [ x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
             oo [b # a # (z ⊖ [a] ⊖ [b]) ↝  z]"
      
      apply (subgoal_tac " ([ [b,a] ↝ [a,b] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝  z]) = [b # a # (z ⊖ [a] ⊖ [b]) ↝  z]")
       apply (simp)
      apply (subst par_switch, simp_all add: set_diff)
      apply (subst switch_comp, simp_all add: set_diff)
       apply (simp add: perm_mset)
        by blast
        

    finally have Aa: "Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] oo
    [a # (z ⊖ [a]) ↝ z] =  
    [y ↝ y] ∥ [(x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ Trs A ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])] oo [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
      by simp

     have G: " [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] oo
    [a # (z ⊖ [a]) ↝ z] =  
    [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    (Trs B ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [b # (x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a])] oo
    Trs A ∥ [z ⊖ [a] ↝ z ⊖ [a] ] oo
    [a # (z ⊖ [a]) ↝ z])"
       by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
     have H: "... =   [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [y ↝ y] ∥ [(x ⊕ (z ⊖ [a] ⊖ [b])) ↝ x @ (z ⊖ [a] ⊖ [b])] oo Trs B ∥ Trs A ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])] oo [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
      apply (simp add: Aa)
       by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
       
     have I:"[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [y ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
    [b # a # (z ⊖ [a] ⊖ [b]) ↝ z] = 
        [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    ([a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [y ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]) oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
    [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
       by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
         
    have J:"... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
    [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
      apply (subgoal_tac " ([a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [y ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]) = [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]")
          apply simp
      by (subst comp_parallel_distrib, simp_all add: x_def b_def Out_out)
        have K:"... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo ((Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]) oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
    [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
          apply (simp add: par_assoc)
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
        have L:"... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] 
        oo (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo  [a # (y ⊖ [a]) ↝ y]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
        Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
        [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
       apply (subgoal_tac "((Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x ⊕ (z ⊖ [a] ⊖ [b])] oo
    [a # (y ⊖ [a]) ↝ y] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]) =  (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo  [a # (y ⊖ [a]) ↝ y]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]")
           apply simp
      by (subst comp_parallel_distrib, simp_all add: x_def b_def Out_out a_def)
            

    have Ba: "[a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])] = 
        [ [a] ↝ [a,a] ] ∥  [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
          oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a])  ↝ (y ⊖ [a]) @ [a]  ] ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
          oo [a # (y ⊖ [a]) ↝ y] ∥ [ a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ]"
      apply (subst par_switch, simp_all add: set_diff set_addvars)
        apply (cut_tac x = "a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))" and y = "[a]" and y' = "[a]" 
          and z = "a # (y ⊖ [a])" and z' = " (y ⊖ [a]) @ [a]" and u = "z ⊖ [a] ⊖ [b] " and u' = "z ⊖ [a] ⊖ [b]"  in switch_par_comp3)
                  apply (simp_all add: set_diff set_addvars)
        apply auto
      apply (cut_tac x = "a # ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))" 
          and y = "a # (y ⊖ [a])" and y' = y and z = "a # (z ⊖ [a] ⊖ [b])" and z' = "z ⊖ [b]"  in switch_par_comp)
      by (simp_all add:set_diff set_addvars, auto)
        
    have Ca: "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])] oo
    ([ [a] ↝ [a, a] ] ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
     [a # (y ⊖ [a]) ↝ y] ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ]) oo
    Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo
    [b # (z ⊖ [b]) ↝ z] = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])] oo
    [ [a] ↝ [a, a] ] ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]) oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
     ([a # (y ⊖ [a]) ↝ y] ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] oo
    Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo
    [b # (z ⊖ [b]) ↝ z])"
      by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
    have Da: "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A oo [ [a] ↝ [a, a] ] ) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
        oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
        ([a # (y ⊖ [a]) ↝ y] ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z])"
      apply (subgoal_tac " (Trs A ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b])] oo [ [a] ↝ [a, a] ] ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]) = 
        (Trs A oo [ [a] ↝ [a, a] ] ) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]")
       apply simp
      by (subst comp_parallel_distrib, simp_all add: a_def Out_out)
        
    have Ea: "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A oo [ [a] ↝ [a, a] ] ) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
        oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
        (([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ]  oo [b # (z ⊖ [b]) ↝ z])"
      apply (subgoal_tac "[a # (y ⊖ [a]) ↝ y] ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] = ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ]")
       apply simp
      by (subst comp_parallel_distrib, simp_all add: y_def)
    have Fa: "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A oo [ [a] ↝ [a, a] ] ) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
        oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
        (([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b]) ] oo [ [b] ↝ [b] ] ∥ [ a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z])"
      apply (subgoal_tac "([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] 
          = ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b]) ] oo [ [b] ↝ [b] ] ∥ [ a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] ")
       apply simp
      apply (subst comp_parallel_distrib, simp_all)
       apply (subst TO_comp, simp_all add: y_def b_def Out_out)
      by (subst switch_comp, simp_all add: set_diff, auto)
        
     have Ga: "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A oo [ [a] ↝ [a, a] ] ) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
        oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
        ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b]) ] oo ([ [b] ↝ [b] ] ∥ [ a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z])"
       by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
         have Ha: "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A oo [ [a] ↝ [a, a] ] ) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
        oo [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
        ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b]) ] oo ([ b # a # (z ⊖ [a] ⊖ [b]) ↝ z])"
           apply (subgoal_tac " ([ [b] ↝ [b] ] ∥ [ a # (z ⊖ [a] ⊖ [b]) ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z]) = ([ b # a # (z ⊖ [a] ⊖ [b]) ↝ z])")
            apply simp
           apply (subst par_switch, simp_all add:set_diff, auto)
           apply (subst switch_comp, simp_all add: set_diff)
            apply (rule set_perm , simp_all add: set_diff, auto)
           using a_def z_def apply auto[1]
           using ‹b ≠ a› by auto
             
       
         have Ab: "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo ([x ↝ x @ x] oo Trs A ∥ Trs A) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]
        = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo (([x ↝ x @ x] oo Trs A ∥ Trs A) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])])"
           by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
         have Ac: "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo 
            (([x ↝ x @ x] ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]) oo (Trs A ∥ Trs A ∥ ([(y ⊖ [a]) ↝ y ⊖ [a] ] ∥ [(z ⊖ [a] ⊖ [b]) ↝  (z ⊖ [a] ⊖ [b])])))"
           apply (subgoal_tac "(([x ↝ x @ x] oo Trs A ∥ Trs A) ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]) = 
               (([x ↝ x @ x] ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])]) oo (Trs A ∥ Trs A ∥ ([(y ⊖ [a]) ↝ y ⊖ [a] ] ∥ [(z ⊖ [a] ⊖ [b]) ↝  (z ⊖ [a] ⊖ [b])])))")
            apply simp
           apply (subst comp_parallel_distrib, simp_all)
            apply (simp add: x_def)
           by (subst switch_par_comp, simp_all)
         have Ad: "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ ((y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]))] oo 
            [x ↝ x @ x] ∥ [(y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] oo Trs A ∥ Trs A ∥ [(y ⊖ [a]) ↝ y ⊖ [a] ] ∥ [(z ⊖ [a] ⊖ [b]) ↝  (z ⊖ [a] ⊖ [b])]"
           by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def par_assoc)
         have Ae: "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ ((y ⊖ [a]) @ (z ⊖ [a] ⊖ [b]))] 
            oo Trs A ∥ Trs A ∥ [(y ⊖ [a]) ↝ y ⊖ [a] ] ∥ [(z ⊖ [a] ⊖ [b]) ↝  (z ⊖ [a] ⊖ [b])]"
           by (subst switch_par_comp, simp_all add: set_addvars set_diff, auto)
           
           
         have "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
              oo Trs A ∥ Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])] 
              = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
                oo (Trs A ∥ (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ]) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo
            ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])]"
           apply (simp add: par_assoc)
           by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
        also have "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
                oo Trs A ∥ (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ]) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])]"
          
           apply (subst comp_parallel_distrib, simp_all add: a_def Out_out)
          by (subst comp_parallel_distrib, simp_all add: a_def Out_out)
            
         also have "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
                oo Trs A ∥ ([ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] oo [y ⊖ [a] ↝ y ⊖ [a] ] ∥ Trs A) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])]"
           apply (subgoal_tac "(Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ]) 
            = ([ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] oo [y ⊖ [a] ↝ y ⊖ [a] ] ∥ Trs A)")
            apply simp
           apply (subst switch_parallel_a [THEN sym], simp_all add: set_diff)
           using ‹set x' ∩ (set y) = {}› apply blast
           by (simp_all add: Out_out a_def x_def)
             
        also have "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
                oo ([x ↝ x] ∥ [ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] 
                    oo  Trs A ∥ ([y ⊖ [a] ↝ y ⊖ [a] ] ∥ Trs A) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])]"
          apply (subgoal_tac " Trs A ∥ ([ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] oo [y ⊖ [a] ↝ y ⊖ [a] ] ∥ Trs A) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] 
              = ([x ↝ x] ∥ [ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] 
                    oo  Trs A ∥ ([y ⊖ [a] ↝ y ⊖ [a] ] ∥ Trs A) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])")
           apply simp
           apply (subst comp_parallel_distrib, simp_all add: a_def Out_out x_def)
          by (subst comp_parallel_distrib, simp_all add: x_def)
            also have "... = ([x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
                oo [x ↝ x] ∥ [ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])
                    oo  ((Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ]) ∥ (Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])])"
           apply (simp add: par_assoc)
              by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
                
          also have "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] 
                    oo  ((Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ]) ∥ (Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])])"
            
           apply (subgoal_tac "([x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (x @ (y ⊖ [a])) @ (z ⊖ [a] ⊖ [b])] 
                oo [x ↝ x] ∥ [ x' @ (y ⊖ [a])  ↝ (y ⊖ [a]) @ x'  ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) 
              = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] ")
             apply simp
            apply (subst switch_par_comp_Subst3, simp_all add: set_diff set_addvars)
              apply (simp add: Diff_Int_distrib, blast)
            apply (subgoal_tac " Subst (x' @ (y ⊖ [a])) (x @ (y ⊖ [a])) ((y ⊖ [a]) @ x') = (y ⊖ [a]) @ x")
             apply simp
            apply (simp add: Subst_append, safe)
             apply (metis (no_types, lifting) AAA_c Subst_eq Subst_not_in_a TVs_length_eq ‹TVs x' = TVs x› ‹set x' ∩ set y = {}› disjoint_insert(2) empty_set insert_Diff list.simps(15) set_diff)
            by (metis Subst_all Subst_cancel_left_type TVs_length_eq ‹TVs x' = TVs x› ‹set x' ∩ set y = {}› empty_inter_diff empty_set newvars_distinct set_inter x'_def)
              
        also have "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] 
                    oo  (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ (Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])"
          
          apply (subst comp_parallel_distrib)
            apply (simp_all add: y_def a_def Out_out)[2]
          apply (subst comp_switch_id)
            apply (simp_all add: set_diff a_def Out_out) [2]
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
            
       finally have Bc: "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ x @ (y ⊖ [a]) @ (z ⊖ [a] ⊖ [b])] 
              oo Trs A ∥ Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              [ [a] ↝ [a] ] ∥ [a # (y ⊖ [a]) ↝ (y ⊖ [a]) @ [a] ] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo
              ([a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ [a # (z ⊖ [a] ⊖ [b]) ↝ a # (z ⊖ [a] ⊖ [b])]
            = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] 
                    oo  (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ (Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])"
         by simp
           
              
     have "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo
    (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] = 
        [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo
        ([x ↝ x] ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
    (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ ([x ↝ x ] ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])])) oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]"
       apply (subgoal_tac " (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] = 
          ([x ↝ x] ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
    (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ ([x ↝ x ] ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])]))")
        apply simp
       apply (subst comp_parallel_distrib)
         apply (simp_all add: x_def y_def a_def Out_out) [2]
       apply (simp add: distinct_id)
       by (subst comp_id_left_simp, simp_all add: x_def a_def Out_out)
     also have " ... =  ([x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo
        [x ↝ x] ∥ [y ⊖ [a] ↝ y ⊖ [a] ] ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])]) oo
    ((Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ [x ↝ x ] ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])"
       apply (simp add: par_assoc)
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
     also have "... = [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] oo
    ((Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ [x ↝ x ] ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])"
       by (subst switch_par_comp3, simp_all add: set_diff set_addvars, auto)
         
    also have "... =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] oo
    (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ Trs A ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])]"
      apply (subst comp_parallel_distrib)
        apply (simp_all add: Out_out a_def b_def c_def x_def y_def z_def) [2]
      apply (subst comp_parallel_distrib)
        apply (simp_all add: Out_out a_def b_def c_def x_def y_def z_def) [2]
      by (simp add: x_def)
        
    finally have Cc: "[x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ (x ⊕ (z ⊖ [a] ⊖ [b]))] oo
    (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y]) ∥ [x ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (z ⊖ [a] ⊖ [b])] oo
    Trs B ∥ Trs A ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] =  [x ⊕ (y ⊖ [a]) ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊖ [a]) @ x @ (z ⊖ [a] ⊖ [b])] oo
    (Trs A ∥ [y ⊖ [a] ↝ y ⊖ [a] ] oo [a # (y ⊖ [a]) ↝ y] oo Trs B) ∥ Trs A ∥ [(z ⊖ [a] ⊖ [b]) ↝ (z ⊖ [a] ⊖ [b])]"
      by simp
         
     show "[In A ⊕ (In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ In A @ ((In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]))] oo
    Trs A ∥ [(In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ (In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B])] oo
    [out A # ((In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B])) ↝ In B ⊕ (In C ⊖ [out B])] oo
    [In B ⊕ (In C ⊖ [out B]) ↝ In B @ (In C ⊖ [out B])] oo
    Trs B ∥ [In C ⊖ [out B] ↝ In C ⊖ [out B] ] oo
    [out B # (In C ⊖ [out B]) ↝ In C] =
    [In A ⊕ (In B ⊖ [out A]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ (In A ⊕ (In B ⊖ [out A])) @ ((In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B]))] oo
    ([In A ⊕ (In B ⊖ [out A]) ↝ In A @ (In B ⊖ [out A])] oo Trs A ∥ [In B ⊖ [out A] ↝ In B ⊖ [out A] ] oo [out A # (In B ⊖ [out A]) ↝ In B] oo Trs B) ∥
    [(In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ (In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B])] oo
    [out B # ((In A ⊖ [out B]) ⊕ (In C ⊖ [out A] ⊖ [out B])) ↝ In A ⊕ (In C ⊖ [out A])] oo
    [In A ⊕ (In C ⊖ [out A]) ↝ In A @ (In C ⊖ [out A])] oo
    Trs A ∥ [In C ⊖ [out A] ↝ In C ⊖ [out A] ] oo
    [out A # (In C ⊖ [out A]) ↝ In C]"
       apply (simp add: a_def [THEN sym] b_def [THEN sym] c_def [THEN sym] x_def [THEN sym] y_def [THEN sym] z_def [THEN sym])
       apply (simp add: A B C D E F)
       apply (simp add: X AAA_c)
       apply (simp add: G H I J K L)
       apply (simp add: Ba )
       apply (simp add: Ca Da Ea Fa Ga Ha)
         thm arg_cong
       apply (subst  arg_cong [of _ _ "λ A . A oo  [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"], simp_all)
       apply (simp add: A_det)
       apply (subst Ab)
         apply (simp add: Ac Ad Ae)
         apply (simp add: Bc Cc)
         by (simp add: par_assoc)
     qed
         
lemma Comp_commute_aux:
  assumes [simp]: "length (Out A) = 1"
    and [simp]: "length (Out B) = 1"
    and [simp]: "io_diagram A"
    and [simp]: "io_diagram B"
    and [simp]: "io_diagram C"
    and [simp]: "out B ∉ set (In A)"
    and [simp]: "out A ∉ set (In B)"
    and [simp]: "out A ∈ set (In C)"
    and [simp]: "out B ∈ set (In C)"
    and Diff: "out A ≠ out B"

    shows "Trs (A ;; (B ;; C)) = 
                [In A ⊕ In B ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ In A @ In B @ (In C ⊖ [out A] ⊖ [out B])] 
                    oo Trs A ∥ Trs B ∥ [ In C ⊖ [out A] ⊖ [out B] ↝ In C ⊖ [out A] ⊖ [out B] ]
                    oo [out A # out B # (In C ⊖ [out A] ⊖ [out B]) ↝ In C] 
                    oo Trs C"
      and "In (A ;; (B ;; C)) = In A ⊕ In B ⊕ (In C ⊖ [out A] ⊖ [out B])"
      and "Out (A ;; (B ;; C)) = Out C"
    proof -
        define a where "a = out A"
        define b where "b = out B"
        define c where "c = out C"
        define x where "x = In A"
        define y where "y = In B"
        define z where "z = In C"
        have [simp]: "distinct x"
          by (simp add: x_def)
        have [simp]: "distinct y"
          by (simp add: y_def)
        have [simp]: "distinct z"
          by (simp add: z_def)
            
        have [simp]: "b ∈ set z"
          by (simp add: b_def z_def)
        have [simp]: "b ≠ a"
          using Diff a_def b_def by (simp)
        have [simp]: "a ≠ b"
          using Diff a_def b_def by (simp)
        have [simp]: "b ∉ set x"
          by (simp add: b_def x_def)
            
        have [simp]: "a ∉ set y"
          by (simp add: a_def y_def)
            
        have [simp]: "a ∈ set z"
          by (simp add: ‹a ≡ out A› ‹z ≡ In C›)
            
        have [simp]: "(y ⊕ (z ⊖ [b])) ⊖ [a] = y ⊕ (z ⊖ [a] ⊖ [b])"
          by (simp add: AAA_c addvars_minus diff_sym)
            
            
        have "[y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo [y @ [a] ↝ a # y] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] 
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] 
            = [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo ([y @ [a] ↝ a # y] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z]"
          
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
        also have "... = [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo ([y @ [a] ↝ a # y] oo [ [a] ↝ [a] ] ∥ Trs B) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z]"
          apply (subgoal_tac " ([y @ [a] ↝ a # y] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) = 
                ([y @ [a] ↝ a # y] oo [ [a] ↝ [a] ] ∥ Trs B) ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]")
           apply simp
          by (subst comp_parallel_distrib, simp_all add: y_def)
          also have "... = [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo (Trs B ∥ [ [a] ↝ [a] ] oo [ [b, a] ↝ [a, b] ])  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z]"
            apply (subgoal_tac "([y @ [a] ↝ a # y] oo [ [a] ↝ [a] ] ∥ Trs B)  = (Trs B ∥ [ [a] ↝ [a] ] oo [ [b, a] ↝ [a, b] ])")
             apply simp
            thm switch_parallel_a
            apply (cut_tac switch_parallel_a [of y "[a]" "[b]" "[a]" "Trs B" "[ [a] ↝ [a] ]"])
                  apply simp_all
             by (simp_all add: y_def b_def Out_out)
              also have "... =  [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo (Trs B ∥ [ [a] ↝ [a] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [b, a] ↝ [a, b] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z]"
                apply (subgoal_tac "(Trs B ∥ [ [a] ↝ [a] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [b, a] ↝ [a, b] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) 
                    =   (Trs B ∥ [ [a] ↝ [a] ] oo [ [b, a] ↝ [a, b] ])  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]")
                apply simp
                by (subst comp_parallel_distrib, simp_all add: y_def b_def Out_out)
          also have "... = ([y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo Trs B ∥ ([ [a] ↝ [a] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])) oo ([ [b, a] ↝ [a, b] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z])"
            apply (simp add: par_assoc)
            by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
              also have "... =  Trs B ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo  ([ [b, a] ↝ [a, b] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z])"
                apply (subgoal_tac "([y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo Trs B ∥ ([ [a] ↝ [a] ]  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])) = Trs B ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] ")
                 apply simp
                apply (subst comp_parallel_distrib, simp_all add: y_def b_def Out_out)
                by (subst par_switch, simp_all add: set_diff)
        also have "... =  Trs B ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] oo  [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
          apply (subst par_switch)
             apply (simp_all add: set_diff)
          apply (subst switch_comp, simp_all add: set_diff)
          by (subst set_perm, simp_all add: set_diff, auto)
        also have "... =  (Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [ [b] ↝ [b] ] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])])oo  [b # a # (z ⊖ [a] ⊖ [b]) ↝ z]"
          by (subst comp_parallel_distrib, simp_all add: y_def b_def Out_out)
        also have "... = Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo ([ [b] ↝ [b] ] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] oo  [b # a # (z ⊖ [a] ⊖ [b]) ↝ z])"
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
        also have "... = Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z]"
          apply (subst par_switch, simp_all add: set_diff, auto)
          apply (subst switch_comp, simp_all add: set_diff, auto)
          by (rule set_perm, simp_all add: set_diff, auto)
            
        finally have Aa: "Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z] = [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] 
            oo [y @ [a] ↝ a # y] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] 
            oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z]" (is "?X = ?Y")
          by simp
            
        have "Trs (A ;; (B ;; C)) = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
            oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] oo [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y ⊕ (z ⊖ [b])] oo
            ([y ⊕ (z ⊖ [b]) ↝ y @ (z ⊖ [b])] oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z] oo Trs C  )"       
          by (simp add: Comp_def Let_def a_def [THEN sym] x_def [THEN sym] b_def [THEN sym] y_def [THEN sym]
              c_def [THEN sym] z_def [THEN sym] Var_def Out_out par_empty_left set_addvars set_diff addvars_assoc [THEN sym])
        also have "... =  [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
            oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] oo ([a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y ⊕ (z ⊖ [b])] oo
            [y ⊕ (z ⊖ [b]) ↝ y @ (z ⊖ [b])]) oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z] oo Trs C"
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
            also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
            oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] oo [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])]
                  oo Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z] oo Trs C"
              apply (subgoal_tac "([a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y ⊕ (z ⊖ [b])] oo
            [y ⊕ (z ⊖ [b]) ↝ y @ (z ⊖ [b])]) = [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])]")
               apply simp
              apply (subst switch_comp)
                 apply (simp_all add: set_addvars set_diff)
              by (subst set_perm, simp_all add: set_addvars set_diff, auto)
          also have "... =  [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
            oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] oo [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])]
                  oo (Trs B ∥ [z ⊖ [b] ↝ z ⊖ [b] ] oo [b # (z ⊖ [b]) ↝ z]) oo Trs C"
            by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
          also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
            oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] oo [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])]
                  oo ?Y oo Trs C"
            by (simp add: Aa)
          also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] 
              oo ([a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])] oo
                [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] oo [y @ [a] ↝ a # y] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) 
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
            by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
           also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] 
              oo [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝  a # y @ (z ⊖ [a] ⊖ [b]) ]
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
            apply (subgoal_tac "([a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝ y @ (z ⊖ [b])] oo
                [y ↝ y] ∥ [z ⊖ [b] ↝ a # (z ⊖ [a] ⊖ [b])] oo [y @ [a] ↝ a # y] ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ])  = 
                [a # (y ⊕ (z ⊖ [a] ⊖ [b])) ↝  a # y @ (z ⊖ [a] ⊖ [b]) ]")
              apply (simp)
             apply (subst switch_par_comp, simp_all add: set_diff set_addvars, auto)
               thm switch_par_comp
               apply (cut_tac switch_par_comp [of "a # (y ⊕ (z ⊖ [a] ⊖ [b]))" " y @ [a]" "(z ⊖ [a] ⊖ [b])" "a # y"])
                      apply simp
               by (simp_all add: set_addvars set_diff, auto)
             
            also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] 
              oo [ [a] ↝ [a] ] ∥ [(y ⊕ (z ⊖ [a] ⊖ [b])) ↝  y @ (z ⊖ [a] ⊖ [b]) ]
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
              apply (subst par_switch)
              by (simp_all add: set_diff set_addvars)
                also have "... =  [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] oo (Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] 
              oo [ [a] ↝ [a] ] ∥ [(y ⊕ (z ⊖ [a] ⊖ [b])) ↝  y @ (z ⊖ [a] ⊖ [b]) ])
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
                  by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
              also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] oo Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])] 
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
                apply (subgoal_tac "(Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ (z ⊖ [a] ⊖ [b])] 
              oo [ [a] ↝ [a] ] ∥ [(y ⊕ (z ⊖ [a] ⊖ [b])) ↝  y @ (z ⊖ [a] ⊖ [b]) ]) =  Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])] ")
                 apply simp
                by (subst comp_parallel_distrib, simp_all add: y_def b_def Out_out a_def)
                  
                  
              also have "... =  [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
                  oo ([x ↝ x] ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])] oo Trs A ∥ ( [y ↝ y] ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]))
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
                
                apply (subgoal_tac "Trs A ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])]  = ([x ↝ x] ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])] oo Trs A ∥ ( [y ↝ y] ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]))")
                 apply simp
                apply (subst comp_parallel_distrib)
                  apply (simp_all add: y_def b_def Out_out x_def) [2]
                by (subst switch_par_comp, simp_all add: x_def)
               also have "... = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
                  oo [x ↝ x] ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])]) oo (Trs A ∥ [y ↝ y] ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
                apply (simp add: par_assoc) 
                 by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
            also have "... =  ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [a] ⊖ [b])]) oo (Trs A ∥ [y ↝ y] ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
              apply (subgoal_tac " ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ (y ⊕ (z ⊖ [a] ⊖ [b]))] 
                  oo [x ↝ x] ∥ [y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ (z ⊖ [a] ⊖ [b])]) = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [a] ⊖ [b])]) ")
              apply simp
              by (subst switch_par_comp, simp_all add: set_diff set_addvars, auto)
           also have "... = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [a] ⊖ [b])]) oo Trs A ∥ Trs B ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
                oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
                apply (subgoal_tac " (Trs A ∥ [y ↝ y] ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
                oo [ [a] ↝ [a] ] ∥ Trs B ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]) =  Trs A ∥ Trs B ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]")
              apply simp
                apply (subst comp_parallel_distrib)
                  apply (simp_all add: y_def b_def Out_out x_def a_def)
             by (subst comp_parallel_distrib, simp_all add: Out_out)
        
           finally have "Trs (A ;; (B ;; C)) = 
                [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [a] ⊖ [b])] 
                    oo Trs A ∥ Trs B ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
                    oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] 
                    oo Trs C"
             by simp
               
        from this show "Trs (A ;; (B ;; C)) = 
                [In A ⊕ In B ⊕ (In C ⊖ [out A] ⊖ [out B]) ↝ In A @ In B @ (In C ⊖ [out A] ⊖ [out B])] 
                    oo Trs A ∥ Trs B ∥ [ In C ⊖ [out A] ⊖ [out B] ↝ In C ⊖ [out A] ⊖ [out B] ]
                    oo [out A # out B # (In C ⊖ [out A] ⊖ [out B]) ↝ In C] 
                    oo Trs C"
          by (simp add: x_def y_def z_def a_def b_def)
        show "In (A ;; (B ;; C)) = In A ⊕ In B ⊕ (In C ⊖ [out A] ⊖ [out B])"
          apply (simp add: Comp_def Let_def Var_def Out_out set_addvars set_diff, safe)
           apply (metis ‹a ≡ out A› ‹b ≡ out B› ‹y ⊕ (z ⊖ [b]) ⊖ [a] = y ⊕ (z ⊖ [a] ⊖ [b])› addvars_assoc b_def y_def z_def) 
            by (simp add: Diff)
          
      show  "Out (A ;; (B ;; C)) = Out C"
          apply (simp add: Comp_def Let_def Var_def Out_out set_addvars set_diff, safe)
            by (simp add: Diff)
  qed

       
lemma Comp_commute:
  assumes [simp]: "length (Out A) = 1"
    and [simp]: "length (Out B) = 1"
    and [simp]: "io_diagram A"
    and [simp]: "io_diagram B"
    and [simp]: "io_diagram C"
    and [simp]: "out B ∉ set (In A)"
    and [simp]: "out A ∉ set (In B)"
    and [simp]: "out A ∈ set (In C)"
    and [simp]: "out B ∈ set (In C)"
    and Diff: "out A ≠ out B"
  shows "in_equiv (A ;; (B ;; C)) (B ;; (A ;; C))"
    proof -
        define a where "a = out A"
        define b where "b = out B"
        define c where "c = out C"
        define x where "x = In A"
        define y where "y = In B"
        define z where "z = In C"
        have [simp]: "distinct x"
          by (simp add: x_def)
        have [simp]: "distinct y"
          by (simp add: y_def)
        have [simp]: "distinct z"
          by (simp add: z_def)
            
        have [simp]: "b ∈ set z"
          by (simp add: b_def z_def)
        have [simp]: "b ≠ a"
          using Diff a_def b_def by (simp)
        have [simp]: "a ≠ b"
          using Diff a_def b_def by (simp)
        have [simp]: "b ∉ set x"
          by (simp add: b_def x_def)
            
        have [simp]: "a ∉ set y"
          by (simp add: a_def y_def)
            
        have [simp]: "a ∈ set z"
          by (simp add: ‹a ≡ out A› ‹z ≡ In C›)
            
        have [simp]: "(y ⊕ (z ⊖ [b])) ⊖ [a] = y ⊕ (z ⊖ [a] ⊖ [b])"
          by (simp add: AAA_c addvars_minus diff_sym)
            
        
        have A: "Trs (A ;; (B ;; C)) = 
                [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [a] ⊖ [b])] 
                    oo Trs A ∥ Trs B ∥ [ z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ]
                    oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] 
                    oo Trs C"
          apply (subst Comp_commute_aux, simp_all)
           apply (simp add: Diff)
          by (simp add: x_def y_def z_def a_def b_def)
            
            
        define x' where "x' = newvars (y) (TVs x)"
          
        have [simp]: "distinct x'" and [simp]: "set y ∩ set x' = {}"
           by (simp_all add: x'_def)
            
            
        have  " [In (A ;; (B ;; C)) ↝ In (B ;; (A ;; C))] oo Trs (B ;; (A ;; C)) = 
              [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ x ⊕ (z ⊖ [b] ⊖ [a])]
              oo ([y ⊕ x ⊕ (z ⊖ [b] ⊖ [a]) ↝ y @ x @ (z ⊖ [b] ⊖ [a])] 
              oo Trs B ∥ Trs A ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] 
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z] oo Trs C)"
          apply (subst Comp_commute_aux, simp_all)
          using Diff apply auto
          apply (subst Comp_commute_aux, simp_all)
          apply (subst Comp_commute_aux, simp_all)
          by (simp add: x_def[THEN sym] y_def[THEN sym] z_def[THEN sym] a_def[THEN sym] b_def[THEN sym])
            
        also have "... = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y ⊕ x ⊕ (z ⊖ [b] ⊖ [a])]
              oo [y ⊕ x ⊕ (z ⊖ [b] ⊖ [a]) ↝ y @ x @ (z ⊖ [b] ⊖ [a])])
              oo Trs B ∥ Trs A ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] 
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z] oo Trs C"
          by (simp add:  Out_out comp_assoc a_def b_def c_def x_def y_def z_def)
        also have "... =  ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ x @ (z ⊖ [b] ⊖ [a])])
              oo Trs B ∥ Trs A ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] 
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z] oo Trs C"
          apply (subst switch_comp, simp_all)
          by (rule set_perm, simp_all add: set_addvars set_diff, auto)
            also have "... = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ x @ (z ⊖ [b] ⊖ [a])])
              oo ([y @ x' ↝ x' @ y] oo Trs A ∥ Trs B oo [ [a, b] ↝ [b, a] ]) ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] 
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z] oo Trs C"
              
              apply (subgoal_tac "Trs B ∥ Trs A = ([y @ x' ↝ x' @ y] oo Trs A ∥ Trs B oo [ [a] @ [b] ↝ [b] @ [a] ])")
               apply simp
              apply (subst switch_par [THEN sym], simp_all)
              by (simp_all add: y_def x'_def x_def b_def a_def Out_out)
        also have "... = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ x @ (z ⊖ [b] ⊖ [a])])
              oo ([y @ x' ↝ x' @ y]  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] oo Trs A ∥ Trs B  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] oo [ [a, b] ↝ [b, a] ] ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]) 
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z] oo Trs C"
          
          apply (subgoal_tac "([y @ x' ↝ x' @ y] oo Trs A ∥ Trs B oo [ [a, b] ↝ [b, a] ]) ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]  = 
               ([y @ x' ↝ x' @ y]  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] oo Trs A ∥ Trs B  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] oo [ [a, b] ↝ [b, a] ] ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]) ")
           apply simp
          apply (subst comp_parallel_distrib)
            apply (simp_all add: Out_out x'_def x_def y_def) [2]
          apply (subst comp_parallel_distrib)
          by (simp_all add: Out_out x'_def x_def y_def b_def a_def)
            
        also have "... = ([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ y @ x @ (z ⊖ [b] ⊖ [a])]
              oo [y @ x' ↝ x' @ y]  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]) oo Trs A ∥ Trs B  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] oo ([ [a, b] ↝ [b, a] ] ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z]) oo Trs C"
          by (simp add:  Out_out comp_assoc a_def b_def x_def y_def z_def x'_def)
        also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [b] ⊖ [a])]
               oo Trs A ∥ Trs B  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] oo ([ [a, b] ↝ [b, a] ] ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z]) oo Trs C"
          apply (subgoal_tac "([x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ (y @ x) @ (z ⊖ [b] ⊖ [a])]
              oo [y @ x' ↝ x' @ y]  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]) = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [b] ⊖ [a])]")
           apply simp
            thm switch_par_comp_Subst
            apply (subst switch_par_comp_Subst)
                     apply (simp_all add: set_addvars set_diff, auto) [9]
             apply (simp add: x'_def)
            apply (simp add: Subst_append)
              apply (subgoal_tac "Subst (y @ x') (y @ x) x' = x")
             apply (subgoal_tac "Subst (y @ x') (y @ x) y = y")
              apply simp
             apply (metis Subst_eq Subst_not_in ‹distinct x'› ‹distinct y› ‹set y ∩ set x' = {}› dist_perm distinct_append length_Subst perm_tp)
              by (simp add: ‹x' ≡ newvars y (TVs x)›)
            
        also have "... =  [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [b] ⊖ [a])]
               oo Trs A ∥ Trs B  ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ] 
              oo [a # b # (z ⊖ [b] ⊖ [a]) ↝ z] oo Trs C"
          apply (subgoal_tac "([ [a, b] ↝ [b, a] ] ∥ [z ⊖ [b] ⊖ [a] ↝ z ⊖ [b] ⊖ [a] ]
              oo [b # a # (z ⊖ [b] ⊖ [a]) ↝ z]) = [a # b # (z ⊖ [b] ⊖ [a]) ↝ z]")
           apply simp
          apply (subst par_switch, simp_all add: set_diff)
          apply (subst switch_comp, simp_all add: set_addvars set_diff)
          by (rule set_perm, auto simp add: set_diff)
        also have "... = [x ⊕ y ⊕ (z ⊖ [a] ⊖ [b]) ↝ x @ y @ (z ⊖ [a] ⊖ [b])] oo Trs A ∥ Trs B  ∥ [z ⊖ [a] ⊖ [b] ↝ z ⊖ [a] ⊖ [b] ] oo [a # b # (z ⊖ [a] ⊖ [b]) ↝ z] oo Trs C"
          by (simp add: diff_sym)
          
            
        finally have [simp]: "Trs (A ;; (B ;; C)) = [In (A ;; (B ;; C)) ↝ In (B ;; (A ;; C))] oo Trs (B ;; (A ;; C))"
          apply (simp)
          by (simp add: A)
            
        have [simp]: "Out (A ;; (B ;; C)) = Out (B ;; (A ;; C))"
          apply (subst Comp_commute_aux, simp_all)
           apply (simp add: Diff)
          apply (subst Comp_commute_aux, simp_all)
           using Diff by auto
            
        have [simp]: "perm (In (A ;; (B ;; C))) (In (B ;; (A ;; C)))"
          apply (subst Comp_commute_aux, simp_all)
           apply (simp add: Diff)
          apply (subst Comp_commute_aux, simp_all)
          using Diff apply auto
            by (simp add: diff_sym distinct_perm_switch)

        show "in_equiv (A ;; (B ;; C)) (B ;; (A ;; C))"
          by (simp add: in_equiv_def)
  qed

lemma CompA_commute_aux_a: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ length (Out A) = 1 ⟹ length (Out B) = 1 
    ⟹ out A ∉ set (Out C) ⟹ out B ∉ set (Out C)
    ⟹ out A ≠ out B ⟹ out A ∈ set (In B) ⟹ out B ∉ set (In A)
    ⟹ deterministic (Trs A)
    ⟹ (CompA (CompA B A) (CompA B C)) = (CompA (CompA A B) (CompA A C))"
  proof -
    assume [simp]: "io_diagram A"
    assume [simp]: "io_diagram B"
    assume [simp]: "io_diagram C"
    assume "length (Out A) = 1"
    assume "length (Out B) = 1"
    assume [simp]: "out A ∉ set (Out C)"
    assume [simp]: "out B ∉ set (Out C)"
    assume B: "out A ≠ out B"
    assume [simp]: "deterministic (Trs A)"
      
    have [simp]: "Out A = [out A]"
      using Out_out ‹length (Out A) = 1› by auto
    have [simp]: "Out B = [out B]"
      using Out_out ‹length (Out B) = 1› by auto
    have [simp]: "io_diagram (A ;; C)"
      by (rule io_diagram_Comp, simp_all)
    assume A[simp]: "out A ∈ set (In B)"
    assume [simp]: "out B ∉ set (In A)"
      
    have [simp]: "io_diagram (B ;; C)"
      by (rule io_diagram_Comp, simp_all)
    have [simp]: "io_diagram (A ;; (B ;; C))"
      apply (rule io_diagram_Comp, simp_all)
      by (simp add: Comp_def Let_def Var_def set_addvars set_diff)
    then show ?thesis
      apply (simp)
        proof (cases "out A ∈ set (In C)")
          case True
          from True have [simp]: "out A ∈ set (In C)"
            by simp
          have [simp]: "out A ∈ set (In (CompA B C))"
            by (simp add: In_CompA set_addvars)
          then show "(CompA A (CompA B C)) = (CompA (A ;; B) (CompA A C))"
            apply (simp)
          proof (cases "out B ∈ set (In C)")
            case True
            have [simp]: "out ((A ;; B)) ∈ set (In (A ;; C))"
              apply (simp)
              using B by (simp add: Comp_def Let_def set_addvars set_diff Var_def True)
            then show "(A ;; CompA B C) = (CompA (A ;; B) (A ;; C))" 
              apply (simp add: True)
              apply (rule  Comp_assoc_single, simp_all)
              using B apply blast
                using True by blast
          next
            case False
            have [simp]: "out ((A ;; B)) ∉ set (In (A ;; C))"
              apply (simp)
              using B by (simp add: Comp_def Let_def set_addvars set_diff Var_def False)
            then show "(A ;; CompA B C) = (CompA (A ;; B) (A ;; C))"
              by (simp add: False)
          qed
        next
          case False
          assume [simp]: "out A ∉ set (In C)"
          then show "(CompA A (CompA B C)) = (CompA (A ;; B) (CompA A C))"
            apply simp
          proof (cases "out B ∈ set (In C)")
            case True
            have [simp]: "out (A ;; B) ∈ set (In C)"
              by (simp add: True)
            have [simp]: "out A ∈ set (In (B ;; C))"
              by (simp add: Comp_def Let_def set_addvars)
            then show "(CompA A (CompA B C)) = (CompA (A ;; B) C)" 
              by (simp add: True Comp_assoc_new in_equiv_eq)
          next
            case False
            have [simp]: "out (A ;; B) ∉ set (In C)"
              using False by simp
            then show "(CompA A (CompA B C)) = (CompA (A ;; B) C)" 
              by (simp add: False in_equiv_eq)
          qed
        qed
  qed

    
lemma CompA_commute_aux_b: "io_diagram A ⟹ io_diagram B ⟹ io_diagram C ⟹ length (Out A) = 1 ⟹ length (Out B) = 1 
    ⟹ out A ∉ set (Out C) ⟹ out B ∉ set (Out C)
    ⟹ out A ≠ out B ⟹ out A ∉ set (In B) ⟹ out B ∉ set (In A)
    ⟹ in_equiv (CompA (CompA B A) (CompA B C)) (CompA (CompA A B) (CompA A C))"
  proof -
    assume [simp]: "io_diagram A"
    assume [simp]: "io_diagram B"
    assume [simp]: "io_diagram C"
    assume "length (Out A) = 1"
    assume "length (Out B) = 1"
    assume [simp]: "out A ∉ set (Out C)"
    assume [simp]: "out B ∉ set (Out C)"
    assume B: "out A ≠ out B"
      
    have [simp]: "Out A = [out A]"
      using Out_out ‹length (Out A) = 1› by auto
    have [simp]: "Out B = [out B]"
      using Out_out ‹length (Out B) = 1› by auto
    have [simp]: "io_diagram (A ;; C)"
      by (rule io_diagram_Comp, simp_all)
        
    assume A[simp]: "out A ∉ set (In B)"
    assume [simp]: "out B ∉ set (In A)"
      
    have [simp]: "io_diagram (B ;; C)"
      by (rule io_diagram_Comp, simp_all)
        (*
    have [simp]: "io_diagram (A ;; (B ;; C))"
      apply (rule io_diagram_Comp_a, simp_all)
      by (simp add: Comp_def Let_def Var_def set_addvars set_diff)
*)
    then show ?thesis
      apply (simp)
        proof (cases "out A ∈ set (In C)")
          case True
          from True have [simp]: "out A ∈ set (In C)"
            by simp
          have [simp]: "out A ∈ set (In (CompA B C))"
            apply (simp add: In_CompA set_addvars set_diff)
              using B by blast
          then show "in_equiv (CompA A (CompA B C)) (CompA B (CompA A C))"
            apply (simp)
          proof (cases "out B ∈ set (In C)")
            case True
            have [simp]: "out B ∈ set (In (A ;; C))"
              using B by (simp add: Comp_def Let_def set_addvars set_diff Var_def True)
            then show "in_equiv (A ;; CompA B C) (CompA B (A ;; C))" 
              apply (simp add: True)
                thm Comp_commute
                apply (subst Comp_commute, simp_all)
                 apply (simp add: True)
                  by (simp add: B)
          next
            case False
            have [simp]: "out B ∉ set (In (A ;; C))"
              using B by (simp add: Comp_def Let_def set_addvars set_diff Var_def False)
            then show "in_equiv (A ;; CompA B C) (CompA B (A ;; C))"
              apply (simp add: False)
                by (simp add: in_equiv_eq)
          qed
        next
          case False
          assume [simp]: "out A ∉ set (In C)"
          then show "in_equiv (CompA A (CompA B C)) (CompA B (CompA A C))"
            apply simp
          proof (cases "out B ∈ set (In C)")
            case True
            have [simp]: "out B ∈ set (In C)"
              by (simp add: True)
            have [simp]: "out A ∉ set (In (B ;; C))"
              by (simp add: Comp_def Let_def set_addvars set_diff)
            then show "in_equiv (CompA A (CompA B C))  (CompA B C)" 
              by (simp add: Comp_assoc_new in_equiv_eq)
          next
            case False
            have [simp]: "out B ∉ set (In C)"
              using False by simp
            then show "in_equiv (CompA A (CompA B C)) (CompA B C)" 
              by (simp add: in_equiv_eq)
          qed
        qed
  qed

    
fun In_Equiv :: "(('var, 'a) Dgr) list ⇒ (('var, 'a) Dgr) list ⇒ bool" where 
  "In_Equiv [] [] = True" |
  "In_Equiv (A # As) (B# Bs) = (in_equiv A B ∧ In_Equiv As Bs)" |
  "In_Equiv _ _ = False"
  
thm internal_def
  
thm fb_out_less_step_def
thm fb_less_step_def
  
thm CompA_commute_aux_b
thm CompA_commute_aux_a
 
lemma CompA_commute: 
  assumes [simp]: "io_diagram A"
    and [simp]: "io_diagram B"
    and [simp]: "io_diagram C"
    and [simp]: "length (Out A) = 1"
    and [simp]: "length (Out B) = 1"
    and [simp]: "out A ∉ set (Out C)"
    and [simp]: "out B ∉ set (Out C)"
    and [simp]: "out A ≠ out B"
    and [simp]: "deterministic (Trs A)"
    and [simp]: "deterministic (Trs B)"
    and A: "(out A ∈ set (In B) ⟹ out B ∉ set (In A))"
  shows "in_equiv (CompA (CompA B A) (CompA B C)) (CompA (CompA A B) (CompA A C))"
    proof (cases "out A ∈ set (In B)")
      case True
      from this and A have [simp]: "out B ∉ set (In A)"
        by simp
      then show ?thesis
        using True apply (subst CompA_commute_aux_a, simp_all)
          apply (rule in_equiv_eq)
         apply (metis BBB_a BaseOperationFeedbacklessVars.CompA_in BaseOperationFeedbacklessVars_axioms True assms(1) assms(2) assms(3) assms(4) assms(5) io_diagram_CompA)
          by simp
    next
      case False
      then have [simp]: "out A ∉ set (In B)"
        by simp
      show ?thesis
      proof (cases "out B ∈ set (In A)")
        case True
        then show ?thesis
          thm CompA_commute_aux_a
          apply (subst CompA_commute_aux_a [of B A], simp_all)
          using assms(8) apply fastforce
          by (metis BaseOperationFeedbacklessVars.BBB_a BaseOperationFeedbacklessVars.CompA_in BaseOperationFeedbacklessVars_axioms assms(1) assms(2) assms(3) assms(4) assms(5) in_equiv_eq io_diagram_CompA)
      next
        case False
        then show ?thesis
          thm CompA_commute_aux_b
          by (subst CompA_commute_aux_b, simp_all)
      qed
    qed
  
  
lemma In_Equiv_CompA_twice: "(⋀ C . C ∈ set As ⟹ io_diagram C ∧ out A ∉ set (Out C) ∧ out B ∉ set (Out C)) ⟹ io_diagram A ⟹ io_diagram B
    ⟹ length (Out A) = 1 ⟹ length (Out B) = 1 ⟹ out A ≠ out B
    ⟹ deterministic (Trs A) ⟹ deterministic (Trs B)
    ⟹ (out A ∈ set (In B) ⟹ out B ∉ set (In A))
    ⟹ In_Equiv (map (CompA (CompA B A)) (map (CompA B) As)) (map (CompA (CompA A B)) (map (CompA A) As))"
  apply (induction As, simp_all)
  by (rule CompA_commute, simp_all)
    
thm Type_OK_def
thm Deterministic_def
thm internal_def
thm fb_out_less_step_def

thm mem_get_other_out
  
thm mem_get_comp_out
  

thm comp_out_in
  

lemma map_diff: "(⋀ b . b ∈ set x ⟹ b ≠ a ⟹ f b ≠ f a) ⟹ map f x ⊖ [f a] = map f (x ⊖ [a])"
  by (induction x, simp_all)


lemma In_Equiv_fb_out_less_step_commute: "Type_OK As ⟹ Deterministic As ⟹ x ∈ internal As ⟹  y ∈ internal As  ⟹ x ≠ y ⟹ loop_free As
  ⟹ In_Equiv (fb_out_less_step x (fb_out_less_step y As)) (fb_out_less_step y (fb_out_less_step x As))"
proof -
  assume "Deterministic As"
  assume "x ≠ y"
  assume loopfree: "loop_free As"

  assume [simp]: "Type_OK As"
    
  from this have [simp]: "⋀ A . A ∈ set As ⟹ Out A = [out A]"
    using Type_OK_out by blast      
    
  define A where "A = get_comp_out x As"
  assume "x ∈ internal As"
  from this have A_As[simp]: "A ∈ set As" and out_A: "out A = x"
     by (simp_all add: A_def)

  define B where "B = get_comp_out y As"
  assume "y ∈ internal As"
  from this have B_As[simp]: "B ∈ set As" and out_B: "out B = y"
    by (simp_all add: B_def)
      
  have [simp]: " A ≠ B"
    using ‹x ≠ y› out_A out_B by auto
      
  from A_As obtain Bs Cs where As_A: "As = Bs @ A # Cs"
    by (meson split_list)

  from ‹Type_OK As› have "distinct As"
    using Type_OK_distinct by blast
  have As_minus_A: "As ⊖ [A] = Bs @ Cs"
    apply (simp add: union_diff As_A)
    apply (subgoal_tac "Bs ⊖ [A] = Bs")
     apply (subgoal_tac "Cs ⊖ [A] = Cs")
      apply simp
     apply (metis AAA_c As_A  ‹distinct As› distinct.simps(2) distinct_append)
    by (metis AAA_c As_A UnCI ‹distinct As› append.simps(2) dist_perm distinct.simps(2) perm_tp set_append)
    
  have [simp]: "Out A = [out A]"
    using A_As Type_OK_out ‹Type_OK As› by blast
  have [simp]: "Out B = [out B]"
    using B_As Type_OK_out ‹Type_OK As› by blast
      
  from loopfree have "out A ∈ set (In B) ⟹ out B ∉ set (In A)"
    apply (simp add: loop_free_def IO_Rel_def io_rel_def)
    apply (drule_tac x = "out A" in spec, safe)
    apply (drule notE, simp_all)
    apply (subst trancl_unfold_left)
    apply (simp add: relcomp_def OO_def)
    apply (rule_tac x = "out B" in exI, safe)
     apply (rule_tac x = A in bexI)
       apply (simp add: io_rel_def, simp_all)
      apply (rule r_into_rtrancl, simp_all)
    apply (rule_tac x = B in bexI)
    by (simp add: io_rel_def, simp)
 
  have [simp]: "(fb_out_less_step x As) = map (CompA A) (As ⊖ [A])"
    apply (simp add: fb_out_less_step_def A_def [THEN sym])
    apply (simp add: out_A[THEN sym])
    apply (subst mem_get_other_out, simp_all)
    by (simp add: fb_less_step_def)

  have [simp]: "(fb_out_less_step y As) =  map (CompA B) (As ⊖ [B])"
    apply (simp add: fb_out_less_step_def B_def [THEN sym])
    apply (simp add: out_B[THEN sym])
    apply (subst mem_get_other_out, simp_all)
    by (simp add: fb_less_step_def As_A union_diff)
      
  thm mem_get_comp_out
    
  have y_out_CompA: "y = out (CompA A B)"
    by (metis A_As BaseOperationFeedbacklessVars.BBB_a BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars.out_def BaseOperationFeedbacklessVars_axioms ‹Type_OK As› out_B)
      
  have x_out_CompA: "x = out (CompA B A)"
    by (metis B_As BaseOperationFeedbacklessVars.BBB_a BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars.out_def BaseOperationFeedbacklessVars_axioms ‹Type_OK As› out_A)
    
  have [simp]: "Type_OK (map (CompA A) (As ⊖ [A]))"
    by (metis A_As BaseOperationFeedbacklessVars.fb_out_less_step_def BaseOperationFeedbacklessVars.mem_get_other_out BaseOperationFeedbacklessVars_axioms Type_OK_fb_out_less_step_aux ‹A ≡ get_comp_out x As› ‹Type_OK As› ‹fb_out_less_step x As = map (CompA A) (As ⊖ [A])› out_A)
    
  have [simp]: "Type_OK (map (CompA B) (As ⊖ [B]))"
      by (metis B_As B_def BaseOperationFeedbacklessVars.fb_out_less_step_def BaseOperationFeedbacklessVars.mem_get_other_out BaseOperationFeedbacklessVars_axioms Type_OK_fb_out_less_step_aux ‹Type_OK As› ‹fb_out_less_step y As = map (CompA B) (As ⊖ [B])› out_B)
    
      
  have [simp]: "get_comp_out y (map (CompA A) (As ⊖ [A])) = CompA A B"
    apply (subgoal_tac "y = out (CompA A B)")
     apply (simp)
     apply (rule mem_get_comp_out)
      apply (simp_all add: set_diff image_def)
     apply (rule_tac x = B in bexI, simp_all)
    using ‹A ≠ B› apply blast
      using ‹y = out (CompA A B)› by blast
      
  have [simp]: "get_comp_out x (map (CompA B) (As ⊖ [B])) = CompA B A"
    apply (subgoal_tac "x = out (CompA B A)")
     apply (simp)
     apply (rule mem_get_comp_out)
      apply (simp_all add: set_diff image_def)
     apply (rule_tac x = A in bexI, simp_all)
      by (rule x_out_CompA)
      
    thm mem_get_other_out
      
    have [simp]: "map (CompA A) (As ⊖ [A]) ⊖ [CompA A B] = map (CompA A) (As ⊖ [A] ⊖ [B])"
      apply (rule map_diff)
        by (metis A_As B_As BaseOperationFeedbacklessVars.BBB_a BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars_axioms DiffE Type_OK_out ‹Type_OK As› list.simps(1) mem_get_comp_out set_diff)
      have [simp]: "map (CompA B) (As ⊖ [B]) ⊖ [CompA B A] = map (CompA B) (As ⊖ [A] ⊖ [B])"
        apply (subst map_diff)
         apply (metis A_As B_As BaseOperationFeedbacklessVars.BBB_a BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars_axioms DiffE Type_OK_out ‹Type_OK As› list.simps(1) mem_get_comp_out set_diff)
          by (simp add: diff_sym)

  have [simp]: "fb_out_less_step y (map (CompA A) (As ⊖ [A])) = map (CompA (CompA A B)) (map (CompA A) (As ⊖ [A] ⊖ [B]))"
    apply (simp add: fb_out_less_step_def fb_less_step_def y_out_CompA)
    apply (subst mem_get_other_out, simp_all)
     apply (simp add: image_def set_diff)
     apply (rule_tac x = B in bexI, simp_all)
    using ‹A ≠ B› apply blast
    by (simp add: y_out_CompA[THEN sym])
      
  have [simp]: "fb_out_less_step x (map (CompA B) (As ⊖ [B])) = map (CompA (CompA B A)) (map (CompA B) (As ⊖ [A] ⊖ [B]))"
    apply (simp add: fb_out_less_step_def fb_less_step_def x_out_CompA)
    apply (subst mem_get_other_out, simp_all)
     apply (simp add: image_def set_diff)
     apply (rule_tac x = A in bexI, simp_all)
    by (simp add: x_out_CompA[THEN sym])
      thm In_Equiv_CompA_twice
  show ?thesis
    apply (simp del: map_map)
    apply (rule In_Equiv_CompA_twice)
            apply simp_all
          apply (simp add: set_diff, safe)
    using BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars_axioms ‹Type_OK As› apply blast
           apply (metis  ‹A ≡ get_comp_out x As› ‹Type_OK As› mem_get_comp_out out_A )
          apply (metis ‹B ≡ get_comp_out y As› ‹Type_OK As›  mem_get_comp_out out_B )
         apply (meson A_As BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars_axioms ‹Type_OK As›)
    using B_As BaseOperationFeedbacklessVars.Type_OK_def BaseOperationFeedbacklessVars_axioms ‹Type_OK As› apply blast
       apply (simp add: ‹x ≠ y› out_A out_B)
      using A_As Deterministic_def ‹Deterministic As› apply blast
      using B_As Deterministic_def ‹Deterministic As› apply blast
        using ‹out A ∈ set (In B) ⟹ out B ∉ set (In A)› by blast
   
    qed
      
lemma [simp]: "Type_OK As ⟹ In_Equiv As As"
proof (induction As)
  case Nil
  then show ?case
    by simp
next
  case (Cons a As)
  then show ?case
    apply simp
    by (simp add: Type_OK_def in_equiv_eq)
qed
  
lemma fb_less_append: "⋀ As . fb_less (x @ y) As = fb_less y (fb_less x As)"
  proof (induction x)
    case Nil
    then show ?case
      by simp
  next
    case (Cons a x)
    then show ?case 
      by simp
  qed
    
  thm in_equiv_tran

    
lemma In_Equiv_trans: "⋀ Bs Cs . Type_OK Cs ⟹ In_Equiv As Bs ⟹ In_Equiv Bs Cs ⟹ In_Equiv As Cs"
  proof (induction As)
    case Nil
    show ?case
      apply (case_tac Bs)
      using Nil.prems(3) apply blast
      using Nil.prems(2) by auto
  next
    case (Cons a As)
    show ?case
      apply (case_tac Bs)
      using Cons.prems(2) apply auto[1]
      apply (case_tac Cs, simp_all)
      using Cons.prems(3) In_Equiv.simps(3) apply blast
      apply safe
       apply (rule_tac B = aaa in in_equiv_tran)
      using Cons.prems(1) Type_OK_cons apply blast
        apply (metis Cons.prems(1) Cons.prems(2) Cons.prems(3) In_Equiv.simps(2) Type_OK_cons in_equiv_tran)
      using Cons.prems(1) Type_OK_cons in_equiv_eq apply blast
      using Cons.IH Cons.prems(1) Cons.prems(2) Cons.prems(3) In_Equiv.simps(2) Type_OK_cons by blast
    qed
      

  
lemma In_Equiv_exists: "⋀ Bs . In_Equiv As Bs ⟹ A ∈ set As ⟹ ∃ B ∈ set Bs . in_equiv A B"
  proof (induction As)
    case Nil
    then show ?case
      by simp
  next
    case (Cons a As)
    then show ?case
      by (case_tac Bs, simp_all, safe, simp)
  qed
       
lemma In_Equiv_Type_OK: "⋀Bs . Type_OK Bs ⟹ In_Equiv As Bs ⟹ Type_OK As"
proof (induction As)
  case Nil
  show ?case
    apply (case_tac Bs)
    using Nil.prems(1) apply blast
    using In_Equiv.simps(4) Nil.prems(2) by blast
next
  case (Cons a As)
  from Cons(3) obtain b Cs where [simp]: "Bs = b # Cs" and A: "in_equiv a b" and B[simp]: "In_Equiv As Cs"
    using In_Equiv.elims(2) by blast
      
  from A have [simp]: "length (Out a) = 1"
    apply (simp add: in_equiv_def)
    by (metis Cons.prems(1) One_nat_def Type_OK_cons ‹Bs = b # Cs›)
      
  from A have C: "Out a = Out b"
    by (simp add: in_equiv_def)
      
  show ?case
    apply (subst Type_OK_cons, safe)
    using Cons.prems(1) Type_OK_cons ‹Bs = b # Cs› ‹in_equiv a b› in_equiv_io_diagram apply blast
      apply simp
     apply (cut_tac A = aa and As = As and Bs = Cs in  In_Equiv_exists, simp_all)
     apply safe
     apply (simp add: C in_equiv_def)
    using Cons(2)
     apply (simp add: Type_OK_def)
      apply auto [1]
    using B Cons.IH Cons.prems(1) Type_OK_cons ‹Bs = b # Cs› by blast
qed
  
      
lemma In_Equiv_internal_aux: "Type_OK Bs ⟹ In_Equiv As Bs ⟹ internal As ⊆ internal Bs"
  apply (simp add: internal_def, safe)
  apply (frule_tac A = A in In_Equiv_exists, blast)   
  apply (frule_tac A = B in In_Equiv_exists, blast)
  apply safe
  apply (rule_tac x = Ba in bexI, safe)
   apply (simp add: in_equiv_def out_def)
    using In_Equiv_exists in_equiv_def perm_set_eq by blast
    
    
lemma In_Equiv_sym: "⋀ Bs . Type_OK Bs ⟹ In_Equiv As Bs ⟹ In_Equiv Bs As"
proof (induction As)
  case Nil
  then show ?case
    by (case_tac Bs, simp_all)
next
  case (Cons a As)
  then show ?case
    apply (case_tac Bs, simp_all)
    apply (rule in_equiv_sym, simp_all)
    using Type_OK_cons by blast
qed

lemma In_Equiv_internal: "Type_OK Bs ⟹ In_Equiv As Bs ⟹ internal As = internal Bs"
  apply (frule In_Equiv_Type_OK, blast)
  apply (frule In_Equiv_internal_aux, blast)
  apply (drule_tac As = Bs and Bs = As in In_Equiv_internal_aux)
  by (rule In_Equiv_sym, simp_all)

lemma in_equiv_CompA: "in_equiv A A' ⟹ in_equiv B B' ⟹ io_diagram A' ⟹ io_diagram B' ⟹ in_equiv (CompA A B) (CompA A' B')"
  apply (simp add: CompA_def)
    apply (case_tac "out A ∈ set (In B)", simp_all, safe)
    apply (rule in_equiv_Comp, simp_all)
    apply (subst (asm) in_equiv_def) 
   apply (subst (asm) in_equiv_def, safe)
   apply (simp add: out_def)
  using perm_set_eq apply blast
    apply (subst (asm) in_equiv_def) 
   apply (subst (asm) in_equiv_def, safe)
   apply (simp add: out_def)
  using perm_set_eq by blast
    
lemma In_Equiv_fb_less_step_cong: "⋀ Bs . Type_OK Bs ⟹ in_equiv A B ⟹ io_diagram B ⟹ In_Equiv As Bs
    ⟹ In_Equiv (fb_less_step A As) (fb_less_step B Bs)"
proof (induction As)
  case Nil
  then show ?case
    by (case_tac Bs, simp_all add: fb_less_step_def)
next
  case (Cons b As)
  then show ?case
    apply (case_tac Bs, simp_all)
    apply (simp add: fb_less_step_def)
    apply (rule in_equiv_CompA)
       apply simp_all
    using Type_OK_cons by blast
qed
  
lemma In_Equiv_append: "⋀ As' . In_Equiv As As' ⟹ In_Equiv Bs Bs' ⟹ In_Equiv (As @ Bs) (As' @ Bs')"   
proof (induction As)
  case Nil
  then show ?case
    apply (case_tac As')
    by simp_all
next
  case (Cons a As)
  then show ?case
    by (case_tac As', simp_all)
qed
  
lemma In_Equiv_split: "⋀ Bs . In_Equiv As Bs ⟹ A ∈ set As 
    ⟹ ∃ B As' As'' Bs' Bs'' . As = As' @ A # As'' ∧ Bs = Bs' @ B # Bs'' ∧ in_equiv A B ∧ In_Equiv As' Bs' ∧ In_Equiv As'' Bs''"
proof (induction As)
  case Nil
  then show ?case
    by simp
next
  case (Cons a As)
  then show ?case
  proof (cases "a = A")
    case True
    from this and Cons show ?thesis
    apply (simp_all, safe)
      apply (case_tac Bs, simp_all)
     apply (rule_tac x = aa in exI)
     apply (rule_tac x = "[]" in exI)
      apply (rule_tac x = As in exI, simp)
     apply (rule_tac x = "[]" in exI)
     by (rule_tac x = list in exI, simp)      
  next
    case False
    obtain b Ba where [simp]: "Bs = b # Ba"
      using Cons.prems(1) In_Equiv.elims(2) by blast
    
    have "A ∈ set As"
      using Cons.prems(2) False by auto
        
    have "In_Equiv As Ba"
      using Cons.prems(1) ‹Bs = b # Ba› by auto
        
    have [simp]: "in_equiv a b"
      using Cons.prems(1) In_Equiv.simps(2) ‹Bs = b # Ba› by blast
        
    obtain B As' As'' Bs' Bs'' where [simp]: "As = As' @ A # As''" and [simp]: "Ba = Bs' @ B # Bs''" 
        and [simp]: "in_equiv A B" and [simp]: "In_Equiv As' Bs'" and [simp]: "In_Equiv As'' Bs''"
      using Cons.IH ‹A ∈ set As› ‹In_Equiv As Ba› by blast
        
    show ?thesis
      apply simp
      apply (rule_tac x = B in exI, simp)
      apply (rule_tac x = "a # As'" in exI, simp)
      by (rule_tac x = "b # Bs'" in exI, simp)
  qed  
qed

    
lemma In_Equiv_fb_out_less_step_cong: 
  assumes [simp]: "Type_OK Bs"
    and "In_Equiv As Bs"
    and internal: "a ∈ internal As"
    shows "In_Equiv (fb_out_less_step a As) (fb_out_less_step a Bs)"
proof -
  have [simp]: "Type_OK As"
    using In_Equiv_Type_OK assms(1) assms(2) by blast

  obtain A where "A ∈ set As" and "out A = a"
    using internal by (subst (asm) internal_Type_OK_simp, simp_all, blast)
      
  have [simp]: "get_comp_out a As = A"
    using ‹A ∈ set As› ‹Type_OK As› ‹out A = a› mem_get_comp_out by blast
      
  have [simp]: "get_other_out a As = As ⊖ [A]"
    using ‹A ∈ set As› ‹Type_OK As› ‹out A = a› mem_get_other_out by blast
      
  obtain B As' As'' Bs' Bs'' where As_split: "As = As' @ A # As''" and Bs_split: "Bs = Bs' @ B # Bs''" and [simp]: "in_equiv A B" 
      and [simp]: "In_Equiv As' Bs'" and [simp]: "In_Equiv As'' Bs''"
    using In_Equiv_split ‹A ∈ set As› assms(2) by blast
      
  have "out B = a"
    by (metis ‹in_equiv A B› ‹out A = a› in_equiv_def out_def)
      
  have "B ∈ set Bs"
    by (simp add: ‹Bs = Bs' @ B # Bs''›)
      
  have [simp]: "get_comp_out a Bs = B"
    using ‹B ∈ set Bs› ‹Type_OK Bs› ‹out B = a› mem_get_comp_out by blast

  have [simp]: "get_other_out a Bs = Bs ⊖ [B]"
    using ‹B ∈ set Bs› ‹Type_OK Bs› ‹out B = a› mem_get_other_out by blast
      
  have "distinct As"
    by (simp add: Type_OK_distinct )

  have [simp]: "As ⊖ [A] = As' @ As''"
    apply (simp add: As_split union_diff)
    by (metis AAA_c As_split ‹distinct As› disjoint_insert(2) distinct.simps(2) distinct_append list.simps(15))
      
  have "distinct Bs"
    by (simp add: Type_OK_distinct)

  have Bs_diff: "Bs ⊖ [B] = Bs' @ Bs''"
    apply (simp add: Bs_split union_diff)
    by (metis AAA_c Bs_split ‹distinct Bs› disjoint_insert(2) distinct.simps(2) distinct_append list.simps(15))
      

  show ?thesis
    apply (simp add: fb_out_less_step_def)
    apply (rule In_Equiv_fb_less_step_cong)
       apply (metis Diff_iff Type_OK_def ‹get_other_out a Bs = Bs ⊖ [B]› assms(1) concat_map_Out_get_other_out distinct_diff set_diff)
      apply simp
    using Type_OK_def ‹B ∈ set Bs› assms(1) apply blast
    by (simp add: Bs_diff In_Equiv_append)
qed
 
lemma In_Equiv_IO_Rel: "⋀ Bs . In_Equiv As Bs ⟹ IO_Rel Bs = IO_Rel As"
proof (induction As)
  case Nil
  then show ?case
    by (case_tac Bs, simp_all)
next
  case (Cons a As)
    
  obtain B Bs' where [simp]: "Bs = B # Bs'"
    using In_Equiv.elims(2) local.Cons(2) by blast
  have [simp]: "(⋃x∈set Bs'. io_rel x) = (⋃x∈set As . io_rel x)"
    by (metis Cons.IH IO_Rel_def In_Equiv.simps(2) ‹Bs = B # Bs'› local.Cons(2) set_map)
      
  have "in_equiv a B"
    using Cons.prems by auto

  from this have [simp]: "io_rel a = io_rel B"
    by (metis in_equiv_def io_rel_def perm_set_eq)
     
  then show ?case
      by (simp add: IO_Rel_def)
qed
  
      
lemma In_Equiv_loop_free: "In_Equiv As Bs ⟹ loop_free Bs ⟹ loop_free As"
  apply (simp add: loop_free_def)
  by (subgoal_tac "IO_Rel Bs = IO_Rel As", simp_all add: In_Equiv_IO_Rel)
    
lemma loop_free_fb_out_less_step_internal: 
  assumes [simp]: "loop_free As"
    and [simp]: "Type_OK As"
    and "a ∈ internal As"
    shows "loop_free (fb_out_less_step a As)"
proof -
  obtain A where [simp]: "A ∈ set As" and [simp]: "out A = a"
    using assms(3) by (simp add: internal_Type_OK_simp, blast)
  show ?thesis
    by (rule_tac A = A in loop_free_fb_out_less_step, simp_all)
qed

lemma loop_free_fb_less_internal: 
  "⋀ As . loop_free As ⟹ Type_OK As ⟹ set x ⊆ internal As ⟹ distinct x ⟹ loop_free (fb_less x As)"
proof (induction x)
  case Nil
  then show ?case
    by simp
next
  case (Cons a x)
  then show ?case
    apply (simp)
    apply (rule Cons(1))
       apply (rule loop_free_fb_out_less_step_internal)
         apply simp_all
    using Type_OK_fb_out_less_step_new apply blast
    by (metis Diff_empty internal_fb_out_less_step subset_Diff_insert)
qed

  
      
     
lemma In_Equiv_fb_less_cong: "⋀ As Bs . Type_OK Bs ⟹ In_Equiv As Bs ⟹ set x ⊆ internal As ⟹  distinct x ⟹ loop_free Bs ⟹ In_Equiv (fb_less x As) (fb_less x Bs)"
proof (induction x)
  case Nil
  then show ?case
    by simp
next
  case (Cons a x)
  have [simp]: "a ∈ internal Bs"
    by (metis Cons.prems(1) Cons.prems(2) Cons.prems(3) In_Equiv_internal list.set_intros(1) subsetCE)
  have [simp]: "Type_OK (fb_out_less_step a Bs)"
    using Cons.prems(1) Cons.prems(5) Type_OK_fb_out_less_step_new ‹a ∈ internal Bs› by blast
  have "Type_OK As"
    using Cons.prems(1) Cons.prems(2) In_Equiv_Type_OK by blast
  show ?case
    apply simp
    apply (rule Cons(1))
        apply simp_all
       apply (rule In_Equiv_fb_out_less_step_cong)
         apply (simp_all add: Cons)
    using Cons.prems(3) apply auto[1]
      apply (subst internal_fb_out_less_step)
    using Cons.prems(2) Cons.prems(5) In_Equiv_loop_free apply blast
        apply (simp add: ‹Type_OK As›)
    using Cons.prems(3) apply auto[1]
    using Cons.prems(3) Cons.prems(4) apply auto[1]
    using Cons.prems(4) apply auto [1]
    apply (rule loop_free_fb_out_less_step_internal)
    by (simp_all add: Cons)
qed
  
      
      
thm Type_OK_fb_out_less_step_new

thm Type_OK_fb_less
  
lemma Type_OK_fb_less_delete: "⋀ As . Type_OK As ⟹ set x ⊆ internal As ⟹ distinct x ⟹ loop_free As ⟹ Type_OK (fb_less x As)"
  by (rule Type_OK_fb_less, simp_all)

  
  
thm Deterministic_fb_out_less_step
  
thm internal_fb_out_less_step
  
lemma internal_fb_less: 
  "⋀ As . loop_free As ⟹ Type_OK As ⟹ set x ⊆ internal As ⟹ distinct x ⟹ internal (fb_less x As) = internal As - set x"
proof (induction x)
  case Nil
  then show ?case
    by simp
next
  case (Cons a x)
  then show ?case
    apply simp
    apply (subst Cons(1))
        apply simp_all
    using loop_free_fb_out_less_step_internal apply blast
    using Type_OK_fb_out_less_step_new apply blast
     apply (metis Diff_empty internal_fb_out_less_step subset_Diff_insert)
    using internal_fb_out_less_step by auto    
qed
  

thm  Deterministic_fb_out_less_step
  
  
lemma Deterministic_fb_out_less_step_internal:
  assumes [simp]: "Type_OK As"
    and "Deterministic As"
    and internal: "a ∈ internal As"
  shows "Deterministic (fb_out_less_step a As)"
proof -
  obtain A where "A ∈ set As" and "out A = a"
    using internal by (simp add: internal_Type_OK_simp, blast)
  show ?thesis
    using Deterministic_fb_out_less_step ‹A ∈ set As› ‹out A = a› assms(1) assms(2) by blast
qed
  
lemma Deterministic_fb_less_internal: "⋀ As . Type_OK As ⟹ Deterministic As ⟹ set x ⊆ internal As ⟹ distinct x 
⟹ loop_free As ⟹ Deterministic (fb_less x As)"
proof (induction x)
  case Nil
  then show ?case
    by simp
next
  case (Cons a x)
  then show ?case
    apply simp
    apply (rule Cons(1), simp_all)
    using Type_OK_fb_out_less_step_new apply blast
    using Deterministic_fb_out_less_step_internal apply blast
      apply (subst internal_fb_out_less_step, simp_all, blast)
    using loop_free_fb_out_less_step_internal by blast
qed
  
    
lemma In_Equiv_fb_less_Cons: "⋀ As . Type_OK As ⟹ Deterministic As ⟹ loop_free As ⟹ a ∈ internal As 
⟹ set x ⊆ internal As ⟹  distinct (a # x)
  ⟹ In_Equiv (fb_less (a # x) As) (fb_less (x @ [a]) As)"
proof (induction x)
  case Nil
  have [simp]:"Type_OK (fb_out_less_step a As)"
    using Nil.prems(1) Nil.prems(3) Nil.prems(4) Type_OK_fb_out_less_step_new by blast
  from Nil show ?case
    by simp_all
next
  case (Cons b x)
  have [simp]: "Type_OK (fb_out_less_step b As)"
    by (metis Cons.prems(1) Cons.prems(5) Type_OK_fb_out_less_step_new insert_subset list.simps(15))
  have [simp]: "Deterministic (fb_out_less_step b As)"
    apply (rule Deterministic_fb_out_less_step_internal)
      apply (simp_all add: Cons)
    using Cons.prems(5) by auto
  have [simp]: " Type_OK (fb_out_less_step a (fb_less x (fb_out_less_step b As)))"
    apply (rule Type_OK_fb_out_less_step_new, simp_all)
     apply (rule Type_OK_fb_less, simp_all)
     apply (meson Cons.prems(1) Cons.prems(3) Cons.prems(5) list.set_intros(1) loop_free_fb_out_less_step_internal subset_iff)
    using Cons.prems(6) apply auto[1]
     apply (metis Cons.prems(1) Cons.prems(3) Cons.prems(5) Cons.prems(6) Diff_empty distinct.simps(2) insert_subset internal_fb_out_less_step list.simps(15) subset_Diff_insert)
    by (metis Cons.prems(1) Cons.prems(3) Cons.prems(4) Cons.prems(5) Cons.prems(6) DiffI distinct.simps(2) fb_less.simps(2) internal_fb_less)
  have [simp]: "Type_OK (fb_out_less_step a (fb_out_less_step b As))"
    apply (rule Type_OK_fb_out_less_step_new, simp_all)
      by (metis Cons.prems(1) Cons.prems(3) Cons.prems(4) Cons.prems(5) Cons.prems(6) distinct_length_2_or_more insert_Diff insert_iff internal_fb_out_less_step list.set_intros(1) subset_eq)
  have [simp]: "set x ⊆ internal (fb_out_less_step b (fb_out_less_step a As))"
  proof -
    have f1: "⋀v. v ∈ insert b (set x) ∨ set x ⊆ internal As - {v}"
      by (metis (no_types) Cons.prems(5) Diff_empty insert_subset list.simps(15) subset_Diff_insert)
    have "b ∈ internal As - {a}"
      by (metis (no_types) Cons.prems(5) Cons.prems(6) Diff_empty distinct.simps(2) insert_subset list.simps(15) subset_Diff_insert)
    then show ?thesis
      using f1 by (metis (no_types) Cons.prems(1) Cons.prems(3) Cons.prems(4) Cons.prems(6) Diff_empty Type_OK_fb_out_less_step_new distinct.simps(2) internal_fb_out_less_step list.simps(15) loop_free_fb_out_less_step_internal subset_Diff_insert)
  qed
  have [simp]: "loop_free (fb_out_less_step a (fb_out_less_step b As))"
    by (metis Cons.prems(1) Cons.prems(3) Cons.prems(4) Cons.prems(5) Cons.prems(6) Type_OK_fb_out_less_step_new distinct_length_2_or_more insert_Diff insert_iff insert_subset internal_fb_out_less_step list.simps(15) loop_free_fb_out_less_step_internal)
  have [simp]: "In_Equiv (fb_less x (fb_out_less_step a (fb_out_less_step b As))) (fb_out_less_step a (fb_less x (fb_out_less_step b As)))"
    apply (cut_tac Cons(1)[of "fb_out_less_step b As"])
          apply (simp add: fb_less_append)
         apply (simp_all add: Cons)
      
       apply (metis Cons.prems(1) Cons.prems(3) Cons.prems(5) insert_subset list.simps(15) loop_free_fb_out_less_step_internal)
      apply (metis Cons.prems(1) Cons.prems(3) Cons.prems(4) Cons.prems(5) Cons.prems(6) distinct_length_2_or_more insert_Diff insert_iff internal_fb_out_less_step list.set_intros(1) subsetCE)
     apply (metis Cons.prems(1) Cons.prems(3) Cons.prems(5) Cons.prems(6) Diff_empty distinct.simps(2) insert_subset internal_fb_out_less_step list.simps(15) subset_Diff_insert)
    using Cons.prems(6) by auto      
  show ?case
    apply (simp add: fb_less_append)
    apply (rule_tac Bs = "(fb_less x (fb_out_less_step a (fb_out_less_step b As)))" in In_Equiv_trans)
      apply simp
      apply (rule In_Equiv_fb_less_cong)
         apply simp_all
        apply (rule In_Equiv_fb_out_less_step_commute)
             apply (simp_all add: Cons)
    using Cons.prems(5) apply auto[1]
    using Cons.prems(6) apply auto[1]
    using Cons.prems(6) by auto[1]
qed
 
    
theorem In_Equiv_fb_less: "⋀ y As . Type_OK As ⟹ Deterministic As ⟹ loop_free As ⟹ set x ⊆ internal As ⟹  distinct x ⟹ perm x y
  ⟹ In_Equiv (fb_less x As) (fb_less y As)"
  
proof (induction x)
  case Nil
  then show ?case
    by simp_all
next
  case (Cons a x)
  obtain y' y'' where A: "y = y' @ a # y''" and [simp]: "perm x (y' @ y'')"
    by (meson Cons.prems(6) split_perm)
      
  have [simp]: "Type_OK (fb_out_less_step a As)"
    by (meson Cons.prems(1) Cons.prems(4) Type_OK_fb_out_less_step_new list.set_intros(1) subset_eq)
      
  have [simp]: "Deterministic (fb_out_less_step a As)"
    by (metis Cons.prems(1) Cons.prems(2) Cons.prems(4) Deterministic_fb_out_less_step_internal insert_subset list.simps(15))
      
  have [simp]: "loop_free (fb_out_less_step a As)"
    by (metis Cons.prems(1) Cons.prems(3) Cons.prems(4) insert_subset list.simps(15) loop_free_fb_out_less_step_internal)
      
  have [simp]: "Type_OK (fb_out_less_step a (fb_less y' As))"
    apply (subgoal_tac "fb_out_less_step a (fb_less y' As) = fb_less (y' @ [a]) As")
     apply simp
     apply (rule Type_OK_fb_less, simp_all add: Cons)
     apply (metis Cons.prems(5) UnI1 ‹perm x (y' @ y'')› dist_perm distinct.simps(2) distinct_append perm_set_eq set_append)
    using Cons.prems(4) ‹perm x (y' @ y'')›
      apply (cut_tac perm_set_eq [of x "y' @ y''"], simp_all)
    by (simp add: fb_less_append)
      

  have [simp]: "Type_OK (fb_less y'' (fb_out_less_step a (fb_less y' As)))"
    apply (subgoal_tac "fb_less y'' (fb_out_less_step a (fb_less y' As)) = fb_less (y' @ a # y'') As")
      apply simp
     apply (rule Type_OK_fb_less, simp_all add: Cons)
     apply (metis A Cons.prems(5) Cons.prems(6) ‹perm x (y' @ y'')› dist_perm distinct.simps(2) distinct_append not_distinct_conv_prefix)
      apply (metis (no_types, lifting) Cons.prems(4) ListProp.perm_set_eq ‹x <~~> y' @ y''› insert_subset le_sup_iff list.simps(15) set_append)
    by (simp add: fb_less_append)
      
  have B: "distinct y ∧ set y ⊆ internal As"
    using Cons.prems(4) Cons.prems(5) Cons.prems(6) dist_perm perm_set_eq by blast
      
  have [simp]: "set y'' ⊆ internal (fb_less y' (fb_out_less_step a As))"
    apply (subst internal_fb_less, simp_all)
      apply (subst internal_fb_out_less_step, simp_all add: Cons)
    using Cons.prems(4) apply auto[1]
    using A B apply (simp add: subset_Diff_insert)
    using A Cons.prems(5) Cons.prems(6) dist_perm distinct_append apply blast
      apply (subst internal_fb_out_less_step, simp_all add: Cons)
    using Cons.prems(4) apply auto[1]
    using A B by auto
      
  have [simp]: "loop_free (fb_out_less_step a (fb_less y' As))"
  proof -
    have f1: "distinct y"
      using Cons.prems(5) Cons.prems(6) dist_perm by blast
    have "set y ⊆ internal As"
      using Cons.prems(4) Cons.prems(6) perm_set_eq by blast
    then have "loop_free (fb_less (y' @ [a]) As)"
      using f1 by (simp add: A Cons.prems(1) Cons.prems(3) loop_free_fb_less_internal)
    then show "loop_free (fb_out_less_step a (fb_less y' As))"
      by (simp add: fb_less_append)
  qed
      
  show ?case
    apply (simp add: A fb_less_append)
    apply (rule_tac Bs = "fb_less y'' (fb_less y' (fb_out_less_step a As))" in In_Equiv_trans, simp)
     apply (simp add: fb_less_append[THEN sym])
     apply (rule Cons(1), simp_all)
      apply (metis Cons.prems(1) Cons.prems(3) Cons.prems(4) Cons.prems(5) Diff_empty distinct.simps(2) insert_subset internal_fb_out_less_step list.simps(15) subset_Diff_insert)
    using Cons.prems(5) apply auto[1]
    apply (rule In_Equiv_fb_less_cong, simp_all)
      apply (cut_tac In_Equiv_fb_less_Cons, simp add: fb_less_append)
            apply (simp_all add: Cons)
    using Cons.prems(4) apply auto[1]
      using A B apply auto[1]
      apply (metis Cons.prems(5) UnI1 ‹perm x (y' @ y'')› dist_perm distinct.simps(2) distinct_append perm_set_eq set_append)
    by (metis A Cons.prems(5) Cons.prems(6) dist_perm distinct.simps(2) distinct_append)
qed
 
lemma [simp]: "in_equiv □ □"
  apply (simp add: in_equiv_def)
  by (simp add: switch.simps(1))
    
  
lemma in_equiv_Parallel_list: "⋀ Bs . Type_OK Bs ⟹ In_Equiv As Bs ⟹ in_equiv (Parallel_list As) (Parallel_list Bs)"
proof (induction As)
  case Nil
  then show ?case
    by (case_tac Bs, simp_all)
next
  case (Cons a As)
    
  obtain B Bs' where A[simp]: "Bs = B # Bs'"
    using In_Equiv.elims(2) local.Cons(3) by blast
    
  have B: "in_equiv (Parallel_list As) (Parallel_list Bs')"
    apply (rule Cons(1))
    using Cons.prems by auto

  show ?case
    apply simp
    by (metis Cons.prems(1) Cons.prems(2) In_Equiv.simps(2) Type_OK_cons A
        B in_equiv_Parallel io_diagram_parallel_list)        
qed
  
  
thm FB_fb_less
  
lemma [simp]: "io_diagram A ⟹ distinct (VarFB A)"
  by (simp add: VarFB_def)
    
lemma [simp]: "io_diagram A ⟹ distinct (InFB A)"
  by (simp add: InFB_def)
    
theorem fb_perm_eq_Parallel_list:
  assumes [simp]: "Type_OK As"
    and [simp]: "Deterministic As"
    and [simp]: "loop_free As"
    shows "fb_perm_eq (Parallel_list As)"
proof (simp add: fb_perm_eq_def, safe)
  fix x
  assume perm [simp]: "perm x (VarFB (Parallel_list As))"
    
  have length: "length(VarFB (Parallel_list As)) = length x"
    by (metis Permutation.perm_length perm)

  define y where "y = VarFB (Parallel_list As)"
      
  define X where "X = Parallel_list (fb_less x As)"
  define Y where "Y = Parallel_list (fb_less y As)"

      
  have A: "(fb ^^ length x) ([x @ InFB (Parallel_list As) ↝ In (Parallel_list As)] oo Trs (Parallel_list As) 
      oo [Out (Parallel_list As) ↝ x @ OutFB (Parallel_list As)]) 
      = [InFB (Parallel_list As) ↝ In X] oo Trs X"
    and perm_x: "perm (InFB (Parallel_list As)) (In X)"
    apply (subst FB_fb_less, simp_all add: X_def perm_sym)
    by (subst FB_fb_less, simp_all add: X_def perm_sym)
      
  have B: "(fb ^^ length (VarFB (Parallel_list As))) ([VarFB (Parallel_list As) @ InFB (Parallel_list As) ↝ In (Parallel_list As)] 
      oo Trs (Parallel_list As) oo [Out (Parallel_list As) ↝ VarFB (Parallel_list As) @ OutFB (Parallel_list As)]) 
      = [InFB (Parallel_list As) ↝ In Y] oo Trs Y"
    and perm_y: "perm (InFB (Parallel_list As)) (In Y)"
    apply (subst FB_fb_less, simp_all add: Y_def y_def)
    by (subst FB_fb_less, simp_all add: Y_def y_def)
      
  thm In_Equiv_fb_less
    
  have [simp]: "set x ⊆ internal As"
    by (simp add: internal_VarFB)

  have perm[simp]: "perm (VarFB (Parallel_list As)) x"
    by (simp add: perm_sym)

  have "io_diagram (Parallel_list As)"
    using io_diagram_parallel_list assms(1) by blast
      
  from this have "distinct (VarFB (Parallel_list As))"
    by simp
      
  from this have [simp]: "distinct x"
    using perm dist_perm by blast
    

  have [simp]: "In_Equiv (fb_less x As) (fb_less y As)"
    by (rule In_Equiv_fb_less, simp_all add: y_def)
      
      
  have [simp]: "Type_OK (fb_less y As)"
    using Type_OK_fb_less ‹distinct (VarFB (Parallel_list As))› ‹set x ⊆ internal As› ‹y ≡ VarFB (Parallel_list As)› assms(1) assms(3) perm perm_set_eq by blast
      
  have [simp]: "io_diagram Y"
    by (simp add: Y_def io_diagram_parallel_list)
      
  have [simp]: "io_diagram (Parallel_list As)"
    by (simp add: io_diagram_parallel_list)

              
  have "in_equiv (Parallel_list (fb_less x As)) (Parallel_list (fb_less y As))"
    by (subst in_equiv_Parallel_list, simp_all)
     
      
  from this have "perm (In X) (In Y)" and "Trs X = [In X ↝ In Y] oo Trs Y" and "Out X = Out Y"
    by (simp_all add: in_equiv_def X_def [THEN sym] Y_def [THEN sym])
          
      
  from this have "[InFB (Parallel_list As) ↝ In X] oo Trs X = [InFB (Parallel_list As) ↝ In X] oo ([In X ↝ In Y] oo Trs Y)"
    by simp
  also have "... =  ([InFB (Parallel_list As) ↝ In X] oo [In X ↝ In Y]) oo Trs Y"
    by (simp add: comp_assoc)
  also have "... = [InFB (Parallel_list As) ↝  In Y] oo Trs Y"
    apply (subst switch_comp, simp_all add: perm_x)
    by (simp add: ‹perm (In X) (In Y)›)
  
  finally show  "(fb ^^ length (VarFB (Parallel_list As)))
          ([VarFB (Parallel_list As) @ InFB (Parallel_list As) ↝ In (Parallel_list As)] 
          oo Trs (Parallel_list As) oo [Out (Parallel_list As) ↝ VarFB (Parallel_list As) @ OutFB (Parallel_list As)]) =
         (fb ^^ length (VarFB (Parallel_list As))) ([x @ InFB (Parallel_list As) ↝ In (Parallel_list As)] 
          oo Trs (Parallel_list As) oo [Out (Parallel_list As) ↝ x @ OutFB (Parallel_list As)])"
    apply (simp add: B)
    by (simp add: length A)
qed
  

theorem FeedbackSerial_Feedbackless: "io_diagram A ⟹ io_diagram B ⟹ set (In A) ∩ set (In B) = {} ― ‹required›
      ⟹ set (Out A) ∩ set (Out B) = {} ⟹ fb_perm_eq (A ||| B) ⟹ FB (A ||| B) = FB (FB (A) ;; FB (B))"
proof -
  assume [simp]: "io_diagram A"
          assume [simp]: "io_diagram B"
          assume [simp]: "set (In A) ∩ set (In B) = {}"
          assume [simp]: "set (Out A) ∩ set (Out B) = {}"
            
          assume fb_perm_eq: "fb_perm_eq (A ||| B)"
            

          define I where "I ≡ (In (A ||| B)) ⊖ (Var (A ||| B) (A ||| B))"
            
          define O' where "O' ≡ (Out (A ||| B)) ⊖ (Var (A ||| B) (A ||| B))"

          define IA' where "IA' ≡ In A ⊖ Out A ⊖ Out B"
          define IB' where "IB' ≡ In B ⊖ Out A ⊖ Out B"

          define IA'' where "IA'' ≡ In A ⊖ Out A"
          define IB'' where "IB'' ≡ In B ⊖ Out B"

          define OA' where "OA' ≡ Out A ⊖ In A ⊖ In B"
          define OB' where "OB' ≡ Out B ⊖ In A ⊖ In B"
          
          define OA'' where "OA'' ≡ Out A ⊖ In A"
          define OB'' where "OB'' ≡ Out B ⊖ In B"

          have [simp]: "TI (Trs A) = TVs (In A)"
            apply (subgoal_tac "io_diagram A")
            apply (unfold io_diagram_def)[1]
            by simp_all

          have [simp]: "TI (Trs B) = TVs (In B)"
            apply (subgoal_tac "io_diagram B")
            apply (unfold io_diagram_def)[1]
            by simp_all

          have [simp]: "TO (Trs A) = TVs (Out A)"
            apply (subgoal_tac "io_diagram A")
            apply (unfold io_diagram_def)[1]
            by simp_all

          have [simp]: "TO (Trs B) = TVs (Out B)"
            apply (subgoal_tac "io_diagram B")
            apply (unfold io_diagram_def)[1]
            by simp_all

          have I_simp:"I = IA' @ IB'"
            apply (simp add: I_def IA'_def IB'_def Parallel_indep Var_def diff_filter inter_filter)
            apply (subgoal_tac "[a←In A . (a ∈ set (Out A) ⟶ a ∉ set (In A) ∧ a ∉ set (In B)) ∧ (a ∈ set (Out B) ⟶ a ∉ set (In A) ∧ a ∉ set (In B))] = [x←In A . x ∉ set (Out A) ∧ x ∉ set (Out B)]")
            apply simp
            apply (drule drop_assumption, simp)
            apply (rule filter_cong, auto)
            by (rule filter_cong, auto)

          have In_simp: "(In (A ||| B)) ⊖ (Var (A ||| B) (A ||| B)) = IA' @ IB'"
            apply (simp add: IA'_def IB'_def Parallel_indep Var_def diff_filter inter_filter)
            apply (subgoal_tac "[a←In A . (a ∈ set (Out A) ⟶ a ∉ set (In A) ∧ a ∉ set (In B)) ∧ (a ∈ set (Out B) ⟶ a ∉ set (In A) ∧ a ∉ set (In B))] = [x←In A . x ∉ set (Out A) ∧ x ∉ set (Out B)]")
            apply simp
            apply (drule drop_assumption, simp)
            apply (rule filter_cong, auto)
            by (rule filter_cong, auto)

          have O'_simp: "O' = OA' @ OB'"
            by (simp add: O'_def OA'_def OB'_def Parallel_indep Var_def diff_inter_left union_diff diff_union)
            
          have Out_simp: "(Out (A ||| B)) ⊖ (Var (A ||| B) (A ||| B)) = OA' @ OB'" 
            by (simp add: OA'_def OB'_def Parallel_indep Var_def diff_inter_left union_diff diff_union)

          have [simp]: "distinct O'"
            by (simp add: O'_def)

          have [simp]: "distinct I"
            by (simp add: I_def Parallel_indep Var_def)
          

          have [simp]: "distinct IA'"
            by (simp add: IA'_def)

          have [simp]: "distinct IB'"
            by (simp add: IB'_def)

          have [simp]: "TI (Trs (A ||| B)) = TVs (In (A ||| B))"
            by (simp add: Parallel_indep)

          have [simp]: "TO (Trs (A ||| B)) = TVs (Out (A ||| B))"
            by (simp add: Parallel_indep)
          
          have [simp]: "distinct (Out A)"
            apply (subgoal_tac "io_diagram A")
            apply (unfold io_diagram_def)[1]
            by simp_all
 
          have [simp]: "distinct (Out B)"
            apply (subgoal_tac "io_diagram B")
            apply (unfold io_diagram_def)[1]
            by simp_all

          have [simp]: "distinct (Var A A)"
            by (simp add: Var_def )

          have [simp]: "distinct (Var B B)"
            by (simp add: Var_def )

          have [simp]: "distinct (Var A B)"
            by (simp add: Var_def )

          have [simp]: "distinct (Var B A)"
            by (simp add: Var_def )

          have setI: "set I  = set (In A) ∪ set (In B) - (set (Out A) ∪ set (Out B))"
            by (simp add: I_def Parallel_indep Var_def set_diff set_inter, auto)

          have [simp]: "set (Var A A) ∩ set I = {}"
            apply (simp add: Var_def setI set_inter)
            by blast
          have [simp]: "set (Var A B) ∩ set I = {}"
            apply (simp add: Var_def setI set_inter)
            by blast

          have [simp]: "set (Var B A) ∩ set I = {}"
            apply (simp add: Var_def setI set_inter)
            by blast

          have [simp]: "set (Var B B) ∩ set I = {}"
            apply (simp add: Var_def setI set_inter)
            by blast

          have [simp]: "set (Var A B) ∩ set (Var B A) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (Out A) ∩ set (Out B) = {}› by blast

          have [simp]: "set (Var B B) ∩ set (Var A B) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (Out A) ∩ set (Out B) = {}› by blast

          have [simp]: " set (Var B B) ∩ set (Var B A) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (In A) ∩ set (In B) = {}› by blast

          have [simp]: "set (Var A A) ∩ set (Var B B) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (Out A) ∩ set (Out B) = {}› by blast

          have [simp]: "set (Var A A) ∩ set (Var A B) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (In A) ∩ set (In B) = {}› by blast

          have [simp]: "set (Var A A) ∩ set (Var B A) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (Out A) ∩ set (Out B) = {}› by blast

          have [simp]: "set (Var A B) ∩ set (Var B B) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (Out A) ∩ set (Out B) = {}› by blast

          have [simp]: "set (Var B A) ⊆ set (Var B B) ∪ (set (Var A B) ∪ (set (Var B A) ∪ set I))"
            apply (simp add: Var_def set_inter I_def Parallel_def set_diff)
            by blast

          have [simp]: "set (Var A B) ⊆ set (Var B B) ∪ (set (Var A B) ∪ (set (Var B A) ∪ set I))"
            apply (simp add: Var_def set_inter I_def Parallel_def set_diff)
            by blast

          have [simp]: "set IA' ⊆ set (Var B B) ∪ (set (Var A B) ∪ (set (Var B A) ∪ set I))"
            apply (simp add: Var_def set_inter I_def IA'_def Parallel_indep set_diff)
            by blast          

          have [simp]: "set IB' ⊆ set (Var B B) ∪ (set (Var A B) ∪ (set (Var B A) ∪ set I))"
            apply (simp add: Var_def set_inter I_def IB'_def Parallel_indep set_diff)
            by blast 

          have [simp]: "distinct OA'"
            by (simp add: OA'_def )

          have [simp]: "distinct OB'" 
            by (simp add: OB'_def )

          have [simp]: "set (Var B A) ∩ set OB' = {}"
            apply (simp add: Var_def OB'_def set_diff set_inter)
            by blast

          have [simp]: "set (Var B B) ∩ set OB' = {}"
            apply (simp add: Var_def OB'_def set_diff set_inter)
            by blast

          have [simp]: " set OA' ∩ set (Var B B) = {}"
            apply (simp add: Var_def OA'_def set_diff set_inter)
            by blast

          have [simp]: "set OA' ∩ set (Var B A) = {}"
            apply (simp add: Var_def OA'_def set_diff set_inter)
            by blast

          have [simp]: "set OA' ∩ set OB' = {}"
            by (metis O'_simp ‹distinct O'› distinct_append)

          have [simp]: "set (Var A B) ∩ set OA' = {}"
            apply (simp add: Var_def OA'_def set_diff set_inter)
            by blast

          have [simp]: "set (Var A B) ∩ set OB' = {}"
            apply (simp add: Var_def OB'_def set_diff set_inter)
            by blast

          have [simp]: "set (Var A A) ∩ set OA' = {}"
            apply (simp add: Var_def OA'_def set_diff set_inter)
            by blast

          have [simp]: "set (Var A A) ∩ set OB' = {}"
            apply (simp add: Var_def OB'_def set_diff set_inter)
            by blast

          have [simp]: "set (Var B B) ⊆ set (Var A B) ∪ (set OA' ∪ (set (Var B B) ∪ (set (Var B A) ∪ set OB')))"
            apply (simp add: OA'_def OB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (Var B A) ⊆ set (Var A B) ∪ (set OA' ∪ (set (Var B B) ∪ (set (Var B A) ∪ set OB')))"
            apply (simp add: OA'_def OB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set O' ⊆ set (Var A B) ∪ (set OA' ∪ (set (Var B B) ∪ (set (Var B A) ∪ set OB')))"
            apply (simp add: O'_def OA'_def OB'_def Parallel_indep Var_def set_inter set_diff)
            by blast

          have [simp]: "set (Var A B) ∩ set IB' = {}"
            apply (simp add: IB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (Var B B) ∩ set IB' = {}"
            apply (simp add: IB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set IA' ∩ set (Var B B) = {}"
            apply (simp add: IA'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set IA' ∩ set (Var A B) = {}"
            apply (simp add: IA'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set IA' ∩ set IB' = {}"
            apply (simp add: IA'_def IB'_def set_diff)
            apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
            apply blast
            by simp

          have [simp]: "set (Var B A) ∩ set IA' = {}"
            apply (simp add: IA'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (Var B A) ∩ set (Var B B) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (In A) ∩ set (In B) = {}› by blast

          have [simp]: "set (Var B A) ∩ set (Var A B) = {}"
            apply (simp add: Var_def set_inter)
            using ‹set (In A) ∩ set (In B) = {}› by blast

          have [simp]: "set (Var B A) ∩ set IB' = {}"
            apply (simp add: IB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (Var A A) ∩ set IA' = {}"
            apply (simp add: IA'_def Var_def set_inter set_diff)
            by blast
          have [simp]: "set (Var A A) ∩ set IB' = {}"
            apply (simp add: IB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (In A) ⊆ set (Var A A) ∪ (set (Var B A) ∪ set IA')"
            apply (simp add: IA'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (In B) ⊆ set (Var B B) ∪ (set (Var A B) ∪ set IB')"
            apply (simp add: IB'_def Var_def set_inter set_diff)
            by blast

          have [simp]: "set (Var A A) ⊆ set (Out A)"
            by (simp add: Var_def set_inter)

          have [simp]: "set (Var A B) ⊆ set (Out A)"
            by (simp add: Var_def set_inter)

          have [simp]: "set OA' ⊆ set (Out A)"
            apply (simp add: OA'_def set_diff)
            by blast

          have [simp]: "set (Var B B) ⊆ set (Out B)"
            by (simp add: Var_def set_inter)

          have [simp]: "set (Var B A) ⊆ set (Out B)"
            by (simp add: Var_def set_inter)

          have [simp]: "set OB' ⊆ set (Out B)"
            apply (simp add: OB'_def set_diff)
            by blast

          have [simp]: "set OB' ∩ set (Var A A) = {}"
            apply (simp add: OB'_def Var_def set_diff set_inter)
            by blast

          have [simp]: "set OB' ∩ set (Var A B) = {}"
            apply (simp add: OB'_def Var_def set_diff set_inter)
            by blast

          have [simp]: "set OB' ∩ set OA' = {}"
            by (simp add: Int_commute)          

          have [simp]: "set (Var B A) ∩ set (Var A A) = {} "
            by (simp add: Int_commute)          

          have [simp]: "set (Var B A) ∩ set OA' = {}"
            by (simp add: Int_commute)          

          have [simp]: "set (Var B B) ∩ set (Var A A) = {} "
            by (simp add: Int_commute)          

          have [simp]: "set (Var B B) ∩ set OA' = {}"
            by (simp add: Int_commute)          

          have [simp]: "perm (Var B B @ Var A B @ Var B A @ I) (Var B A @ IA' @ Var B B @ Var A B @ IB')"
            by (simp add: I_simp perm_mset union_lcomm)

          have [simp]: "perm (Var B B @ Var B A @ OB' @ Var A B @ OA') (Var A B @ OA' @ Var B B @ Var B A @ OB')"
            by (simp add: perm_mset)

          have [simp]: "set IB' ⊆ set (Var A B) ∪ (set (Var B A) ∪ set I)"
            apply (simp add: I_simp)
            by blast

          have [simp]: "set (Var B A) ⊆ set (Var A B) ∪ (set (Var B A) ∪ set I)"
            by blast

          have [simp]: "set IA' ⊆ set (Var A B) ∪ (set (Var B A) ∪ set I)"
            apply (simp add: I_simp)
            by blast

          have [simp]: "set IB' ⊆ set (Var B A) ∪ set I" 
            apply (simp add: I_simp)
            by blast

          have [simp]: "set IA' ⊆ set (Var B A) ∪ set I"
            apply (simp add: I_simp)
            by blast
          
          have [simp]: "set (Var A B) ⊆ set (Var B A) ∪ (set OB' ∪ (set (Var A B) ∪ set OA'))"
            by blast

          have [simp]: "set O' ⊆ set (Var B A) ∪ (set OB' ∪ (set (Var A B) ∪ set OA'))"
            apply (simp add: O'_simp)
            by safe

          have [simp]: "set IB' ∩ set (Var B A) = {}"
            apply (simp add: IB'_def Var_def set_diff set_inter)
            by blast

          have [simp]: "set IB' ∩ set IA' = {}"
            by (simp add: Int_commute)

          have [simp]: "set (Var A B) ∩ set IA' = {}"
            by (simp add: Int_commute)

          have [simp]: "perm (Var B A @ I) (IB' @ Var B A @ IA')"
            by (simp add: I_simp perm_mset)

          have [simp]: "perm (Var A B @ OA' @ Var B A @ OB') (Var B A @ OB' @ Var A B @ OA')"
            by (metis append_assoc perm_tp)

          have [simp]: "set (Var B A) ⊆ set OA' ∪ (set (Var B A) ∪ set OB')"
            by blast

          have [simp]: "set O' ⊆ set OA' ∪ (set (Var B A) ∪ set OB')"
            apply (simp add: O'_simp)
            by blast

          have [simp]: "set (Var B A) ⊆ set (Var A B) ∪ (set OA' ∪ (set (Var B A) ∪ set OB'))"
            by blast

          have [simp]: "set O' ⊆ set (Var A B) ∪ (set OA' ∪ (set (Var B A) ∪ set OB'))"
            apply (simp add: O'_simp)
            by blast

          have [simp]: "set (Var A B) ∩ set O' = {}"
            by (simp add: O'_simp)

          have [simp]: "set OA' ∩ set IB' = {}"
            apply (simp add: OA'_def IB'_def set_diff)
            by blast

          have [simp]: "set IA'' ⊆ set (Var B A) ∪ set IA'"
            apply (simp add: IA''_def IA'_def set_diff Var_def set_inter)
            by blast

          have [simp]: "perm (Var B A @ IA') IA''"
            proof -
              have A: "perm (((In A ⊖ Out A) ⊗ Out B) @ (In A ⊖ Out A ⊖ Out B)) IA''"
                apply (simp add: IA''_def)
                  using perm_diff_left_inter perm_sym by blast
 
              have B: "((In A ⊖ Out A) ⊗ Out B) = (In A ⊗ Out B)"
                apply (simp add: diff_filter inter_filter)
                apply (subgoal_tac "set (Out A) ∩ set (Out B) = {}")
                apply (metis diff_distinct diff_filter filter_id_conv)
                by simp

              have C: "perm (In A ⊗ Out B) (Out B ⊗ In A)"
                apply (simp add:  perm_mset)
                using ‹distinct (Out B)› ‹io_diagram A› perm_mset perm_switch_aux_d io_diagram_def
                  by metis

              have D: "perm (((In A ⊖ Out A) ⊗ Out B) @ (In A ⊖ Out A ⊖ Out B)) ((Out B ⊗ In A) @ (In A ⊖ Out A ⊖ Out B))"
                by (simp add: B C perm_union_left)

              have E: "perm ((Out B ⊗ In A) @ (In A ⊖ Out A ⊖ Out B)) (((In A ⊖ Out A) ⊗ Out B) @ (In A ⊖ Out A ⊖ Out B))"
                by (simp only: D perm_sym)

              show "perm (Var B A @ IA') IA''"
                apply (simp add: Var_def IA'_def)
                apply (subgoal_tac "perm ((Out B ⊗ In A) @ (In A ⊖ Out A ⊖ Out B)) (((In A ⊖ Out A) ⊗ Out B) @ (In A ⊖ Out A ⊖ Out B))")
                 apply (subgoal_tac "perm (((In A ⊖ Out A) ⊗ Out B) @ (In A ⊖ Out A ⊖ Out B)) IA''")
                  using perm_trans apply blast
                by (simp_all only: E A )
            qed

          have [simp]: "perm (Var A B @ OA') OA''"
            proof -
              have A: "perm (((Out A ⊖ In A) ⊗ In B) @ (Out A ⊖ In A ⊖ In B)) OA''"
                apply (simp add: OA''_def)
                  using perm_diff_left_inter perm_sym by blast

              have B: "((Out A ⊖ In A)) ⊗ In B = (Out A ⊗ In B)"
                apply (simp add: diff_filter inter_filter)
                apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
                apply (metis diff_distinct diff_filter filter_id_conv)
                by simp
              have C: "perm ((Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B)) OA''"
                apply (subgoal_tac "perm (((Out A ⊖ In A) ⊗ In B) @ (Out A ⊖ In A ⊖ In B)) OA''")
                apply (subgoal_tac "((Out A ⊖ In A)) ⊗ In B = (Out A ⊗ In B)")
                apply auto
                apply (simp only: B)
                by (simp only: A)
              show "perm (Var A B @ OA') OA''"
                by (simp add: Var_def OA'_def C)
            qed           

          have [simp]: "perm (OA' @ Var A B) OA''"
            apply (subgoal_tac "perm (Var A B @ OA') OA''")
            apply (metis perm_mset perm_tp)
            by simp

          have [simp]: "perm (Out A) (Var A A @ OA'')"
            apply (simp add: OA''_def Var_def )
            using ‹io_diagram A› perm_switch_aux_c perm_sym io_diagram_def by blast

          have [simp]: "distinct OA''"
            by (simp add: OA''_def)

          have [simp]: "set (Var A A) ∩ set OA'' = {}"
            apply (simp add: OA''_def Var_def set_diff set_inter)
            by blast

          have [simp]: "set (Var A B) ⊆ set OA''"
            apply (simp add: OA''_def Var_def set_diff set_inter)
            by (simp add: Diff_Int_distrib2 inf.absorb_iff2 inf.left_commute)

         have [simp]: "set OA' ⊆ set OA''"
           by (simp add: OA'_def OA''_def set_diff)

         have [simp]: "perm (Var A B @ IB') IB''"
            proof -
              have A: "perm (((In B ⊖ Out B) ⊗ Out A) @ (In B ⊖ Out B ⊖ Out A)) IB''"
                apply (simp add: IB''_def)
                  using perm_diff_left_inter perm_sym by blast

              have B: "perm (((In B ⊖ Out B) ⊗ Out A) @ (In B ⊖ Out A ⊖ Out B)) IB''"
                apply (subst diff_sym)
                by (simp add: A)
 
              have C: "((In B ⊖ Out B) ⊗ Out A) = (In B ⊗ Out A)"
                apply (simp add: diff_filter inter_filter)
                apply (subgoal_tac "set (Out A) ∩ set (Out B) = {}")
                apply (metis diff_distinct diff_filter filter_id_conv)
                by simp

              have D: "perm (In B ⊗ Out A) (Out A ⊗ In B)"
                apply (simp add: perm_mset)
                apply (subgoal_tac "distinct (Var A B)")
                apply (subgoal_tac "io_diagram B")
                apply (simp only: Var_def io_diagram_def)
                apply (metis Int_commute distinct_inter set_eq_iff_mset_eq_distinct set_inter)
                by simp_all

              have E: "perm (((In B ⊖ Out B) ⊗ Out A) @ (In B ⊖ Out A ⊖ Out B)) ((Out A ⊗ In B) @ (In B ⊖ Out A ⊖ Out B))"
                by (simp add: B C D perm_union_left)

              have F: "perm ((Out A ⊗ In B) @ (In B ⊖ Out A ⊖ Out B)) (((In B ⊖ Out B) ⊗ Out A) @ (In B ⊖ Out A ⊖ Out B))"
                by (simp only: E perm_sym)

              show "perm (Var A B @ IB') IB''"
                apply (simp add: Var_def IB'_def)
                apply (subgoal_tac "perm ((Out A ⊗ In B) @ (In B ⊖ Out A ⊖ Out B)) (((In B ⊖ Out B) ⊗ Out A) @(In B ⊖ Out A ⊖ Out B))")
                 apply (subgoal_tac "perm (((In B ⊖ Out B) ⊗ Out A) @ (In B ⊖ Out A ⊖ Out B)) IB''")
                  using perm_trans apply blast
                by (simp_all only: F B)
            qed

         have [simp]: "perm (Out B) (Var B B @ OB'')"
           apply (simp add: OB''_def Var_def)
             by (metis diff_inter_left mset_inter_diff perm_mset union_code)

         have [simp]: "perm (OA'' @ IB') (Var A B @ OA' @ IB')"
            by (metis perm_union_left ‹perm (Var A B @ OA') OA''› append_assoc perm_sym)

         have [simp]: "perm (OA'' @ IB') (OA' @ Var A B @ IB')"
            by (metis perm_union_left ‹perm (OA' @ Var A B) OA''› append_assoc perm_sym)

         have [simp]: "perm (Var B A @ OB') OB''"
            proof -
              have A: "perm (((Out B ⊖ In B) ⊗ In A) @ (Out B ⊖ In B ⊖ In A)) OB''"
                apply (simp add: OB''_def )
                  using perm_diff_left_inter perm_sym by blast
              have B: "(Out B ⊖ In B) ⊗ In A = (Out B ⊗ In A)"
                apply (simp add: diff_filter inter_filter)
                apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
                apply (metis diff_distinct diff_filter filter_id_conv)
                by simp
              have C: "perm ((Out B ⊗ In A) @ (Out B ⊖ In B ⊖ In A)) OB''"
                apply (subgoal_tac "perm (((Out B ⊖ In B) ⊗ In A) @ (Out B ⊖ In B ⊖ In A)) OB''")
                apply (subgoal_tac "(Out B ⊖ In B) ⊗ In A = (Out B ⊗ In A)")
                apply (simp add: diff_filter inter_filter)
                apply (simp only: B)
                by (simp only: A)
              show "perm  (Var B A @ OB') OB''"
                apply (simp add: Var_def OB'_def)
                apply (subst diff_sym)
                by (simp add: C)
            qed 

         have [simp]: "perm (Out A @ Out B) ((Out A ⊗ In A) @ (Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B) @ (Out B ⊗ In B) @ (Out B ⊗ In A) @ (Out B ⊖ In A ⊖ In B))"
            proof -
              have A: "perm (Out A) ((Out A ⊗ In A) @ (Out A ⊖ In A))"
                by (metis OA''_def Var_def ‹perm (Out A) (Var A A @ OA'')›)
              have B: "perm (Out A ⊖ In A) (((Out A ⊖ In A) ⊗ In B) @ (Out A ⊖ In A ⊖ In B))"
                using perm_diff_left_inter by blast
              have C: "((Out A ⊖ In A) ⊗ In B) = (Out A ⊗ In B)"
                apply (simp add: diff_filter inter_filter)
                apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
                apply (metis diff_distinct diff_filter filter_id_conv)
                by simp
              have D: "perm (Out A ⊖ In A) ((Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B))"
                apply (subgoal_tac "perm (Out A ⊖ In A) (((Out A ⊖ In A) ⊗ In B) @ (Out A ⊖ In A ⊖ In B))")
                 apply (subgoal_tac "((Out A ⊖ In A) ⊗ In B) = (Out A ⊗ In B)")
                  apply simp
                apply (simp only: C)
                by (simp only: B)
              
              have E: "perm (Out A)  ((Out A ⊗ In A) @ (Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B))"
                apply (subgoal_tac "perm (Out A) ((Out A ⊗ In A) @ (Out A ⊖ In A))")
                 apply (subgoal_tac "perm (Out A ⊖ In A) ((Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B))")
                  apply (metis perm_mset union_code)
                apply (simp only: D)
                by (simp only: A)

              have F: "perm (Out B) ((Out B ⊗ In B) @ (Out B ⊖ In B))"
                by (metis OB''_def Var_def ‹perm (Out B) (Var B B @ OB'')›)
              have G: "perm (Out B ⊖ In B) (((Out B ⊖ In B) ⊗ In A) @ (Out B ⊖ In A ⊖ In B))"
                by (metis diff_sym perm_diff_left_inter)
              have H: "((Out B ⊖ In B) ⊗ In A) = (Out B ⊗ In A)"
                apply (simp add: diff_filter inter_filter)
                apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
                apply (metis diff_distinct diff_filter filter_id_conv)
                by simp
              have I: "perm (Out B ⊖ In B) ((Out B ⊗ In A) @ (Out B ⊖ In A ⊖ In B))"
                apply (subgoal_tac "perm (Out B ⊖ In B) (((Out B ⊖ In B) ⊗ In A) @ (Out B ⊖ In A ⊖ In B))")
                 apply (subgoal_tac "((Out B ⊖ In B) ⊗ In A) = (Out B ⊗ In A)")
                  apply simp
                apply (simp only: H)
                by (simp only: G)
              
              have J: "perm (Out B)  ((Out B ⊗ In B) @ (Out B ⊗ In A) @ (Out B ⊖ In A ⊖ In B))"
                apply (subgoal_tac "perm (Out B) ((Out B ⊗ In B) @ (Out B ⊖ In B))")
                 apply (subgoal_tac "perm (Out B ⊖ In B) ((Out B ⊗ In A) @ (Out B ⊖ In A ⊖ In B))")
                  apply (metis perm_mset union_code)
                apply (simp only: I)
                by (simp only: F)
             
             show "perm (Out A @ Out B) ((Out A ⊗ In A) @ (Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B) @ (Out B ⊗ In B) @ (Out B ⊗ In A) @ (Out B ⊖ In A ⊖ In B))"
              apply (subgoal_tac "perm (Out A)  ((Out A ⊗ In A) @ (Out A ⊗ In B) @ (Out A ⊖ In A ⊖ In B))")
                apply (subgoal_tac "perm (Out B)  ((Out B ⊗ In B) @ (Out B ⊗ In A) @ (Out B ⊖ In A ⊖ In B))")
                 apply (metis append.assoc perm_mset union_code)
              apply (simp only: J)
              by (simp only: E)
          qed

         have [simp]: "set IB'' ⊆ set (Var A B) ∪ set IB'"
            apply (simp add: IB''_def IB'_def set_diff Var_def set_inter)
            by blast

         have [simp]: "distinct OB''"
            by (simp add: OB''_def)

         have [simp]: "set (Var B B) ∩ set OB'' = {}"
            apply (simp add: Var_def OB''_def set_inter set_diff)
            by blast

         have [simp]: "set (Var B A) ⊆ set OB''"
            apply (simp add: Var_def OB''_def set_inter set_diff)
            by (metis (no_types, hide_lams) Diff_Diff_Int Diff_Int_distrib Diff_eq_empty_iff Int_commute ‹set (In A) ∩ set (In B) = {}› equalityI inf.cobounded2)
         
         have [simp]: "set OB' ⊆ set OB''"
            apply (simp add: OB'_def OB''_def)
            by (metis DiffE DiffI set_diff subsetI)


         have IA''_simp: "IA'' = (In A ⊖ Var A A)"
            by (simp add: IA''_def Var_def diff_inter_right)

         have OA''_simp: "OA'' = (Out A ⊖ Var A A)"
            by (simp add: OA''_def Var_def diff_inter_left)

         have IB''_simp: "IB'' = (In B ⊖ Var B B)"
            by (simp add: IB''_def Var_def diff_inter_right)

         have OB''_simp: "OB'' = (Out B ⊖ Var B B)"
            by (simp add: OB''_def Var_def diff_inter_left)

         have [simp]: "TI (Trs (FB A)) = TVs IA''"
            apply (simp add: FB_def Let_def IA''_simp)
            apply (cut_tac t="TVs (Var A A)" and ts="TVs(In A ⊖ Var A A)" and ts'="TVs(Out A ⊖ Var A A)" and
                S="([Var A A @ (In A ⊖ Var A A) ↝ In A] oo Trs A oo [Out A ↝ Var A A @ (Out A ⊖ Var A A)])" in  TI_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var A A)) = length (Var A A)")
            by (simp_all)

         have [simp]: "TO (Trs (FB A)) = TVs OA''"
            apply (simp add: FB_def Let_def OA''_simp)
            apply (cut_tac t="TVs (Var A A)" and ts="TVs(In A ⊖ Var A A)" and ts'="TVs(Out A ⊖ Var A A)" and
                S="([Var A A @ (In A ⊖ Var A A) ↝ In A] oo Trs A oo [Out A ↝ Var A A @ (Out A ⊖ Var A A)])" in  TO_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var A A)) = length (Var A A)")
            by simp_all

         have [simp]: "set OA'' ∩ set IB' = {}"
            apply (simp add: OA''_def IB'_def set_diff)
            by blast

         have [simp]: "TI (Trs (FB B)) = TVs IB''"
            apply (simp add: FB_def Let_def IB''_simp)
            apply (cut_tac t="TVs (Var B B)" and ts="TVs(In B ⊖ Var B B)" and ts'="TVs(Out B ⊖ Var B B)" and
                S="([Var B B @ (In B ⊖ Var B B) ↝ In B] oo Trs B oo [Out B ↝ Var B B @ (Out B ⊖ Var B B)])" in  TI_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var B B)) = length (Var B B)")
            apply (simp)
            by (simp add: )

         have [simp]: "TO (Trs (FB B)) = TVs OB''"
            apply (simp add: FB_def Let_def OB''_simp)
            apply (cut_tac t="TVs (Var B B)" and ts="TVs(In B ⊖ Var B B)" and ts'="TVs(Out B ⊖ Var B B)" and
                S="([Var B B @ (In B ⊖ Var B B) ↝ In B] oo Trs B oo [Out B ↝ Var B B @ (Out B ⊖ Var B B)])" in  TO_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var B B)) = length (Var B B)")
            apply (simp)
            by (simp add: )

         have legth_Var_Parralel: "length (Var (A ||| B) (A ||| B)) = length (Var B A) + length (Var A B) + length (Var B B) + length (Var A A)"
            apply (simp add: Parallel_indep Var_def append_inter)
            apply (subgoal_tac "perm (Out A ⊗ In A @ In B) ((Out A ⊗ In A) @ (Out A ⊗ In B))")
            apply (simp add: perm_length)
            apply (subgoal_tac "perm (Out B ⊗ In A @ In B) ((Out B ⊗ In A) @ (Out B ⊗ In B))")
            apply (simp add: perm_length)
            apply (simp add: inter_append)
            by (simp add: inter_append)

          have [simp]: "TI ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) = TVs (Var B A) @ TVs IA'"
            apply (cut_tac t="(TVs (Var A A))" and S="[Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']" and ts="TVs(Var B A @ IA')" and ts'="TVs(Var A B @ OA')" in TI_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var A A)) = length (Var A A)")
            by (simp_all)

          have [simp]: "TO ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) = TVs (Var A B) @ TVs OA'"
            apply (cut_tac t="(TVs (Var A A))" and S="[Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']" and ts="TVs(Var B A @ IA')" and ts'="TVs(Var A B @ OA')" in TO_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (Var A A) = length (TVs (Var A A))")
              using TVs_append apply presburger
            by (simp add: TO_fb)

          have [simp]: "TI ((fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])) = TVs (Var A B) @ TVs IB'"
            apply (cut_tac t="(TVs (Var B B))" and S="[Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']" and ts="TVs(Var A B @ IB')" and ts'="TVs(Var B A @ OB')" in TI_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (Var B B) = length (TVs (Var B B))")
              using TVs_append apply presburger
            by (simp add: TO_fb)
          
          have [simp]: "TO ((fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])) = TVs (Var B A) @ TVs OB'"
            apply (cut_tac t="(TVs (Var B B))" and S="[Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']" and ts="TVs(Var A B @ IB')" and ts'="TVs(Var B A @ OB')" in TO_fb_fbtype_n)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (Var B B) = length (TVs (Var B B))")
              using TVs_append apply presburger
            by (simp add: TO_fb)

          have [simp]: "set OA' ∩ set (Var A B) = {}"
            apply (simp add: OA'_def Var_def set_diff set_inter)
            by blast

          have [simp]: "set OA' ∩ set OB'' = {}"
            apply (simp add: OA'_def OB''_def set_diff)
            by (simp add: Diff_Int_distrib inf.commute)

          have In_FB_A_simp: "In (FB A) = IA''"
            by (simp add: FB_def Let_def Var_def IA''_def diff_inter_left diff_inter_right)

          have Out_FB_A_simp: "Out (FB A) = OA''"
            by (simp add: FB_def Let_def Var_def OA''_def diff_inter_left diff_inter_right)

          have In_FB_B_simp: "In (FB B) = IB''"
            by (simp add: FB_def Let_def Var_def IB''_def diff_inter_left diff_inter_right)

          have Out_FB_B_simp: "Out (FB B) = OB''"
            by (simp add: FB_def Let_def Var_def OB''_def diff_inter_left diff_inter_right)

          have [simp]: "(IB'' ⊖ Var (FB A) (FB B)) = IB'"
            apply (simp add: FB_def Let_def Var_def IB''_def IB'_def diff_inter_right diff_inter_left)
            apply (subst diff_sym)
            apply (subst diff_notin)
            by (simp_all add: Int_commute)

          have [simp]:"(OA'' ⊖ Var (FB A) (FB B)) = OA'"
            apply (simp add: FB_def Let_def Var_def OA''_def OA'_def diff_inter_right diff_inter_left)
            apply (subst diff_notin)
            apply (simp add: set_diff)
            apply (subgoal_tac "set (Out A) ∩ set (Out B) = {}")
            apply blast
            by simp_all

          have[simp]: "set IA'' ∩ set IB' = {}"
            apply (simp add: IA''_def IB'_def set_diff)
            apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
            apply blast
            by simp

          have [simp]: "IA'' ⊕ IB' = IA'' @ IB'"
            by (simp add: addvars_distinct)

          have [simp]: "distinct IA''"
            by (simp add: IA''_def)

          have [simp]: "Trs (FB A) ∥ ID (TVs IB') oo [OA''@ IB' ↝ OA' @ IB''] oo ID (TVs OA') ∥ Trs (FB B) = Trs (FB (A) ;; FB (B))"
            apply (simp add: Comp_def Let_def In_FB_A_simp Out_FB_A_simp In_FB_B_simp Out_FB_B_simp)
            by (simp add: distinct_id)
         
          have In_FB_simp: "In (FB A ;; FB B) = IA'' @ IB'"
            by (simp add: Comp_def In_FB_A_simp Out_FB_A_simp In_FB_B_simp Out_FB_B_simp)

          have Out_FB_simp: "Out (FB A ;; FB B) = OA' @ OB''"
            by (simp add: Comp_def In_FB_A_simp Out_FB_A_simp In_FB_B_simp Out_FB_B_simp)

          have Var_FB_simp: "(Var (FB A ;; FB B) (FB A ;; FB B)) = Var B A"
            apply (simp add: Var_def In_FB_simp Out_FB_simp)
            apply (simp add: append_inter)
            apply (simp add: OA'_def OB''_def IA''_def IB'_def)
            apply (subgoal_tac "((Out A ⊖ In A ⊖ In B) ⊗ (In A ⊖ Out A) @ (In B ⊖ Out A ⊖ Out B)) = []")
            apply simp
            apply (subgoal_tac "(Out B ⊖ In B) ⊗ (In A ⊖ Out A) @ (In B ⊖ Out A ⊖ Out B) = (Out B ⊖ In B) ⊗ (In A ⊖ Out A)")
            apply simp
            apply (subst inter_diff_distrib)
            apply (subgoal_tac "Out B ⊗ (In A ⊖ Out A) = (Out B ⊗ In A)")
            apply simp
            apply (subgoal_tac "In B ⊗ (In A ⊖ Out A) =[]")
            apply (simp)
            apply (subgoal_tac "set (In B) ∩ set(In A) = {}")
            apply (simp add: empty_inter_diff)
            apply (simp add: Int_commute)
            apply (subgoal_tac "set (Out B) ∩ set (Out A) = {}")
            apply (subst inter_diff_empty)
            apply simp
            apply simp
            apply (simp add: Int_commute)
            apply (subst inter_addvars_empty)
            apply (simp add: set_diff)
            apply blast
            apply simp
            apply (subst empty_inter)
            apply (simp add: set_diff)
            apply blast
            by simp

          have [simp]: "(IA'' @ IB' ⊖ Var (FB A ;; FB B) (FB A ;; FB B)) = IA' @ IB'"
            apply (simp only: Var_FB_simp)
            apply (simp add: Var_def IA''_def IB'_def IA'_def)
            apply (simp add: union_diff)
            apply (subst diff_sym)
            apply (simp add: diff_inter_right)
            apply (subst diff_sym)
            apply (subst(5) diff_disjoint)
            apply (simp add: set_diff set_inter)
            apply blast
            by simp

          have [simp]: "(In (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B)) = IA' @ IB'"
            by (simp add: In_FB_simp)

          have [simp]: "(OA' @ OB'' ⊖ Var (FB A ;; FB B) (FB A ;; FB B)) = O'"
            apply (simp only: Var_FB_simp Out_FB_simp)
            apply (simp add: OA'_def OB''_def Var_def O'_simp OB'_def)
            apply (simp add: union_diff)
            apply (subgoal_tac "set (Out A) ∩ set (Out B) = {}")
            apply (subst diff_inter_empty)
            apply (simp only: set_diff)
            apply blast
            apply (subst(2) diff_sym)
            apply (subst diff_inter_left)
            by simp_all

          have [simp]: "(Out (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B)) = O'"
            by (simp add: Out_FB_simp)
   

          have aa: "perm ((((Var A A @ Var B B) @ Var A B) @ Var B A) @ I) (Var (A ||| B) (A ||| B) @ I)"
            apply (subgoal_tac "perm (((Var A A @ Var B B) @ Var A B) @ Var B A) (Var (A ||| B) (A ||| B))")
            apply (subst perm_union_left)
            apply simp_all
            apply (subgoal_tac "io_diagram A")
            apply (subgoal_tac "io_diagram B")
            apply (subgoal_tac "set (In A) ∩ set (In B) = {}")
            apply (simp add: perm_var_Par perm_sym)
            by simp_all

         
          have FB_Par_A_B: "FB (A ||| B) = 
            ⦇In = I, Out = O', Trs = (fb ^^ length (Var (A ||| B) (A ||| B))) ([Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] 
            oo Trs (A ||| B) oo [Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O'])  ⦈"
            (is "_ = ⦇In=I,Out=O',Trs = ?T⦈")

            by (simp add: FB_def Let_def I_def O'_def) 
              
          thm fb_perm_eq
          thm I_def
            
            have "[(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ Var (A ||| B) (A ||| B) @ I] oo 
              ([Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O']) oo
              [Var (A ||| B) (A ||| B) @ O' ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O']
            = [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ Var (A ||| B) (A ||| B) @ I] oo 
              [Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo ([Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O'] oo
              [Var (A ||| B) (A ||| B) @ O' ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'])"
              by (simp add: comp_assoc [THEN sym]) 
            also have "... = [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ Var (A ||| B) (A ||| B) @ I] oo 
              [Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O']"
                  apply (subgoal_tac "[Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O'] oo
              [Var (A ||| B) (A ||| B) @ O' ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'] = [Out (A ||| B) ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O']")
                   apply simp
                  apply (subst switch_comp, simp_all)
                   apply (metis BaseOperationFeedbacklessVars.Parallel_def BaseOperationFeedbacklessVars.Var_def BaseOperationFeedbacklessVars_axioms O'_def mset_inter_diff perm_mset simps(2) union_code)
                  by (simp add: O'_def Var_def  set_addvars set_diff set_inter, auto)
                    
                also have "... = [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O']"
                  apply (subgoal_tac " [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ Var (A ||| B) (A ||| B) @ I] oo 
              [Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] = [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ In (A ||| B)]")
                   apply simp
                  apply (subst switch_comp, simp_all)
                  using aa apply auto[1]
                  by (simp add: I_def Var_def  set_addvars set_diff set_inter)
                    
                    
                    
                    
                finally have ZZZ: "[(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ Var (A ||| B) (A ||| B) @ I] 
                oo ([Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O']) oo
              [Var (A ||| B) (A ||| B) @ O' ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'] =
              [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'] "
             by simp
                    
                    
                 
                
            
          from fb_perm_eq have fb_perm_eq_a: "⋀ x . perm x (VarFB (A ||| B)) ⟹ (fb ^^ length (VarFB (A ||| B))) ([VarFB (A ||| B) @ InFB (A ||| B) ↝ In A ⊕ In B] oo Trs (A ||| B) oo [Out A @ Out B ↝ VarFB (A ||| B) @ OutFB (A ||| B)]) =
        (fb ^^ length (VarFB (A ||| B))) ([x @ InFB (A ||| B) ↝ In A ⊕ In B] oo Trs (A ||| B) oo [Out A @ Out B ↝ x @ OutFB (A ||| B)]) "
            by (simp add: fb_perm_eq_def )
             
          have "?T = (fb ^^ length (Var (A ||| B) (A ||| B))) (
              [(Var A A @ Var B B @ Var A B @ Var B A) @ I ↝ Var (A ||| B) (A ||| B) @ I] oo 
              ([Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O']) oo
              [Var (A ||| B) (A ||| B) @ O' ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'] )" (is "_ = ?Fb (?Sa oo (?Sb oo ?Tr oo ?Sc) oo ?Sd)")
            apply (subst ZZZ)
            apply (cut_tac fb_perm_eq_a[of "Var A A @ Var B B @ Var A B @ Var B A"])
             apply (simp add: O'_def I_def OutFB_def VarFB_def InFB_def)
              by (metis VarFB_def aa append_assoc perm_append2_eq)

          also have "... = ?Fb ((?Sa oo ?Sb) oo ?Tr oo (?Sc oo ?Sd))"
            apply (rule_tac f = "?Fb" in arg_cong)
            by (simp add: comp_assoc)
          also have "... = ?Fb ([(Var A A @ Var B B @ Var A B @ Var B A) @ I  ↝ In (A ||| B)] oo ?Tr oo [Out (A ||| B) ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'])"
            apply (subst switch_comp, simp_all)
            apply (unfold append_assoc [THEN sym])
            apply (simp only: aa)
            apply (simp add: Var_def Parallel_def set_addvars set_inter)
            apply auto [1]
            
              apply (simp add: setI)
              apply (simp add: setI)
              apply (simp add: perm_var_Par [THEN perm_sym])
            apply (subst switch_comp, simp_all add: Var_def set_inter setI Parallel_def O'_def)
              apply (metis (no_types, lifting) mset_inter_diff perm_mset union_code)
            by (auto simp add: set_addvars set_diff set_inter)
          also have "... = ?Fb ([Var A A @ Var B B @ Var A B @ Var B A @ I  ↝ In A @ In B] oo ?Tr oo [Out A @ Out B ↝ Var A A @ Var B B @ Var A B @ Var B A @ O'])" (is "?Lhs = ?Fc ?SS")
            by (simp add: Parallel_indep)
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) ((fb ^^ length (Var B B)) ((fb ^^ length (Var A A)) 
               ([Var A A @ Var B B @ Var A B @ Var B A @ I  ↝ In A @ In B] oo ?Tr oo [Out A @ Out B ↝ Var A A @ Var B B @ Var A B @ Var B A @ O']))))"
            apply (simp add: legth_Var_Parralel)
            by (simp add: funpow_add)
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) ((fb ^^ length (Var B B)) ((fb ^^ length (Var A A)) 
               (([Var A A ↝ Var A A] ∥ [Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB'] oo  [Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB'  ↝ In A @ In B]) 
               oo ?Tr oo [Out A @ Out B ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O']))))"
            apply (subgoal_tac "[Var A A @ Var B B @ Var A B @ Var B A @ I ↝ In A @ In B] = [Var A A ↝ Var A A] ∥ [Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB'] oo  [Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB'  ↝ In A @ In B]")
            apply simp
            apply (subst par_switch)
            apply (simp_all)
            apply (subst switch_comp)
            apply (simp_all add: perm_union_right)
            by (simp add: Var_def set_inter IB'_def set_diff IA'_def, auto)
            
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) ((fb ^^ length (Var B B)) ((fb ^^ length (Var A A)) 
               (([Var A A ↝ Var A A] ∥ [Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB'] oo  [Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB'  ↝ In A @ In B]) 
               oo ?Tr oo ([Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB'] oo [Var A A ↝ Var A A] ∥ [Var A B @ OA' @ Var B B @ Var B A @ OB' ↝ Var B B @ Var A B @ Var B A @ O']) )))) "
            apply (subgoal_tac "[Out A @ Out B ↝ (Var A A @ Var B B @ Var A B @ Var B A) @ O'] = [Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB'] oo [Var A A ↝ Var A A] ∥ [Var A B @ OA' @ Var B B @ Var B A @ OB' ↝ Var B B @ Var A B @ Var B A @ O']")
            apply simp
            apply (subst par_switch)
            apply (simp_all)
            apply (subst switch_comp)
            apply (simp_all)
            apply (simp add: Var_def OA'_def OB'_def)
            by (simp add: Var_def set_inter IB'_def set_diff IA'_def OB'_def OA'_def O'_def Parallel_def, auto)
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) ((fb ^^ length (Var B B)) ((fb ^^ length (Var A A)) 
               ([Var A A ↝ Var A A] ∥ [Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB'] oo  ([Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB'  ↝ In A @ In B] 
               oo ?Tr oo [Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB']) oo [Var A A ↝ Var A A] ∥ [Var A B @ OA' @ Var B B @ Var B A @ OB' ↝ Var B B @ Var A B @ Var B A @ O']) ))) "
            apply (subst comp_assoc[THEN sym])
            apply (simp add:   Parallel_indep)
            using Parallel_indep TO_comp ‹TI (Trs (A ||| B)) = TVs (In (A ||| B))› ‹TO (Trs (A ||| B)) = TVs (Out (A ||| B))› apply auto[1]
            apply (subst comp_assoc)
              apply simp_all
              apply (simp add: addvars_def diff_distinct)
            apply (simp add: Parallel_indep)
            apply (subst comp_assoc)
            by (simp_all)
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) ((fb ^^ length (Var B B)) ((fb ^^ length (Var A A)) 
               (ID (TVs (Var A A)) ∥ [Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB'] oo  ([Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB'  ↝ In A @ In B] 
               oo ?Tr oo [Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB']) oo ID (TVs (Var A A)) ∥ [Var A B @ OA' @ Var B B @ Var B A @ OB' ↝ Var B B @ Var A B @ Var B A @ O']) ))) "
            apply (subst distinct_id)
            apply simp_all
            apply (subst distinct_id)
            by simp_all
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) ((fb ^^ length (Var B B)) (
              [Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB'] oo
                ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB'  ↝ In A @ In B] 
                  oo ?Tr oo [Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB'])) oo 
               [Var A B @ OA' @ Var B B @ Var B A @ OB' ↝ Var B B @ Var A B @ Var B A @ O']) ))" (is "_ = ?Fc (?Sf oo _ oo ?Sh)")
            apply (cut_tac A= "[Var B B @ Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var B B @ Var A B @ IB']" and B = "[Var A B @ OA' @ Var B B @ Var B A @ OB' ↝ Var B B @ Var A B @ Var B A @ O']" and tsa = "TVs (Var A A)"
              and S="([Var A A @ Var B A @ IA' @ Var B B @ Var A B @ IB' ↝ In A @ In B] oo Trs (A ||| B) oo [Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB'])" in fb_indep)
            apply (simp add: fbtype_def)
            apply safe
            by (simp_all add: Parallel_indep)
          also have "... = ?Fc (?Sf oo (
                (fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] ∥ [Var B B @ Var A B @ IB'  ↝ In B]  oo ?Tr oo [Out A @ Out B ↝ Var A A @ Var A B @ OA' @ Var B B @ Var B A @ OB'])) 
              oo ?Sh)"
            apply (subst par_switch)
            by simp_all 
          also have "... = ?Fc (?Sf oo (
                (fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] ∥ [Var B B @ Var A B @ IB'  ↝ In B]  oo ?Tr oo [Out A ↝ Var A A @ Var A B @ OA'] ∥ [Out B ↝ Var B B @ Var B A @ OB']))
              oo ?Sh)"
            apply (subst(3) par_switch)
            by simp_all
          also have "... = ?Fc (?Sf oo (
                (fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] ∥ [Var B B @ Var A B @ IB'  ↝ In B]  oo (Trs A ∥ Trs B) oo [Out A ↝ Var A A @ Var A B @ OA'] ∥ [Out B ↝ Var B B @ Var B A @ OB']))
              oo ?Sh)"
            by (simp add: Parallel_indep)
          also have "... = ?Fc (?Sf oo (
                (fb ^^ length (Var A A)) (([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']) ∥ ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])))
              oo ?Sh)"  
            by (simp add: comp_parallel_distrib)
          also have "... = ?Fc (?Sf oo 
                ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) ∥ ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])
              oo ?Sh)"
            apply (cut_tac S="[Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']" and T="[Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']" 
              and tsa= "TVs (Var A A)" and ts="TVs (Var B A @ IA')" and ts'="TVs(Var A B @ OA')" in fb_gen_parallel)
            apply (simp add: fbtype_def )
            apply (subgoal_tac "length (Var A A)= length (TVs (Var A A))")
              apply presburger
            by simp
          also have "... = ?Fc (?Sf oo 
                ( [Var B A @ IA' @ Var B B @ Var A B @ IB' ↝ Var B B @ Var A B @ IB' @ Var B A @ IA'] oo
                  ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  [Var B B @ Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ OA' @ Var B B @ Var B A @ OB']
                )
              oo ?Sh)"
            apply (cut_tac x="Var B A @ IA'" and y="Var B B @ Var A B @ IB'" and u="Var B B @ Var B A @ OB'" and v="Var A B @ OA'" and 
              S="((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']))" and 
              T="([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])" in switch_par)
            by (simp_all)
          also have "... = ?Fc 
                ( (?Sf oo [Var B A @ IA' @ Var B B @ Var A B @ IB' ↝ Var B B @ Var A B @ IB' @ Var B A @ IA']) oo
                  ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  ([Var B B @ Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ OA' @ Var B B @ Var B A @ OB'] oo ?Sh) )"
            by (simp add: comp_assoc_middle_ext)
          also have "... = ?Fc 
                ( [Var B B @ Var A B @ Var B A @ I ↝ Var B B @ Var A B @ IB' @ Var B A @ IA'] oo
                  ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  ([Var B B @ Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ OA' @ Var B B @ Var B A @ OB'] oo ?Sh) )"
            apply (subst switch_comp)
            apply (simp_all)
            by (auto simp add: IA'_def IB'_def)
          also have "... = ?Fc 
                ( [Var B B @ Var A B @ Var B A @ I ↝ Var B B @ Var A B @ IB' @ Var B A @ IA'] oo
                  ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  [Var B B @ Var B A @ OB' @ Var A B @ OA' ↝ Var B B @ Var A B @ Var B A @ O'] )"
            apply (subst switch_comp)
            by (simp_all)
          also have  "... = ?Fc 
                ( ID (TVs (Var B B)) ∥ [Var A B @ Var B A @ I ↝ Var A B @ IB' @ Var B A @ IA'] oo
                  ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  [Var B B @ Var B A @ OB' @ Var A B @ OA' ↝ Var B B @ Var A B @ Var B A @ O'] )"
            apply (subst par_switch[THEN sym])
            apply simp_all
            apply (subst distinct_id)
            by simp_all
          also have  "... = ?Fc 
                ( ID (TVs (Var B B)) ∥ [Var A B @ Var B A @ I ↝ Var A B @ IB' @ Var B A @ IA'] oo
                  ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  ID (TVs (Var B B)) ∥ [Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ Var B A @ O'] )"
            apply (subst (2) par_switch[THEN sym])
            apply simp_all
            apply (subst distinct_id)
            by simp_all
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) 
                ( [Var A B @ Var B A @ I ↝ Var A B @ IB' @ Var B A @ IA'] oo
                    ((fb ^^ length (Var B B)) (([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])))) oo
                  [Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ Var B A @ O']))" 
            apply (cut_tac tsa="TVs (Var B B)" and A= "[Var A B @ Var B A @ I ↝ Var A B @ IB' @ Var B A @ IA']" and B="[Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ Var B A @ O']" and
                S = "([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']) ∥
                  (fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])" in fb_indep)
            by (simp_all add: fbtype_def)
          also have "... = (fb ^^ length (Var B A)) ((fb ^^ length (Var A B)) 
                ( [Var A B @ Var B A @ I ↝ Var A B @ IB' @ Var B A @ IA'] oo
                    ((fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB'  ↝ In B]  oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])) ∥ ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])) oo
                  [Var B A @ OB' @ Var A B @ OA' ↝ Var A B @ Var B A @ O']))"  (is "_ = ?Fd (?Sk oo ?Sl ∥ ?Sm oo ?Sn) " )             
            apply (cut_tac tsa="TVs(Var B B)" and ts="TVs(Var A B @ IB')" and ts'="TVs(Var B A @ OB')" and 
                S="([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])" and
                T= "(fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])" in fb_gen_parallel)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var B B)) = length (Var B B)")
            by (simp_all)
          also have "... = ?Fd (?Sk oo 
                ([Var A B @ IB' @ Var B A @ IA' ↝ Var B A @ IA' @ Var A B @ IB'] oo ?Sm ∥ ?Sl oo [Var A B @ OA' @ Var B A @ OB' ↝ Var B A @ OB' @ Var A B @ OA']) oo 
                ?Sn)"
            apply (cut_tac x="Var A B @ IB'" and y="Var B A @ IA'" and u="Var A B @ OA'" and v="Var B A @ OB'" and
                T="(fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])" and
                S="(fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])" in switch_par)
            by simp_all
          also have "... = ?Fd (
                (?Sk oo [Var A B @ IB' @ Var B A @ IA' ↝ Var B A @ IA' @ Var A B @ IB']) oo 
                  ?Sm ∥ ?Sl oo 
                ([Var A B @ OA' @ Var B A @ OB' ↝ Var B A @ OB' @ Var A B @ OA'] oo ?Sn))"
            by (simp add: comp_assoc_middle_ext)
          also have "... = ?Fd (
                [Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var A B @ IB'] oo 
                  ?Sm ∥ ?Sl oo 
                ([Var A B @ OA' @ Var B A @ OB' ↝ Var B A @ OB' @ Var A B @ OA'] oo ?Sn))"
            apply (subst switch_comp, simp_all add: perm_union_right)
            by (auto simp add: IA'_def IB'_def)
          also have "... = ?Fd (
                [Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var A B @ IB'] oo 
                  ?Sm ∥ ?Sl oo 
                [Var A B @ OA' @ Var B A @ OB' ↝ Var A B @ Var B A @ O'])"
            apply (subst switch_comp)
            by simp_all

           also have "... = ?Fd (
                [Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var A B @ IB'] oo 
                  ?Sm ∥ ?Sl oo 
                ID (TVs (Var A B)) ∥ [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (subst(2) par_switch[THEN sym])
            apply simp_all
            by (simp add: distinct_id)


          also have "... = (fb ^^ length (Var B A)) (((fb ^^ length (Var A B)) (
                [Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var A B @ IB'] oo 
                  ?Sm ∥ ?Sl)) oo [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (cut_tac tsa="TVs(Var A B)" and
                S="([Var A B @ Var B A @ I ↝ Var B A @ IA' @ Var A B @ IB'] oo
                  (fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']) ∥
                  (fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB']))" and 
                B="[OA' @ Var B A @ OB' ↝ Var B A @ O']" in fb_indep_right)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var A B)) = length (Var A B)")
            by (simp_all)
          also have "... = (fb ^^ length (Var B A))
                (?Sm ∥ ID (TVs IB') oo [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (cut_tac u="Var A B" and x="Var B A @ IA'" and x'="IB'" and y="OA'" and y'="Var B A @ OB'" and
               A="(fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA'])" and
               B="(fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])" in fb_par_serial)
            apply simp_all
            by (simp add: I_simp)
          also have "... = (fb ^^ length (Var B A))
                ((fb ^^ length (Var A A)) (([Var A A @ Var B A @ IA' ↝ Var A A @ IA'']) oo [Var A A @ IA'' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ Var A B @ OA']) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (subst switch_comp, simp_all add: perm_union_right)
            by (auto simp add: IA''_def Var_def set_inter set_diff)

          also have "... = (fb ^^ length (Var B A))
                ((fb ^^ length (Var A A)) (([Var A A @ Var B A @ IA' ↝ Var A A @ IA''] oo [Var A A @ IA'' ↝ In A]) oo Trs A oo ([Out A ↝ Var A A @ OA''] oo [Var A A @ OA'' ↝ Var A A @ Var A B @ OA'])) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (subst (3) switch_comp, simp_all)
            by (auto simp add: OA''_def OA'_def Var_def set_inter set_diff)

          also have "... = (fb ^^ length (Var B A))
                ((fb ^^ length (Var A A)) ([Var A A @ Var B A @ IA' ↝ Var A A @ IA''] oo ([Var A A @ IA'' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ OA'']) oo [Var A A @ OA'' ↝ Var A A @ Var A B @ OA']) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            by (simp add: comp_assoc [THEN sym])
          also have "... = (fb ^^ length (Var B A))
                ((fb ^^ length (Var A A)) ([Var A A ↝ Var A A] ∥ [Var B A @ IA' ↝ IA''] oo ([Var A A @ IA'' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ OA'']) oo [Var A A @ OA'' ↝ Var A A @ Var A B @ OA']) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (subst par_switch)
            by simp_all
          also have "... = (fb ^^ length (Var B A))
                ((fb ^^ length (Var A A)) ([Var A A ↝ Var A A] ∥ [Var B A @ IA' ↝ IA''] oo ([Var A A @ IA'' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ OA'']) oo [Var A A ↝ Var A A] ∥ [OA'' ↝ Var A B @ OA']) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (subst(3) par_switch)
            by simp_all
          also have "... = (fb ^^ length (Var B A))
                (([Var B A @ IA' ↝ IA''] oo (fb ^^ length (Var A A)) ([Var A A @ IA'' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ OA'']) oo [OA'' ↝ Var A B @ OA']) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])"
            apply (cut_tac tsa="TVs ((Var A A))" and A="[Var B A @ IA' ↝ IA'']" and B="[OA'' ↝ Var A B @ OA']" and
                S="([Var A A @ IA'' ↝ In A] oo Trs A oo [Out A ↝ Var A A @ OA''])" in fb_indep)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var A A)) = length (Var A A)")
            apply (simp add: distinct_id)
            by (simp )
          also have "... = (fb ^^ length (Var B A))
                (([Var B A @ IA' ↝ IA''] oo Trs (FB(A)) oo [OA'' ↝ Var A B @ OA']) ∥ ID (TVs IB') oo 
                [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo ID (TVs OA') ∥ ?Sl oo
                [OA' @ Var B A @ OB' ↝ Var B A @ O'])" (is "_ = ?Fe (?So oo ID (TVs OA') ∥ ?Sl oo ?Sp)")
            apply (simp add: FB_def Let_def)
            apply (subgoal_tac "IA'' = (In A ⊖ Var A A)")
            apply (subgoal_tac "OA'' = (Out A ⊖ Var A A)")
            apply simp
            by (simp_all add: OA''_def IA''_def Var_def diff_inter_left diff_inter_right)
          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ (fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ Var B B @ IB''] oo [Var B B @ IB'' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ Var B A @ OB'])
                oo ?Sp)"
            apply (subst switch_comp, simp_all add: perm_union_right)
            by (auto simp add: Var_def IB'_def IB''_def set_inter set_diff)
          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ (fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ Var B B @ IB''] oo [Var B B @ IB'' ↝ In B] oo Trs B oo ([Out B ↝ Var B B @ OB'' ] oo [Var B B @ OB'' ↝ Var B B @ Var B A @ OB']))
                oo ?Sp)"
            apply (subst(3) switch_comp)
            apply simp_all
            by (auto simp add: Var_def OB'_def OB''_def set_inter set_diff)

          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ (fb ^^ length (Var B B)) ([Var B B @ Var A B @ IB' ↝ Var B B @ IB''] oo ([Var B B @ IB'' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ OB'' ]) oo [Var B B @ OB'' ↝ Var B B @ Var B A @ OB'])
                oo ?Sp)"
            by (simp add: comp_assoc [THEN sym] )
          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ (fb ^^ length (Var B B)) ([Var B B ↝ Var B B] ∥ [Var A B @ IB' ↝ IB''] oo ([Var B B @ IB'' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ OB'' ]) oo [Var B B @ OB'' ↝ Var B B @ Var B A @ OB'])
                oo ?Sp)"
            apply (subst par_switch)
            by simp_all
          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ (fb ^^ length (Var B B)) ([Var B B ↝ Var B B] ∥ [Var A B @ IB' ↝ IB''] oo ([Var B B @ IB'' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ OB'' ]) oo [Var B B ↝ Var B B] ∥ [OB'' ↝ Var B A @ OB'])
                oo ?Sp)"
            apply (subst(3) par_switch)
            by simp_all
          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ ([Var A B @ IB' ↝ IB''] oo (fb ^^ length (Var B B)) ([Var B B @ IB'' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ OB'' ]) oo  [OB'' ↝ Var B A @ OB'])
                oo ?Sp)"
            apply (cut_tac tsa="TVs (Var B B)" and A="[Var A B @ IB' ↝ IB'']" and B="[OB'' ↝ Var B A @ OB']" and
                S="([Var B B @ IB'' ↝ In B] oo Trs B oo [Out B ↝ Var B B @ OB''])"in fb_indep)
            apply (simp add: fbtype_def)
            apply (subgoal_tac "length (TVs (Var B B)) = length (Var B B)")
            by (simp_all add: distinct_id)
          also have "... = ?Fe (?So oo 
                ID (TVs OA') ∥ ([Var A B @ IB' ↝ IB''] oo Trs (FB B) oo  [OB'' ↝ Var B A @ OB'])
                oo ?Sp)" (is "_ = ?Fe (?Sq oo ?Sr oo ?St oo ?Sp)")
            apply (subst(3) FB_def)
            apply (simp add: Let_def)
            apply (subgoal_tac "IB'' = (In B ⊖ Var B B)")
            apply (subgoal_tac "OB'' = (Out B ⊖ Var B B)")
            by (simp_all add: OB''_def IB''_def Var_def diff_inter_left diff_inter_right)
          also have "... = ?Fe (
                ([Var B A @ IA' ↝ IA''] ∥ ID (TVs IB') oo Trs (FB A) ∥ ID (TVs IB') oo [OA'' ↝ Var A B @ OA'] ∥ ID (TVs IB')) oo 
                ?Sr oo ?St oo ?Sp)"
            by (simp add: distinct_id[THEN sym] par_id_comp)
          also have "... = ?Fe (
                ([Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo Trs (FB A) ∥ ID (TVs IB') oo [OA'' ↝ Var A B @ OA'] ∥ ID (TVs IB')) oo 
                ?Sr oo ?St oo ?Sp)"
            by (simp add: distinct_id[THEN sym] par_switch)
          also have "... = ?Fe (
                ([Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo Trs (FB A) ∥ ID (TVs IB') oo [OA''@ IB' ↝ Var A B @ OA'@ IB']) oo 
                ?Sr oo ?St oo ?Sp)" (is "_=?Fe (?Ss oo ?Sr oo ?St oo ?Sp)")
            by (simp add: distinct_id[THEN sym] par_switch)
          also have "... = ?Fe (?Ss oo ?Sr oo
                (ID (TVs OA') ∥ [Var A B @ IB' ↝ IB''] oo ID (TVs OA') ∥ Trs (FB B) oo ID (TVs OA') ∥ [OB'' ↝ Var B A @ OB']) oo
                ?Sp)"
            by (simp add: distinct_id[THEN sym] id_par_comp)
          also have "... = ?Fe (?Ss oo ?Sr oo
                ([OA' @ Var A B @ IB' ↝ OA' @ IB''] oo ID (TVs OA') ∥ Trs (FB B) oo ID (TVs OA') ∥ [OB'' ↝ Var B A @ OB']) oo
                ?Sp)"            
            by (simp add: distinct_id[THEN sym] par_switch)
          also have "... = ?Fe (?Ss oo ?Sr oo
                ([OA' @ Var A B @ IB' ↝ OA' @ IB''] oo ID (TVs OA') ∥ Trs (FB B) oo [OA' @ OB'' ↝ OA' @ Var B A @ OB']) oo
                ?Sp)"  
            by (simp add: distinct_id[THEN sym] par_switch)
          also have "... = ?Fe (
                [Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo Trs (FB A) ∥ ID (TVs IB') oo 
                ([OA''@ IB' ↝ Var A B @ OA'@ IB'] oo [Var A B @ OA' @ IB' ↝ OA' @ Var A B @ IB'] oo [OA' @ Var A B @ IB' ↝ OA' @ IB'']) oo
                ID (TVs OA') ∥ Trs (FB B) oo 
                ([OA' @ OB'' ↝ OA' @ Var B A @ OB'] oo [OA' @ Var B A @ OB' ↝ Var B A @ O']))"  
             by (simp add: comp_assoc  )
          also have "... = ?Fe (
                [Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo Trs (FB A) ∥ ID (TVs IB') oo 
                ([OA''@ IB' ↝ OA' @ Var A B @ IB'] oo [OA' @ Var A B @ IB' ↝ OA' @ IB'']) oo
                ID (TVs OA') ∥ Trs (FB B) oo 
                ([OA' @ OB'' ↝ OA' @ Var B A @ OB'] oo [OA' @ Var B A @ OB' ↝ Var B A @ O']))"  
            apply (subst switch_comp, simp_all)
            by (auto simp add: OA'_def Var_def IB'_def)
          also have "... = ?Fe (
                [Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo Trs (FB A) ∥ ID (TVs IB') oo 
                [OA''@ IB' ↝ OA' @ IB''] oo
                ID (TVs OA') ∥ Trs (FB B) oo 
                ([OA' @ OB'' ↝ OA' @ Var B A @ OB'] oo [OA' @ Var B A @ OB' ↝ Var B A @ O']))"  
            apply (subst switch_comp, simp_all)
            by (auto simp add: OA'_def Var_def IB''_def IB'_def set_diff set_inter)
          also have "... = ?Fe (
                [Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo Trs (FB A) ∥ ID (TVs IB') oo 
                [OA''@ IB' ↝ OA' @ IB''] oo
                ID (TVs OA') ∥ Trs (FB B) oo 
                [OA' @ OB'' ↝ Var B A @ O'])"  
            by (simp add: switch_comp perm_sym perm_union_right)
          also have "... = ?Fe (
                [Var B A @ IA' @ IB' ↝ IA'' @ IB'] oo 
                (Trs (FB (A) ;; FB (B))) oo
                [OA' @ OB'' ↝ Var B A @ O'])"
             by (simp add: comp_assoc)
          also have Az: "... = Trs (FB (FB (A) ;; FB (B)))"
            apply (subst(3) FB_def)
            apply (simp add: Let_def In_FB_simp Out_FB_simp)
            by (simp add: Var_FB_simp)

          finally have A: "(fb ^^ length (Var (A ||| B) (A ||| B))) ([Var (A ||| B) (A ||| B) @ I ↝ In (A ||| B)] oo Trs (A ||| B) oo [Out (A ||| B) ↝ Var (A ||| B) (A ||| B) @ O'])
              =  Trs (FB (FB (A) ;; FB (B)))"
            by simp

       show "FB (A ||| B) = FB (FB (A) ;; FB (B))"
          proof -
            have "FB (A ||| B) = ⦇In = In (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B), Out = Out (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B), Trs 
          = (fb ^^ length (Var (FB A ;; FB B) (FB A ;; FB B))) 
                ([Var (FB A ;; FB B) (FB A ;; FB B) @ (In (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B)) ↝ In (FB A ;; FB B)] oo Trs (FB A ;; FB B) 
              oo [Out (FB A ;; FB B) ↝ Var (FB A ;; FB B) (FB A ;; FB B) @ (Out (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B))])⦈"
              
              
              using A I_def In_FB_simp In_simp Out_FB_simp Var_FB_simp Az FB_Par_A_B 
               ‹In (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B) = IA' @ IB'› 
               ‹Out (FB A ;; FB B) ⊖ Var (FB A ;; FB B) (FB A ;; FB B) = O'› by auto
              
            then show ?thesis
              by (metis FB_def)
          qed
        qed
          
declare io_diagram_distinct [simp del]  

    
lemma in_out_equiv_FB_less: "io_diagram B ⟹ in_out_equiv A B ⟹ fb_perm_eq A ⟹  in_out_equiv (FB A) (FB B)"
      proof -
        assume A: "io_diagram B"
        assume B: "in_out_equiv A B"
          
        have [simp]: "perm (Var A A) (Var B B)"
          apply (simp add: Var_def)
          using B in_out_equiv_def perm_ops by blast
            
        from this have [simp]: "perm (Var B B) (Var A A)"
          by (rule perm_sym)

        have [simp]: "length (Var A A) = length (Var B B)"
          using [[simp_trace]]
          using A B apply (unfold io_diagram_def in_out_equiv_def)
          apply (simp add:  Var_def)
          apply (subgoal_tac "perm (Out A ⊗ In A) (Out B ⊗ In B)")
          using perm_length apply blast
          by simp
        have [simp]: "TI (Trs B) = TVs (In B)" and [simp]: "TO (Trs B) = TVs (Out B)" and [simp]: "distinct (In A)" and [simp]: "distinct (Out A)" 
          and [simp]: "distinct (Out B)" and [simp]: "perm (Out B) (Out A)"
          using A B apply (simp_all add: io_diagram_def in_out_equiv_def Var_def perm_sym)
          using dist_perm perm_sym apply blast
          using dist_perm perm_sym by blast
            
        have "perm (In A) (In B)"
          using B in_out_equiv_def by blast
         
        from this have [simp]: "set (In B) ⊆ set (In A)"
          by simp

        from B have X: "Trs A = [In A ↝ In B] oo Trs B oo [Out B ↝ Out A]"
          by (simp add: in_out_equiv_def)
            
        from this have Y: "⋀ x y . perm x (In A) ⟹ perm y (Out A) ⟹ [x ↝ In A] oo Trs A oo [Out A ↝ y]
            = [x ↝ In B] oo Trs B oo [Out B ↝ y]"
        proof -
          fix x y
          assume "perm x (In A)"
          assume "perm y (Out A)"
          have "[x ↝ In A] oo Trs A oo [Out A ↝ y] = [x ↝ In A] oo ([In A ↝ In B] oo Trs B oo [Out B ↝ Out A]) oo [Out A ↝ y]"
            by (simp add: X)
          also have "... = ([x ↝ In A] oo [In A ↝ In B]) oo Trs B oo ([Out B ↝ Out A] oo [Out A ↝ y])"
            by (simp add: comp_assoc)
          also have "... = [x ↝ In B] oo Trs B oo [Out B ↝ y]"
            by (metis ‹distinct (In A)› ‹distinct (Out B)› ‹perm (Out B) (Out A)› ‹perm x (In A)› ‹perm y (Out A)› ‹set (In B) ⊆ set (In A)› dist_perm order_refl perm_set_eq perm_sym switch_comp)
          finally show "[x ↝ In A] oo Trs A oo [Out A ↝ y] = [x ↝ In B] oo Trs B oo [Out B ↝ y]"
            by simp
        qed
          
        have [simp]: "perm (Var B B @ (In A ⊖ Var A A)) (In A)"
          by (metis (no_types, lifting) Var_def ‹distinct (In A)› ‹distinct (Out B)› ‹perm (In A) (In B)› ‹perm (Out B) (Out A)› diff_inter_right list_inter_set perm_diff_eq perm_set_eq perm_switch_aux_f)
             
        have [simp]: "perm (Var B B @ (Out A ⊖ Var A A)) (Out A)"
          by (metis Var_def ‹distinct (In A)› ‹distinct (Out A)› ‹perm (Var B B) (Var A A)› diff_inter_left perm_mset perm_switch_aux_c union_code)

        assume "fb_perm_eq A"
        from this have H: "(fb ^^ length (Var B B)) ([Var B B @ (In A ⊖ Var A A) ↝ In B] oo Trs B oo [Out B ↝ Var B B @ (Out A ⊖ Var A A)]) =
              (fb ^^ length (Var B B)) ([Var A A @ (In A ⊖ Var A A) ↝ In B] oo Trs B oo [Out B ↝ Var A A @ (Out A ⊖ Var A A)])"
          apply (simp add:fb_perm_eq_def InFB_def VarFB_def OutFB_def)
          apply (drule_tac x = "Var B B" in spec)
          by (simp add:  Y)
            
        have [simp]: "set (Var B B) ∩ set (In A ⊖ Var A A) = {}"
          by (metis Var_def ‹distinct (In A)› ‹distinct (Out A)› ‹perm (Var A A) (Var B B)› addvars_def distinct_addvars distinct_append distinct_inter perm_set_eq)
        have [simp]: "set (In B ⊖ Var B B) ⊆ set (In A ⊖ Var A A)"
          by (metis (full_types) B ‹perm (Var A A) (Var B B)› in_out_equiv_def order_refl perm_diff perm_set_eq)
        have [simp]: " perm (Var B B @ (In A ⊖ Var A A)) (Var B B @ (In B ⊖ Var B B))"
          using B ‹perm (Var A A) (Var B B)› in_out_equiv_def perm_diff perm_union_right by blast
        have [simp]: "set (In B) ⊆ set (Var B B) ∪ set (In B ⊖ Var B B)"
          by (simp add: set_diff)
          
        have [simp]: "set (Out A ⊖ Var A A) ⊆ set (Out B ⊖ Var B B)"
          by auto
        have [simp]: "perm (Out B) (Var B B @ (Out B ⊖ Var B B))"
          by (metis A Var_def diff_inter_left perm_switch_aux_c perm_sym io_diagram_def)
        have [simp]: " set (Out A ⊖ Var A A) ⊆ set (Var B B) ∪ set (Out B ⊖ Var B B)"
          using ‹set (Out A ⊖ Var A A) ⊆ set (Out B ⊖ Var B B)› by blast
        have [simp]: "perm (Var A A @ (In A ⊖ Var A A)) (Var B B @ (In A ⊖ Var A A))"
          using ‹perm (Var A A) (Var B B)› perm_union_left by blast
        have [simp]: "set (In B) ⊆ set (Var B B) ∪ set (In A ⊖ Var A A)"
          using ‹set (In B ⊖ Var B B) ⊆ set (In A ⊖ Var A A)› ‹set (In B) ⊆ set (Var B B) ∪ set (In B ⊖ Var B B)› by blast
        have [simp]: "perm (Out B) (Var B B @ (Out A ⊖ Var A A))"
          by (meson ‹perm (Out B) (Out A)› ‹perm (Out B) (Var B B @ (Out B ⊖ Var B B))› ‹perm (Var A A) (Var B B)› perm_diff perm_sym perm_trans perm_union_right)
        have [simp]: "set (Var A A) ⊆ set (Var B B) ∪ set (Out A ⊖ Var A A)"
          using ListProp.perm_set_eq ‹Var A A <~~> Var B B› by blast

        have C: "ID (TVs (Var B B)) ∥ [In A ⊖ Var A A ↝ In B ⊖ Var B B] oo [Var B B @ (In B ⊖ Var B B) ↝ In B] =  [Var B B @ (In A ⊖ Var A A) ↝ In B]"
          
          apply (subst distinct_id [THEN sym])
            apply (simp_all add: par_switch switch_comp)
          apply (subst switch_comp, simp_all)
            using ‹In A <~~> In B› by auto
              
        have D: "[Out B ↝ Var B B @ (Out B ⊖ Var B B)] oo ID (TVs (Var B B)) ∥ [Out B ⊖ Var B B ↝ Out A ⊖ Var A A] = [Out B ↝ Var B B @ (Out A ⊖ Var A A)]"
          by (subst distinct_id [THEN sym], simp_all add: par_switch switch_comp)
        have E: "[Var A A @ (In A ⊖ Var A A) ↝ Var B B @ (In A ⊖ Var A A)] oo [Var B B @ (In A ⊖ Var A A) ↝ In B] = [Var A A @ (In A ⊖ Var A A) ↝ In B]"
          by (subst switch_comp, simp_all)
        have F: "[Out B ↝ Var B B @ (Out A ⊖ Var A A)] oo [Var B B @ (Out A ⊖ Var A A) ↝ Var A A @ (Out A ⊖ Var A A)] =  [Out B ↝ Var A A @ (Out A ⊖ Var A A)]"
          by (subst switch_comp, simp_all)
        have "[In A ⊖ Var A A ↝ In B ⊖ Var B B] oo (fb ^^ length (Var B B)) ([Var B B @ (In B ⊖ Var B B) ↝ In B] oo (Trs B oo [Out B ↝ Var B B @ (Out B ⊖ Var B B)])) oo [Out B ⊖ Var B B ↝ Out A ⊖ Var A A]
          = (fb ^^ length (Var B B))
            ((ID (TVs (Var B B)) ∥ [In A ⊖ Var A A ↝ In B ⊖ Var B B] oo [Var B B @ (In B ⊖ Var B B) ↝ In B]) oo Trs B 
            oo ([Out B ↝ Var B B @ (Out B ⊖ Var B B)] oo ID (TVs (Var B B)) ∥ [Out B ⊖ Var B B ↝ Out A ⊖ Var A A]))"
          apply (subst fb_indep_a [THEN sym])
            apply (simp_all add: fbtype_def)
            apply (simp add: )
          by (simp add: comp_assoc)
        also have "... = (fb ^^ length (Var B B)) ([Var B B @ (In A ⊖ Var A A) ↝ In B] oo Trs B oo [Out B ↝ Var B B @ (Out A ⊖ Var A A)])"
        by (simp add: C D)
      
      also have "... = (fb ^^ length (Var B B)) ([Var A A @ (In A ⊖ Var A A) ↝ In B] oo Trs B oo [Out B ↝ Var A A @ (Out A ⊖ Var A A)])"
        by (simp add: H)
      also from B have "... = (fb ^^ length (Var B B)) ([Var A A @ (In A ⊖ Var A A) ↝ In A] oo ([In A ↝ In B] oo Trs B oo [Out B ↝ Out A]) oo [Out A ↝ Var A A @ (Out A ⊖ Var A A)])"
          apply (simp add: comp_assoc [THEN sym] switch_comp in_out_equiv_def)
          by (simp add: comp_assoc switch_comp)

      finally show ?thesis
        using A B apply (simp add: FB_def in_out_equiv_def Let_def)
        by (simp add: comp_assoc [THEN sym] switch_comp)
    qed

lemma [simp]: "io_diagram A ⟹ distinct (OutFB A)"
  by (simp add: OutFB_def io_diagram_distinct(2))



end

end