theory CorrectnessOriginal
imports "Denotational" "Launchbury"
begin

text {*
This is the main correctness theorem, Theorem 2 from \cite{launchbury}.
*}

(* Another possible invariant seems to be: "edom \<rho> - domA \<Gamma> \<subseteq> set L" *)

theorem correctness:
  assumes "\<Gamma> : e \<Down>\<^bsub>L\<^esub> \<Delta> : z"
  and     "fv (\<Gamma>, e) - domA \<Gamma> \<subseteq> set L"
  shows   "\<lbrakk>e\<rbrakk>\<^bsub>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub> = \<lbrakk>z\<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<rho>\<^esub>" and "(\<lbrace>\<Gamma>\<rbrace>\<rho>) f|` domA \<Gamma> = (\<lbrace>\<Delta>\<rbrace>\<rho>) f|` domA \<Gamma>"
  using assms
proof(nominal_induct arbitrary: \<rho> rule:reds.strong_induct)
case Lambda
  case 1 show ?case..
  case 2 show ?case..
next
case (Application y \<Gamma> e x L \<Delta> \<Theta> z e')
  hence "y \<noteq> x" by (simp_all add: fresh_at_base)

  have Gamma_subset: "domA \<Gamma> \<subseteq> domA \<Delta>"
    by (rule reds_doesnt_forget[OF Application.hyps(8)])

  case 1
  hence prem1: "fv (\<Gamma>, e) - domA \<Gamma> \<subseteq> set (x#L)" by auto

  from 1 Gamma_subset have *: "x \<in> set L \<or> x \<in> domA \<Delta>" by auto

  have "fv (\<Delta>, e'[y::=x]) - domA \<Delta> \<subseteq> (fv (\<Delta>, Lam [y]. e') - domA \<Delta>) \<union> {x}"
    by (auto dest!: set_mp[OF fv_subst_subset])
  also have "\<dots> \<subseteq> (fv (\<Gamma>, e) - domA \<Gamma>) \<union> {x}"
    using new_free_vars_on_heap[OF Application.hyps(8)] by auto
  also have "\<dots> \<subseteq> set L \<union> {x}" using prem1 by auto
  finally have "fv (\<Delta>, e'[y::=x]) - domA \<Delta> \<subseteq> set L \<union> {x}".
  with *
  have prem2: "fv (\<Delta>, e'[y::=x]) - domA \<Delta> \<subseteq> set L" by auto

  have *: "(\<lbrace>\<Gamma>\<rbrace>\<rho>) x = (\<lbrace>\<Delta>\<rbrace>\<rho>) x"
  proof(cases "x \<in> domA \<Gamma>")
    case True
    from Application.hyps(10)[OF prem1, where \<rho> = \<rho>]
    have "((\<lbrace>\<Gamma>\<rbrace>\<rho>) f|` domA \<Gamma>) x  = ((\<lbrace>\<Delta>\<rbrace>\<rho>) f|` domA \<Gamma>) x" by simp
    with True show ?thesis by simp
  next
    case False
    from False reds_avoids_live[OF Application.hyps(8)]
    show ?thesis by (simp add: lookup_HSem_other)
  qed

  have "\<lbrakk> App e x \<rbrakk>\<^bsub>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub> = (\<lbrakk> e \<rbrakk>\<^bsub>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub>) \<down>Fn (\<lbrace>\<Gamma>\<rbrace>\<rho>) x"
    by simp
  also have "\<dots> = (\<lbrakk> Lam [y]. e' \<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<rho>\<^esub>) \<down>Fn (\<lbrace>\<Gamma>\<rbrace>\<rho>) x"
    using Application.hyps(9)[OF prem1] by simp
  also have "\<dots> = (\<lbrakk> Lam [y]. e' \<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<rho>\<^esub>) \<down>Fn (\<lbrace>\<Delta>\<rbrace>\<rho>) x"
    unfolding *..
  also have "\<dots> = (Fn \<cdot> (\<Lambda> v. \<lbrakk> e' \<rbrakk>\<^bsub>(\<lbrace>\<Delta>\<rbrace>\<rho>)(y := v)\<^esub>)) \<down>Fn (\<lbrace>\<Delta>\<rbrace>\<rho>) x"
    by simp
  also have "\<dots> = \<lbrakk> e' \<rbrakk>\<^bsub>(\<lbrace>\<Delta>\<rbrace>\<rho>)(y := (\<lbrace>\<Delta>\<rbrace>\<rho>) x)\<^esub>"
    by simp
  also have "\<dots> = \<lbrakk> e'[y ::= x] \<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<rho>\<^esub>"
    by (rule arg_cong[OF ESem_subst[OF `y \<noteq> x`]])
  also have "\<dots> = \<lbrakk> z \<rbrakk>\<^bsub>\<lbrace>\<Theta>\<rbrace>\<rho>\<^esub>"
    by (rule Application.hyps(12)[OF prem2])
  finally
  show ?case.

  show "(\<lbrace>\<Gamma>\<rbrace>\<rho>) f|` domA \<Gamma> = (\<lbrace>\<Theta>\<rbrace>\<rho>) f|` domA \<Gamma>"
    using Application.hyps(10)[OF prem1]
          env_restr_eq_subset[OF Gamma_subset Application.hyps(13)[OF prem2]]
    by (rule trans)
next
case (Variable \<Gamma> x e L \<Delta> z)
  hence [simp]:"x \<in> domA \<Gamma>" by (metis domA_from_set map_of_is_SomeD)

  let ?\<Gamma> = "delete x \<Gamma>"

  case 2
  have "x \<notin> domA \<Delta>"
    by (rule reds_avoids_live[OF Variable.hyps(2)], simp_all)

  have subset: "domA ?\<Gamma> \<subseteq> domA \<Delta>"
    by (rule reds_doesnt_forget[OF Variable.hyps(2)])

  have "fv (?\<Gamma>, e) \<union> {x} \<subseteq> fv (\<Gamma>, Var x)"
    by (rule fv_delete_heap[OF `map_of \<Gamma> x = Some e`])
  hence prem: "fv (?\<Gamma>, e) - domA ?\<Gamma> \<subseteq> set (x # L)" using 2 by auto

  have fv_subset: "fv (?\<Gamma>, e) - domA ?\<Gamma> \<subseteq> - (domA \<Delta> - domA \<Gamma>)"
    apply (rule subset_trans[OF prem])
    apply (rule subset_trans[OF reds_avoids_live'[OF Variable.hyps(2)]])
    by auto

  let "?new" = "domA \<Delta> - domA \<Gamma>"
  have "domA \<Gamma> \<subseteq> (-?new)" by auto

  have "\<lbrace>\<Gamma>\<rbrace>\<rho> = \<lbrace>(x,e) # ?\<Gamma>\<rbrace>\<rho>"
    by (rule HSem_reorder[OF map_of_delete_insert[symmetric, OF Variable(1)]])
  also have "\<dots> = (\<mu> \<rho>'. (\<rho> ++\<^bsub>(domA ?\<Gamma>)\<^esub> (\<lbrace>?\<Gamma>\<rbrace>\<rho>'))( x := \<lbrakk> e \<rbrakk>\<^bsub>\<rho>'\<^esub>))"
    by (rule iterative_HSem, simp)
  also have "\<dots> = (\<mu> \<rho>'. (\<rho> ++\<^bsub>(domA ?\<Gamma>)\<^esub> (\<lbrace>?\<Gamma>\<rbrace>\<rho>'))( x := \<lbrakk> e \<rbrakk>\<^bsub>\<lbrace>?\<Gamma>\<rbrace>\<rho>'\<^esub>))"
    by (rule iterative_HSem', simp)
  finally
  have "(\<lbrace>\<Gamma>\<rbrace>\<rho>)f|` (- ?new) = (...) f|` (- ?new)" by simp
  also have "\<dots> = (\<mu> \<rho>'. (\<rho> ++\<^bsub>domA \<Delta>\<^esub> (\<lbrace>\<Delta>\<rbrace>\<rho>'))( x := \<lbrakk> z \<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<rho>'\<^esub>)) f|` (- ?new)"
  proof (induction rule: parallel_fix_ind[where P ="\<lambda> x y. x f|` (- ?new) = y f|` (- ?new)"])
    case 1 show ?case by simp
  next
    case 2 show ?case ..
  next
    case (3 \<sigma> \<sigma>')
    hence "\<lbrakk> e \<rbrakk>\<^bsub>\<lbrace>?\<Gamma>\<rbrace>\<sigma>\<^esub> = \<lbrakk> e \<rbrakk>\<^bsub>\<lbrace>?\<Gamma>\<rbrace>\<sigma>'\<^esub>"
      and "(\<lbrace>?\<Gamma>\<rbrace>\<sigma>) f|` domA ?\<Gamma> = (\<lbrace>?\<Gamma>\<rbrace>\<sigma>') f|` domA ?\<Gamma>"
      using fv_subset by (auto intro: ESem_fresh_cong HSem_fresh_cong  env_restr_eq_subset[OF _ 3])
    from trans[OF this(1) Variable(3)[OF prem]] trans[OF this(2) Variable(4)[OF prem]]
    have  "\<lbrakk> e \<rbrakk>\<^bsub>\<lbrace>?\<Gamma>\<rbrace>\<sigma>\<^esub> = \<lbrakk> z \<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<sigma>'\<^esub>"
       and "(\<lbrace>?\<Gamma>\<rbrace>\<sigma>) f|` domA ?\<Gamma> = (\<lbrace>\<Delta>\<rbrace>\<sigma>') f|` domA ?\<Gamma>".
    thus ?case
      using subset
      by (auto intro!: ext simp add: lookup_override_on_eq  lookup_env_restr_eq dest: env_restr_eqD )
  qed
  also have "\<dots> = (\<mu> \<rho>'. (\<rho> ++\<^bsub>domA \<Delta>\<^esub> (\<lbrace>\<Delta>\<rbrace>\<rho>'))( x := \<lbrakk> z \<rbrakk>\<^bsub>\<rho>'\<^esub>)) f|` (-?new)"
    by (rule arg_cong[OF iterative_HSem'[symmetric], OF `x \<notin> domA \<Delta>`])
  also have "\<dots> = (\<lbrace>(x,z) # \<Delta>\<rbrace>\<rho>)  f|` (-?new)"
    by (rule arg_cong[OF iterative_HSem[symmetric], OF `x \<notin> domA \<Delta>`])
  finally
  show le: ?case by (rule env_restr_eq_subset[OF `domA \<Gamma> \<subseteq> (-?new)`])

  have "\<lbrakk> Var x \<rbrakk>\<^bsub>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub> = \<lbrakk> Var x \<rbrakk>\<^bsub>\<lbrace>(x, z) # \<Delta>\<rbrace>\<rho>\<^esub>"
    using env_restr_eqD[OF le, where x = x]
    by simp
  also have "\<dots> = \<lbrakk> z \<rbrakk>\<^bsub>\<lbrace>(x, z) # \<Delta>\<rbrace>\<rho>\<^esub>"
    by (auto simp add: lookup_HSem_heap)
  finally
  show "\<lbrakk> Var x \<rbrakk>\<^bsub>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub> = \<lbrakk> z \<rbrakk>\<^bsub>\<lbrace>(x, z) # \<Delta>\<rbrace>\<rho>\<^esub>".
next
case (Let as \<Gamma> L body \<Delta> z)
  case 1
  { fix a
    assume a: "a \<in> domA  as"
    have "atom a \<sharp> \<Gamma>"
      by (rule Let(1)[unfolded fresh_star_def, rule_format, OF imageI[OF a]])
    hence "a \<notin> domA \<Gamma>"
      by (metis domA_not_fresh)
  }
  note * = this

  have "fv (as @ \<Gamma>, body) - domA (as @ \<Gamma>) \<subseteq>  fv (\<Gamma>, Let as body) - domA \<Gamma>"
    by auto
  with 1 have prem: "fv (as @ \<Gamma>, body) - domA (as @ \<Gamma>) \<subseteq> set L" by auto

  have f1: "atom ` domA as \<sharp>* \<Gamma>"
    using Let(1) by (simp add: set_bn_to_atom_domA)

  have "\<lbrakk> Let as body \<rbrakk>\<^bsub>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub> = \<lbrakk> body \<rbrakk>\<^bsub>\<lbrace>as\<rbrace>\<lbrace>\<Gamma>\<rbrace>\<rho>\<^esub>"
    by (simp)
  also have "\<dots> = \<lbrakk> body \<rbrakk>\<^bsub>\<lbrace>as @ \<Gamma>\<rbrace>\<rho>\<^esub>"
    by (rule arg_cong[OF HSem_merge[OF f1]])
  also have "\<dots> = \<lbrakk> z \<rbrakk>\<^bsub>\<lbrace>\<Delta>\<rbrace>\<rho>\<^esub>"
    by (rule Let.hyps(4)[OF prem])
  finally
  show ?case.

  have "(\<lbrace>\<Gamma>\<rbrace>\<rho>) f|` (domA \<Gamma>) = (\<lbrace>as\<rbrace>(\<lbrace>\<Gamma>\<rbrace>\<rho>)) f|` (domA \<Gamma>)"
    apply (rule ext)
    apply (case_tac "x \<in> domA as")
    apply (auto simp add: lookup_HSem_other lookup_env_restr_eq *)
    done
  also have "\<dots> = (\<lbrace>as @ \<Gamma>\<rbrace>\<rho>) f|` (domA \<Gamma>)"
    by (rule arg_cong[OF HSem_merge[OF f1]])
  also have "\<dots> = (\<lbrace>\<Delta>\<rbrace>\<rho>) f|` (domA \<Gamma>)"
    by (rule env_restr_eq_subset[OF _ Let.hyps(5)[OF prem]]) simp
  finally
  show "(\<lbrace>\<Gamma>\<rbrace>\<rho>) f|` domA \<Gamma> = (\<lbrace>\<Delta>\<rbrace>\<rho>) f|` domA \<Gamma>".
qed

end


           (*-------------------------------------------*
            |        CSP-Prover on Isabelle2004         |
            |               December 2004               |
            |                   July 2005  (modified)   |
            |              September 2005  (modified)   |
            |                                           |
            |        CSP-Prover on Isabelle2005         |
            |               November 2005  (modified)   |
            |                  April 2006  (modified)   |
            |                  March 2007  (modified)   |
            |                 August 2007  (modified)   |
            |                                           |
            |        CSP-Prover on Isabelle2009         |
            |                   June 2009  (modified)   |
            |                                           |
            |        Yoshinao Isobe (AIST JAPAN)        |
            *-------------------------------------------*)

theory CSP_F_law_dist
imports CSP_F_law_basic CSP_F_law_decompo CSP_T.CSP_T_law_dist
        CSP_F_law_alpha_par
begin

(*****************************************************************

      distribution over internal choice

         1. (P1 |~| P2) [+] Q
         2. Q [+] (P1 |~| P2)
         3. (P1 |~| P2) |[X]| Q
         4. Q |[X]| (P1 |~| P2)
         5. (P1 |~| P2) -- X
         6. (P1 |~| P2) [[r]]
         7. (P1 |~| P2) ;; Q
         8. (P1 |~| P2) |. n
         9. !! x:X .. (P1 |~| P2)

 *****************************************************************)

(*********************************************************
                dist law for Ext_choice (l)
 *********************************************************)

lemma cspF_Ext_choice_dist_l:
  "(P1 |~| P2) [+] Q =F[M,M]
   (P1 [+] Q) |~| (P2 [+] Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Ext_choice_dist_l)
apply (rule order_antisym)
apply (rule, simp add: in_traces in_failures, fast)+
done

(*********************************************************
                dist law for Ext_choice (r)
 *********************************************************)

lemma cspF_Ext_choice_dist_r:
  "P [+] (Q1 |~| Q2) =F[M,M]
   (P [+] Q1) |~| (P [+] Q2)"
apply (rule cspF_rw_left)
apply (rule cspF_commut)
apply (rule cspF_rw_left)
apply (rule cspF_Ext_choice_dist_l)
apply (rule cspF_decompo)
apply (rule cspF_commut)+
done

(*********************************************************
                dist law for Parallel (l)
 *********************************************************)

lemma cspF_Parallel_dist_l:
  "(P1 |~| P2) |[X]| Q =F[M,M]
   (P1 |[X]| Q) |~| (P2 |[X]| Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Parallel_dist_l)
apply (rule order_antisym)

  apply (rule, simp add: in_failures)
  apply (elim disjE conjE exE)
  apply (rule disjI1)
  apply (rule_tac x="Y" in exI)
  apply (rule_tac x="Z" in exI)
  apply (fast)
  apply (rule disjI2)
  apply (rule_tac x="Y" in exI)
  apply (rule_tac x="Z" in exI)
  apply (fast)

  apply (rule, simp add: in_failures)
  apply (elim disjE conjE exE)
  apply (rule_tac x="Y" in exI)
  apply (rule_tac x="Z" in exI)
  apply (fast)
  apply (rule_tac x="Y" in exI)
  apply (rule_tac x="Z" in exI)
  apply (fast)
done

(*********************************************************
                dist law for Parallel (r)
 *********************************************************)

lemma cspF_Parallel_dist_r:
  "P |[X]| (Q1 |~| Q2) =F[M,M]
   (P |[X]| Q1) |~| (P |[X]| Q2)"
apply (rule cspF_rw_left)
apply (rule cspF_commut)
apply (rule cspF_rw_left)
apply (rule cspF_Parallel_dist_l)
apply (rule cspF_decompo)
apply (rule cspF_commut)+
done

(*********************************************************
                dist law for Hiding
 *********************************************************)

lemma cspF_Hiding_dist:
  "(P1 |~| P2) -- X =F[M,M]
   (P1 -- X) |~| (P2 -- X)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Hiding_dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures, fast)+
done

(*********************************************************
               dist law for Renaming
 *********************************************************)

lemma cspF_Renaming_dist:
  "(P1 |~| P2) [[r]] =F[M,M]
   (P1 [[r]]) |~| (P2 [[r]])"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Renaming_dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures, fast)+
done

(*********************************************************
         dist law for Sequential composition
 *********************************************************)

lemma cspF_Seq_compo_dist:
  "(P1 |~| P2) ;; Q =F[M,M]
   (P1 ;; Q) |~| (P2 ;; Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Seq_compo_dist)
apply (rule order_antisym)
apply (rule, simp add: in_traces in_failures, fast)+
done

(*********************************************************
               dist law for Depth_rest
 *********************************************************)

lemma cspF_Depth_rest_dist:
  "(P1 |~| P2) |. n =F[M,M]
   (P1 |. n) |~| (P2 |. n)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Depth_rest_dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures)
apply (rule, simp add: in_failures)
apply (fast)
done

(*********************************************************
               dist law for Rep_int_choice
 *********************************************************)

lemma cspF_Rep_int_choice_sum_dist:
  "!! c:C .. (Pf c |~| Qf c) =F[M,M] (!! c:C .. Pf c) |~| (!! c:C .. Qf c)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_int_choice_dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures, fast)+
done

lemma cspF_Rep_int_choice_nat_dist:
  "!nat n:N .. (Pf n |~| Qf n) =F[M,M] (!nat n:N .. Pf n) |~| (!nat n:N .. Qf n)"
by (simp add: Rep_int_choice_ss_def cspF_Rep_int_choice_sum_dist)

lemma cspF_Rep_int_choice_set_dist:
  "!set X:Xs .. (Pf X |~| Qf X) =F[M,M] (!set X:Xs .. Pf X) |~| (!set X:Xs .. Qf X)"
by (simp add: Rep_int_choice_ss_def cspF_Rep_int_choice_sum_dist)

lemma cspF_Rep_int_choice_com_dist:
  "! a:X .. (Pf a |~| Qf a) =F[M,M] (! a:X .. Pf a) |~| (! a:X .. Qf a)"
by (simp add: Rep_int_choice_com_def cspF_Rep_int_choice_set_dist)

lemma cspF_Rep_int_choice_f_dist:
  "inj f ==>
   !<f> a:X .. (Pf a |~| Qf a) =F[M,M] (!<f> a:X .. Pf a) |~| (!<f> a:X .. Qf a)"
by (simp add: Rep_int_choice_f_def cspF_Rep_int_choice_com_dist)

lemmas cspF_Rep_int_choice_dist =
       cspF_Rep_int_choice_sum_dist
       cspF_Rep_int_choice_nat_dist
       cspF_Rep_int_choice_set_dist
       cspF_Rep_int_choice_com_dist
       cspF_Rep_int_choice_f_dist

(*********************************************************
                     dist laws
 *********************************************************)

lemmas cspF_dist = cspF_Ext_choice_dist_l cspF_Ext_choice_dist_r
                   cspF_Parallel_dist_l   cspF_Parallel_dist_r
                   cspF_Hiding_dist       cspF_Renaming_dist
                   cspF_Seq_compo_dist    cspF_Depth_rest_dist
                   cspF_Rep_int_choice_dist

(*****************************************************************

      distribution over replicated internal choice

         1. (!! :C .. Pf) [+] Q
         2. Q [+] (!! :C .. Pf)
         3. (!! :C .. Pf) |[X]| Q
         4. Q |[X]| (!! :C .. Pf)
         5. (!! :C .. Pf) -- X
         6. (!! :C .. Pf) [[r]]
         7. (!! :C .. Pf) |. n

 *****************************************************************)

(*********************************************************
                Rep_dist law for Ext_choice (l)
 *********************************************************)

lemma cspF_Ext_choice_Dist_sum_l_nonempty:
  "sumset C ~= {} ==> (!! :C .. Pf) [+] Q =F[M,M]
                      !! c:C .. (Pf c [+] Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Dist_nonempty)
apply (rule order_antisym)
apply (rule, simp add: in_traces in_failures, fast)+
done

(*** Dist ***)

lemma cspF_Ext_choice_Dist_sum_l:
  "(!! :C .. Pf) [+] Q =F[M,M]
   IF (sumset C={}) THEN (DIV [+] Q) ELSE (!! c:C .. (Pf c [+] Q))"
apply (case_tac "sumset C={}")
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_decompo)
apply (rule cspF_Rep_int_choice_empty)
apply (simp_all)

apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_Ext_choice_Dist_sum_l_nonempty)
apply (simp)
done

(*********************************************************
                Dist_sum law for Ext_choice (r)
 *********************************************************)

lemma cspF_Ext_choice_Dist_sum_r_nonempty:
  "sumset C ~= {} ==> P [+] (!! :C .. Qf) =F[M,M]
               !! c:C .. (P [+] Qf c)"
apply (rule cspF_rw_left)
apply (rule cspF_commut)
apply (rule cspF_rw_left)
apply (rule cspF_Ext_choice_Dist_sum_l_nonempty, simp)
apply (rule cspF_decompo, simp)
apply (rule cspF_commut)
done

(*** Dist ***)

lemma cspF_Ext_choice_Dist_sum_r:
  "P [+] (!! :C .. Qf) =F[M,M]
   IF (sumset C={}) THEN (P [+] DIV) ELSE (!! c:C .. (P [+] Qf c))"
apply (case_tac "sumset C={}")
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_decompo)
apply (simp)
apply (simp add: cspF_Rep_int_choice_empty)

apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_Ext_choice_Dist_sum_r_nonempty)
apply (simp)
done

(*********************************************************
                Dist_sum law for Parallel (l)
 *********************************************************)

lemma cspF_Parallel_Dist_sum_l_nonempty:
  "sumset C ~= {} ==>
     (!! :C .. Pf) |[X]| Q =F[M,M]
     !! c:C .. (Pf c |[X]| Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Dist_nonempty)
apply (rule order_antisym)

(* domF *)
  apply (rule)
  apply (simp add: in_failures)
  apply (elim conjE exE bexE)
   apply (rule_tac x="c" in bexI)
   apply (rule_tac x="Y" in exI)
   apply (rule_tac x="Z" in exI)
   apply (fast)
   apply (simp)
  (* *)
  apply (rule)
  apply (simp add: in_failures)
  apply (elim conjE exE bexE)
   apply (rule_tac x="Y" in exI)
   apply (rule_tac x="Z" in exI)
   apply (fast)
done

(*** Dist ***)

lemma cspF_Parallel_Dist_sum_l:
  "(!! :C .. Pf) |[X]| Q =F[M,M]
   IF (sumset C={}) THEN (DIV |[X]| Q) ELSE (!! c:C .. (Pf c |[X]| Q))"
apply (case_tac "sumset C={}")
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_decompo)
apply (simp)
apply (simp add: cspF_Rep_int_choice_empty)
apply (simp)

apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_Parallel_Dist_sum_l_nonempty)
apply (simp)
done

(*********************************************************
                Dist_sum law for Parallel (r)
 *********************************************************)

lemma cspF_Parallel_Dist_sum_r_nonempty:
  "sumset C ~= {} ==>
     P |[X]| (!! :C .. Qf) =F[M,M]
     !! c:C .. (P |[X]| Qf c)"
apply (rule cspF_rw_left)
apply (rule cspF_commut)
apply (rule cspF_rw_left)
apply (rule cspF_Parallel_Dist_sum_l_nonempty, simp)
apply (rule cspF_decompo, simp)
apply (rule cspF_commut)
done

(*** Dist ***)

lemma cspF_Parallel_Dist_sum_r:
  "P |[X]| (!! :C .. Qf) =F[M,M]
   IF (sumset C={}) THEN (P |[X]| DIV) ELSE (!! c:C .. (P |[X]| Qf c))"
apply (case_tac "sumset C={}")
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_decompo)
apply (simp)
apply (simp)
apply (simp add: cspF_Rep_int_choice_empty)

apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_Parallel_Dist_sum_r_nonempty)
apply (simp)
done

(*********************************************************
                Dist_sum law for Hiding
 *********************************************************)

lemma cspF_Hiding_Dist_sum:
  "(!! :C .. Pf) -- X =F[M,M]
   !! c:C .. (Pf c -- X)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures, fast)+
done

(*********************************************************
                Dist_sum law for Renaming
 *********************************************************)

lemma cspF_Renaming_Dist_sum:
  "(!! :C .. Pf) [[r]] =F[M,M]
   !! c:C .. (Pf c [[r]])"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures, fast)+
done

(*********************************************************
          Dist_sum law for Sequential composition
 *********************************************************)

lemma cspF_Seq_compo_Dist_sum:
  "(!! :C .. Pf) ;; Q =F[M,M]
   !! c:C .. (Pf c ;; Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Dist)
apply (rule order_antisym)
apply (rule, simp add: in_traces in_failures)
apply (force)
apply (rule, simp add: in_traces in_failures)
apply (force)
done

(*********************************************************
                Dist_sum law for Depth_rest
 *********************************************************)

lemma cspF_Depth_rest_Dist_sum:
  "(!! :C .. Pf) |. m =F[M,M]
   !! c:C .. (Pf c |. m)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Dist)
apply (rule order_antisym)
apply (rule, simp add: in_failures)
apply (rule, simp add: in_failures)
done

(*********************************************************
                     Dist_sum laws
 *********************************************************)

lemmas cspF_Dist_sum = cspF_Ext_choice_Dist_sum_l cspF_Ext_choice_Dist_sum_r
                        cspF_Parallel_Dist_sum_l   cspF_Parallel_Dist_sum_r
                        cspF_Hiding_Dist_sum       cspF_Renaming_Dist_sum
                        cspF_Seq_compo_Dist_sum    cspF_Depth_rest_Dist_sum

lemmas cspF_Dist_sum_nonempty =
       cspF_Ext_choice_Dist_sum_l_nonempty cspF_Ext_choice_Dist_sum_r_nonempty
       cspF_Parallel_Dist_sum_l_nonempty   cspF_Parallel_Dist_sum_r_nonempty
       cspF_Hiding_Dist_sum       cspF_Renaming_Dist_sum
       cspF_Seq_compo_Dist_sum    cspF_Depth_rest_Dist_sum

(*****************************************************************

      distribution of internal bind over ...

         1. (!nat :N .. Pf) [+] Q
         2. Q [+] (!nat :N .. Pf)
         3. (!nat :N .. Pf) |[X]| Q
         4. Q |[X]| (!nat :N .. Pf)
         5. (!nat :N .. Pf) -- X
         6. (!nat :N .. Pf) [[r]]
         7. (!nat :N .. Pf) |. n

 *****************************************************************)

(*********************************************************
                Dist law for Ext_choice (l)
 *********************************************************)

lemma cspF_Ext_choice_Dist_nat_l_nonempty:
  "N ~= {} ==> (!nat :N .. Pf) [+] Q =F[M,M]
               !nat n:N .. (Pf n [+] Q)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Ext_choice_Dist_nat_l:
  "(!nat :N .. Pf) [+] Q =F[M,M]
   IF (N={}) THEN (DIV [+] Q) ELSE (!nat n:N .. (Pf n [+] Q))"
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_rw_left)
apply (rule cspF_Dist_sum)
apply (simp)
done

(*********************************************************
                Dist_nat law for Ext_choice (r)
 *********************************************************)

lemma cspF_Ext_choice_Dist_nat_r_nonempty:
  "N ~= {} ==> P [+] (!nat :N .. Qf) =F[M,M]
               !nat n:N .. (P [+] Qf n)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Ext_choice_Dist_nat_r:
  "P [+] (!nat :N .. Qf) =F[M,M]
   IF (N={}) THEN (P [+] DIV) ELSE (!nat n:N .. (P [+] Qf n))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_nat law for Parallel (l)
 *********************************************************)

lemma cspF_Parallel_Dist_nat_l_nonempty:
  "N ~= {} ==>
     (!nat :N .. Pf) |[X]| Q =F[M,M]
     !nat n:N .. (Pf n |[X]| Q)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Parallel_Dist_nat_l:
  "(!nat :N .. Pf) |[X]| Q =F[M,M]
   IF (N={}) THEN (DIV |[X]| Q) ELSE (!nat n:N .. (Pf n |[X]| Q))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_nat law for Parallel (r)
 *********************************************************)

lemma cspF_Parallel_Dist_nat_r_nonempty:
  "N ~= {} ==>
     P |[X]| (!nat :N .. Qf) =F[M,M]
     !nat n:N .. (P |[X]| Qf n)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Parallel_Dist_nat_r:
  "P |[X]| (!nat :N .. Qf) =F[M,M]
   IF (N={}) THEN (P |[X]| DIV) ELSE (!nat n:N .. (P |[X]| Qf n))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_nat law for Hiding
 *********************************************************)

lemma cspF_Hiding_Dist_nat:
  "(!nat :N .. Pf) -- X =F[M,M]
   !nat n:N .. (Pf n -- X)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
                Dist_nat law for Renaming
 *********************************************************)

lemma cspF_Renaming_Dist_nat:
  "(!nat :N .. Pf) [[r]] =F[M,M]
   !nat n:N .. (Pf n [[r]])"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
          Dist_nat law for Sequential composition
 *********************************************************)

lemma cspF_Seq_compo_Dist_nat:
  "(!nat :N .. Pf) ;; Q =F[M,M]
   !nat n:N .. (Pf n ;; Q)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
                Dist_nat law for Depth_rest
 *********************************************************)

lemma cspF_Depth_rest_Dist_nat:
  "(!nat :N .. Pf) |. m =F[M,M]
   !nat n:N .. (Pf n |. m)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
                     Dist_nat laws
 *********************************************************)

lemmas cspF_Dist_nat = cspF_Ext_choice_Dist_nat_l cspF_Ext_choice_Dist_nat_r
                        cspF_Parallel_Dist_nat_l   cspF_Parallel_Dist_nat_r
                        cspF_Hiding_Dist_nat       cspF_Renaming_Dist_nat
                        cspF_Seq_compo_Dist_nat    cspF_Depth_rest_Dist_nat

lemmas cspF_Dist_nat_nonempty =
       cspF_Ext_choice_Dist_nat_l_nonempty cspF_Ext_choice_Dist_nat_r_nonempty
       cspF_Parallel_Dist_nat_l_nonempty   cspF_Parallel_Dist_nat_r_nonempty
       cspF_Hiding_Dist_nat       cspF_Renaming_Dist_nat
       cspF_Seq_compo_Dist_nat    cspF_Depth_rest_Dist_nat

(*****************************************************************

      distribution of internal bind over ...

         1. (!set :Xs .. Pf) [+] Q
         2. Q [+] (!set :Xs .. Pf)
         3. (!set :Xs .. Pf) |[X]| Q
         4. Q |[X]| (!set :Xs .. Pf)
         5. (!set :Xs .. Pf) -- X
         6. (!set :Xs .. Pf) [[r]]
         7. (!set :Xs .. Pf) |. n

 *****************************************************************)

(*********************************************************
                Dist law for Ext_choice (l)
 *********************************************************)

lemma cspF_Ext_choice_Dist_set_l_nonempty:
  "Xs ~= {} ==> (!set :Xs .. Pf) [+] Q =F[M,M]
               !set X:Xs .. (Pf X [+] Q)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Ext_choice_Dist_set_l:
  "(!set :Xs .. Pf) [+] Q =F[M,M]
   IF (Xs={}) THEN (DIV [+] Q) ELSE (!set X:Xs .. (Pf X [+] Q))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_set law for Ext_choice (r)
 *********************************************************)

lemma cspF_Ext_choice_Dist_set_r_nonempty:
  "Xs ~= {} ==> P [+] (!set :Xs .. Qf) =F[M,M]
               !set X:Xs .. (P [+] Qf X)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Ext_choice_Dist_set_r:
  "P [+] (!set :Xs .. Qf) =F[M,M]
   IF (Xs={}) THEN (P [+] DIV) ELSE (!set X:Xs .. (P [+] Qf X))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_set law for Parallel (l)
 *********************************************************)

lemma cspF_Parallel_Dist_set_l_nonempty:
  "Xs ~= {} ==>
     (!set :Xs .. Pf) |[Y]| Q =F[M,M]
     !set X:Xs .. (Pf X |[Y]| Q)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Parallel_Dist_set_l:
  "(!set :Xs .. Pf) |[Y]| Q =F[M,M]
   IF (Xs={}) THEN (DIV |[Y]| Q) ELSE (!set X:Xs .. (Pf X |[Y]| Q))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_set law for Parallel (r)
 *********************************************************)

lemma cspF_Parallel_Dist_set_r_nonempty:
  "Xs ~= {} ==>
     P |[Y]| (!set :Xs .. Qf) =F[M,M]
     !set X:Xs .. (P |[Y]| Qf X)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*** Dist ***)

lemma cspF_Parallel_Dist_set_r:
  "P |[Y]| (!set :Xs .. Qf) =F[M,M]
   IF (Xs={}) THEN (P |[Y]| DIV) ELSE (!set X:Xs .. (P |[Y]| Qf X))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Dist_sum, simp)

(*********************************************************
                Dist_set law for Hiding
 *********************************************************)

lemma cspF_Hiding_Dist_set:
  "(!set :Xs .. Pf) -- Y =F[M,M]
   !set X:Xs .. (Pf X -- Y)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
                Dist_set law for Renaming
 *********************************************************)

lemma cspF_Renaming_Dist_set:
  "(!set :Xs .. Pf) [[r]] =F[M,M]
   !set X:Xs .. (Pf X [[r]])"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
          Dist_set law for Sequential composition
 *********************************************************)

lemma cspF_Seq_compo_Dist_set:
  "(!set :Xs .. Pf) ;; Q =F[M,M]
   !set X:Xs .. (Pf X ;; Q)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
                Dist_set law for Depth_rest
 *********************************************************)

lemma cspF_Depth_rest_Dist_set:
  "(!set :Xs .. Pf) |. m =F[M,M]
   !set X:Xs .. (Pf X |. m)"
by (simp add: Rep_int_choice_ss_def cspF_Dist_sum_nonempty)

(*********************************************************
                     Dist_set laws
 *********************************************************)

lemmas cspF_Dist_set = cspF_Ext_choice_Dist_set_l cspF_Ext_choice_Dist_set_r
                        cspF_Parallel_Dist_set_l   cspF_Parallel_Dist_set_r
                        cspF_Hiding_Dist_set       cspF_Renaming_Dist_set
                        cspF_Seq_compo_Dist_set    cspF_Depth_rest_Dist_set

lemmas cspF_Dist_set_nonempty =
       cspF_Ext_choice_Dist_set_l_nonempty cspF_Ext_choice_Dist_set_r_nonempty
       cspF_Parallel_Dist_set_l_nonempty   cspF_Parallel_Dist_set_r_nonempty
       cspF_Hiding_Dist_set       cspF_Renaming_Dist_set
       cspF_Seq_compo_Dist_set    cspF_Depth_rest_Dist_set

(*****************************************************************

      for convenience

         1. (! :X .. Pf) [+] Q
         2. Q [+] (! :X .. Pf)
         3. (! :X .. Pf) |[X]| Q
         4. Q |[X]| (! :X .. Pf)
         5. (! :X .. Pf) -- X
         6. (! :X .. Pf) [[r]]
         7. (! :X .. Pf) |. n

 *****************************************************************)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Ext_choice_Dist_com_l_nonempty:
  "X ~= {}
   ==> (! :X .. Pf) [+] Q =F[M,M] ! x:X .. (Pf x [+] Q)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Ext_choice_Dist_com_r_nonempty:
  "X ~= {}
   ==> P [+] (! :X .. Qf) =F[M,M] ! x:X .. (P [+] Qf x)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Parallel_Dist_com_l_nonempty:
  "Y ~= {}
   ==> (! :Y .. Pf) |[X]| Q =F[M,M] ! x:Y .. (Pf x |[X]| Q)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Parallel_Dist_com_r_nonempty:
  "Y ~= {}
   ==> P |[X]| (! :Y .. Qf) =F[M,M] ! x:Y .. (P |[X]| Qf x)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Ext_choice_Dist_com_l:
  "(! :X .. Pf) [+] Q =F[M,M]
   IF (X ={}) THEN (DIV [+] Q) ELSE (! x:X .. (Pf x [+] Q))"
apply (simp add: Rep_int_choice_com_def)
by (rule cspF_rw_left, rule cspF_Dist_set, simp)

lemma cspF_Ext_choice_Dist_com_r:
  "P [+] (! :X .. Qf) =F[M,M]
   IF (X ={}) THEN (P [+] DIV) ELSE (! x:X .. (P [+] Qf x))"
apply (simp add: Rep_int_choice_com_def)
by (rule cspF_rw_left, rule cspF_Dist_set, simp)

lemma cspF_Parallel_Dist_com_l:
  "(! :Y .. Pf) |[X]| Q =F[M,M]
   IF (Y ={}) THEN (DIV |[X]| Q) ELSE (! x:Y .. (Pf x |[X]| Q))"
apply (simp add: Rep_int_choice_com_def)
by (rule cspF_rw_left, rule cspF_Dist_set, simp)

lemma cspF_Parallel_Dist_com_r:
  "P |[X]| (! :Y .. Qf) =F[M,M]
   IF (Y ={}) THEN (P |[X]| DIV) ELSE (! x:Y .. (P |[X]| Qf x))"
apply (simp add: Rep_int_choice_com_def)
by (rule cspF_rw_left, rule cspF_Dist_set, simp)

lemma cspF_Hiding_Dist_com:
  "(! :Y .. Pf) -- X =F[M,M] ! x:Y .. (Pf x -- X)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Renaming_Dist_com:
  "(! :X .. Pf) [[r]] =F[M,M] ! x:X .. (Pf x [[r]])"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Seq_compo_Dist_com:
  "(! :X .. Pf) ;; Q =F[M,M] ! x:X .. (Pf x ;; Q)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

lemma cspF_Depth_rest_Dist_com:
  "(! :X .. Pf) |. n =F[M,M] ! x:X .. (Pf x |. n)"
by (simp add: Rep_int_choice_com_def cspF_Dist_set_nonempty)

(*********************************************************
                     Dist laws
 *********************************************************)

lemmas cspF_Dist_com = cspF_Ext_choice_Dist_com_l cspF_Ext_choice_Dist_com_r
                           cspF_Parallel_Dist_com_l   cspF_Parallel_Dist_com_r
                           cspF_Hiding_Dist_com       cspF_Renaming_Dist_com
                           cspF_Seq_compo_Dist_com    cspF_Depth_rest_Dist_com

lemmas cspF_Dist_com_nonempty =
       cspF_Ext_choice_Dist_com_l_nonempty cspF_Ext_choice_Dist_com_r_nonempty
       cspF_Parallel_Dist_com_l_nonempty   cspF_Parallel_Dist_com_r_nonempty
       cspF_Hiding_Dist_com       cspF_Renaming_Dist_com
       cspF_Seq_compo_Dist_com    cspF_Depth_rest_Dist_com

(*****************************************************************

      for convenience

         1. (!<f> :X .. Pf) [+] Q
         2. Q [+] (!<f> :X .. Pf)
         3. (!<f> :X .. Pf) |[X]| Q
         4. Q |[X]| (!<f> :X .. Pf)
         5. (!<f> :X .. Pf) -- X
         6. (!<f> :X .. Pf) [[r]]
         7. (!<f> :X .. Pf) |. n

 *****************************************************************)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Ext_choice_Dist_f_l_nonempty:
  "[| inj f ; X ~= {} |]
   ==> (!<f> :X .. Pf) [+] Q =F[M,M] !<f> x:X .. (Pf x [+] Q)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com_nonempty)

lemma cspF_Ext_choice_Dist_f_r_nonempty:
  "[| inj f ; X ~= {} |]
   ==> P [+] (!<f> :X .. Qf) =F[M,M] !<f> x:X .. (P [+] Qf x)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com_nonempty)

lemma cspF_Parallel_Dist_f_l_nonempty:
  "[| inj f ; Y ~= {} |]
   ==> (!<f> :Y .. Pf) |[X]| Q =F[M,M] !<f> x:Y .. (Pf x |[X]| Q)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com_nonempty)

lemma cspF_Parallel_Dist_f_r_nonempty:
  "[| inj f ; Y ~= {} |]
   ==> P |[X]| (!<f> :Y .. Qf) =F[M,M] !<f> x:Y .. (P |[X]| Qf x)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com_nonempty)

lemma cspF_Ext_choice_Dist_f_l:
  "(!<f> :X .. Pf) [+] Q =F[M,M]
   IF (X ={}) THEN (DIV [+] Q) ELSE (!<f> x:X .. (Pf x [+] Q))"
apply (simp add: Rep_int_choice_f_def)
by (rule cspF_rw_left, rule cspF_Dist_com, simp)

lemma cspF_Ext_choice_Dist_f_r:
  "P [+] (!<f> :X .. Qf) =F[M,M]
   IF (X ={}) THEN (P [+] DIV) ELSE (!<f> x:X .. (P [+] Qf x))"
apply (simp add: Rep_int_choice_f_def)
by (rule cspF_rw_left, rule cspF_Dist_com, simp)

lemma cspF_Parallel_Dist_f_l:
  "(!<f> :Y .. Pf) |[X]| Q =F[M,M]
   IF (Y ={}) THEN (DIV |[X]| Q) ELSE (!<f> x:Y .. (Pf x |[X]| Q))"
apply (simp add: Rep_int_choice_f_def)
by (rule cspF_rw_left, rule cspF_Dist_com, simp)

lemma cspF_Parallel_Dist_f_r:
  "P |[X]| (!<f> :Y .. Qf) =F[M,M]
   IF (Y ={}) THEN (P |[X]| DIV) ELSE (!<f> x:Y .. (P |[X]| Qf x))"
apply (simp add: Rep_int_choice_f_def)
by (rule cspF_rw_left, rule cspF_Dist_com, simp)

lemma cspF_Hiding_Dist_f:
  "(!<f> :Y .. Pf) -- X =F[M,M] !<f> x:Y .. (Pf x -- X)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com)

lemma cspF_Renaming_Dist_f:
  "(!<f> :X .. Pf) [[r]] =F[M,M] !<f> x:X .. (Pf x [[r]])"
by (simp add: Rep_int_choice_f_def cspF_Dist_com)

lemma cspF_Seq_compo_Dist_f:
  "(!<f> :X .. Pf) ;; Q =F[M,M] !<f> x:X .. (Pf x ;; Q)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com)

lemma cspF_Depth_rest_Dist_f:
  "(!<f> :X .. Pf) |. n =F[M,M] !<f> x:X .. (Pf x |. n)"
by (simp add: Rep_int_choice_f_def cspF_Dist_com)

(*********************************************************
                     Dist laws
 *********************************************************)

lemmas cspF_Dist_f = cspF_Ext_choice_Dist_f_l cspF_Ext_choice_Dist_f_r
                           cspF_Parallel_Dist_f_l   cspF_Parallel_Dist_f_r
                           cspF_Hiding_Dist_f       cspF_Renaming_Dist_f
                           cspF_Seq_compo_Dist_f    cspF_Depth_rest_Dist_f

lemmas cspF_Dist_f_nonempty =
       cspF_Ext_choice_Dist_f_l_nonempty cspF_Ext_choice_Dist_f_r_nonempty
       cspF_Parallel_Dist_f_l_nonempty   cspF_Parallel_Dist_f_r_nonempty
       cspF_Hiding_Dist_f       cspF_Renaming_Dist_f
       cspF_Seq_compo_Dist_f    cspF_Depth_rest_Dist_f

(*** all rules ***)

lemmas cspF_Dist = cspF_Dist_sum
                   cspF_Dist_nat cspF_Dist_set cspF_Dist_com cspF_Dist_f

lemmas cspF_Dist_nonempty = cspF_Dist_sum_nonempty
                            cspF_Dist_nat_nonempty
                            cspF_Dist_set_nonempty
                            cspF_Dist_com_nonempty
                            cspF_Dist_f_nonempty

(*****************************************************************

      additional distribution over replicated internal choice

         1. (!! :X .. (a -> P))
         2. (!! :Y .. (? :X -> P))

 *****************************************************************)

(*********************************************************
              Dist law for Act_prefix
 *********************************************************)

lemma cspF_Act_prefix_Dist_sum:
  "sumset C ~= {} ==>
   a -> (!! :C .. Pf) =F[M,M] !! c:C .. (a -> Pf c)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Act_prefix_Dist)
apply (rule order_antisym)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (erule disjE)
  apply (force)

  apply (elim conjE exE bexE)
  apply (rule_tac x="c" in bexI)
  apply (force)
  apply (simp)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE bexE exE)
  apply (simp)
  apply (simp)
  apply (rule_tac x="c" in bexI)
  apply (simp)
  apply (simp)
done

(*********************************************************
              Dist_nat law for Ext_pre_choice
 *********************************************************)

lemma cspF_Ext_pre_choice_Dist_sum:
  "sumset C ~= {} ==>
   ? x:X -> (!! c:C .. (Pf c) x) =F[M,M] !! c:C .. (? :X -> (Pf c))"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Ext_pre_choice_Dist)
apply (rule order_antisym)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (erule disjE)
  apply (force)

  apply (elim conjE exE bexE)
  apply (rule_tac x="c" in bexI)
  apply (force)
  apply (simp)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE exE bexE)
  apply (simp)
  apply (simp)
  apply (rule_tac x="c" in bexI)
  apply (simp)
  apply (simp)
done

(*****************************************************************
                     for convenienve
 *****************************************************************)

(* nat *)

lemma cspF_Act_prefix_Dist_nat:
  "N ~= {} ==>
   a -> (!nat :N .. Pf) =F[M,M] !nat n:N .. (a -> Pf n)"
by (simp add: Rep_int_choice_ss_def cspF_Act_prefix_Dist_sum)

lemma cspF_Ext_pre_choice_Dist_nat:
  "N ~= {} ==>
   ? x:X -> (!nat n:N .. (Pf n) x) =F[M,M] !nat n:N .. (? :X -> (Pf n))"
by (simp add: Rep_int_choice_ss_def cspF_Ext_pre_choice_Dist_sum)

(* set *)

lemma cspF_Act_prefix_Dist_set:
  "Xs ~= {} ==>
   a -> (!set :Xs .. Pf) =F[M,M] !set X:Xs .. (a -> Pf X)"
by (simp add: Rep_int_choice_ss_def cspF_Act_prefix_Dist_sum)

lemma cspF_Ext_pre_choice_Dist_set:
  "Ys ~= {} ==>
   ? x:X -> (!set Y:Ys .. (Pf Y) x) =F[M,M] !set Y:Ys .. (? :X -> (Pf Y))"
by (simp add: Rep_int_choice_ss_def cspF_Ext_pre_choice_Dist_sum)

(* com *)

lemma cspF_Act_prefix_Dist_com:
  "X ~= {} ==>
   a -> (! :X .. Pf) =F[M,M] ! x:X .. (a -> Pf x)"
by (simp add: Rep_int_choice_com_def cspF_Act_prefix_Dist_set)

lemma cspF_Ext_pre_choice_Dist_com:
  "Y ~= {} ==>
   ? x:X -> (! y:Y .. (Pf y) x) =F[M,M] ! y:Y .. (? :X -> (Pf y))"
by (simp add: Rep_int_choice_com_def cspF_Ext_pre_choice_Dist_set)

(* f *)

lemma cspF_Act_prefix_Dist_f:
  "X ~= {} ==>
   a -> (!<f> :X .. Pf) =F[M,M] !<f> x:X .. (a -> Pf x)"
by (simp add: Rep_int_choice_f_def cspF_Act_prefix_Dist_com)

lemma cspF_Ext_pre_choice_Dist_f:
  "Y ~= {} ==>
   ? x:X -> (!<f> y:Y .. (Pf y) x) =F[M,M] !<f> y:Y .. (? :X -> (Pf y))"
by (simp add: Rep_int_choice_f_def cspF_Ext_pre_choice_Dist_com)

(*** arias ***)

lemmas cspF_Act_prefix_Dist
     = cspF_Act_prefix_Dist_sum
       cspF_Act_prefix_Dist_nat
       cspF_Act_prefix_Dist_set
       cspF_Act_prefix_Dist_com
       cspF_Act_prefix_Dist_f

lemmas cspF_Ext_pre_choice_Dist
     = cspF_Ext_pre_choice_Dist_sum
       cspF_Ext_pre_choice_Dist_nat
       cspF_Ext_pre_choice_Dist_set
       cspF_Ext_pre_choice_Dist_com
       cspF_Ext_pre_choice_Dist_f

(*****************************************************************
      distribution over external choice
         1. (P1 [+] P2) [[r]]
         2. (P1 [+] P2) |. n
 *****************************************************************)

(*********************
     [[r]]-[+]-dist
 *********************)

lemma cspF_Renaming_Ext_dist:
  "(P1 [+] P2) [[r]] =F[M,M]
   (P1 [[r]]) [+] (P2 [[r]])"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Renaming_Ext_dist)
apply (rule order_antisym)

(* => *)
 apply (rule)
 apply (simp add: in_failures in_traces)
 apply (force)

(* <= *)
 apply (rule)
 apply (simp add: in_failures in_traces)
 apply (force)
done

(*********************
     |.-[+]-dist
 *********************)

lemma cspF_Depth_rest_Ext_dist:
  "(P1 [+] P2) |. n =F[M,M]
   (P1 |. n) [+] (P2 |. n)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Depth_rest_Ext_dist)
apply (rule order_antisym)

(* => *)
 apply (rule)
 apply (simp add: in_failures in_traces)
 apply (force)

(* <= *)
 apply (rule)
 apply (simp add: in_failures in_traces)
 apply (force)
done

lemmas cspF_Ext_dist = cspF_Renaming_Ext_dist cspF_Depth_rest_Ext_dist

(*---------------------------------------------------------*
 |                   complex distribution                  |
 *---------------------------------------------------------*)

(*********************
     !!-input-!set
 *********************)

lemma cspF_Rep_int_choice_sum_input_set:
  "(!! c:C .. (? :(Yf c) -> Rff c))
   =F[M,M]
   (!set Y : {(Yf c)|c. c: sumset C} ..
      (? a : Y -> (!! c:{c:C. a : Yf c}s .. Rff c a)))"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_int_choice_input_set)
apply (rule order_antisym)

(* => *)
 apply (rule, simp add: in_failures)
 apply (elim disjE conjE exE bexE)
 apply (simp_all)
 apply (force)
 apply (force)

(* <= *)
 apply (rule, simp add: in_failures)
 apply (elim disjE conjE exE)
 apply (simp_all)
apply (rule_tac x="c" in bexI)
apply (simp)
apply (simp)
apply (rule_tac x="ca" in bexI)
apply (simp)
apply (simp)
done

lemma cspF_Rep_int_choice_nat_input_set:
  "(!nat n:N .. (? :(Yf n) -> Rff n))
   =F[M,M]
   (!set Y : {(Yf n)|n. n:N} .. (? a : Y -> (!nat n:{n:N. a : Yf n} .. Rff n a)))"
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_rw_left)
apply (rule cspF_Rep_int_choice_sum_input_set)
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_decompo)
apply (auto)
apply (rule_tac x="type2 n" in exI)
by (auto)

lemma cspF_Rep_int_choice_set_input_set:
  "(!set X:Xs .. (? :(Yf X) -> Rff X))
   =F[M,M]
   (!set Y : {(Yf X)|X. X:Xs} .. (? a : Y -> (!set X:{X:Xs. a : Yf X} .. Rff X a)))"
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_rw_left)
apply (rule cspF_Rep_int_choice_sum_input_set)
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_decompo)
apply (auto)
apply (rule_tac x="type1 X" in exI)
by (auto)

lemmas cspF_Rep_int_choice_input_set =
       cspF_Rep_int_choice_sum_input_set
       cspF_Rep_int_choice_nat_input_set
       cspF_Rep_int_choice_set_input_set

(*-------------------------------*
          !!-[+]-Dist
 *-------------------------------*)

lemma cspF_Rep_int_choice_Ext_Dist_sum:
  "ALL c:sumset C. (Qf c = SKIP | Qf c = DIV) ==>
   (!! c:C .. (Pf c [+] Qf c)) =F[M,M]
   ((!! :C .. Pf) [+] (!! :C .. Qf))"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_int_choice_Ext_Dist)
apply (rule order_antisym)

(* <= *)
 apply (rule)
 apply (simp add: in_failures in_traces)
 apply (elim conjE exE bexE disjE)

  apply (drule_tac x="c" in bspec, simp)
  apply (erule disjE)
  apply (simp add: in_failures)
  apply (rule disjI2)
  apply (rule disjI2)
  apply (rule_tac x="c" in bexI)
  apply (simp add: in_traces)
  apply (simp)

  apply (simp add: in_failures)
  apply (force)

  apply (drule_tac x="c" in bspec, simp)
  apply (erule disjE)
  apply (simp add: in_failures)
  apply (rule disjI2)
  apply (rule_tac x="c" in bexI)
  apply (simp add: in_failures)
  apply (simp)

  apply (simp add: in_failures)
  apply (force)

  apply (drule_tac x="c" in bspec, simp)
  apply (erule disjE)
  apply (simp add: in_failures)
  apply (rule disjI2)
  apply (rule disjI2)
  apply (rule_tac x="c" in bexI)
  apply (simp add: in_traces)
  apply (simp)

  apply (simp add: in_traces)

(* => *)
 apply (rule)
 apply (simp add: in_failures in_traces)
 apply (elim conjE exE bexE disjE)
 apply (simp_all)

  apply (case_tac "EX c: sumset C. Qf c = SKIP")
  apply (erule bexE)
  apply (rule_tac x="cb" in bexI)
  apply (simp add: in_failures in_traces)
   apply (case_tac "Qf ca = SKIP")
   apply (simp add: in_failures)
   apply (case_tac "Qf ca = DIV")
   apply (simp add: in_failures)
   apply (fast)
  apply (simp)

  apply (simp add: in_failures in_traces)

  apply (force)
  apply (force)
  apply (force)
  apply (force)
done

lemma cspF_Rep_int_choice_Ext_Dist_nat:
  "ALL n:N. (Qf n = SKIP | Qf n = DIV) ==>
   (!nat n:N .. (Pf n [+] Qf n)) =F[M,M]
   ((!nat :N .. Pf) [+] (!nat :N .. Qf))"
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_Rep_int_choice_Ext_Dist_sum)
by (auto)

lemma cspF_Rep_int_choice_Ext_Dist_set:
  "ALL X:Xs. (Qf X = SKIP | Qf X = DIV) ==>
   (!set X:Xs .. (Pf X [+] Qf X)) =F[M,M]
   ((!set :Xs .. Pf) [+] (!set :Xs .. Qf))"
apply (simp add: Rep_int_choice_ss_def)
apply (rule cspF_Rep_int_choice_Ext_Dist_sum)
by (auto)

lemma cspF_Rep_int_choice_Ext_Dist_com:
  "ALL a:X. (Qf a = SKIP | Qf a = DIV) ==>
   (! a:X .. (Pf a [+] Qf a)) =F[M,M]
   ((! :X .. Pf) [+] (! :X .. Qf))"
apply (simp add: Rep_int_choice_com_def)
apply (rule cspF_Rep_int_choice_Ext_Dist_set)
by (auto)

lemma cspF_Rep_int_choice_Ext_Dist_f:
  "[| inj f ; ALL a:X. (Qf a = SKIP | Qf a = DIV) |] ==>
   (!<f> a:X .. (Pf a [+] Qf a)) =F[M,M]
   ((!<f> :X .. Pf) [+] (!<f> :X .. Qf))"
apply (simp add: Rep_int_choice_f_def)
apply (rule cspF_Rep_int_choice_Ext_Dist_com)
by (auto)

lemmas cspF_Rep_int_choice_Ext_Dist =
       cspF_Rep_int_choice_Ext_Dist_sum
       cspF_Rep_int_choice_Ext_Dist_nat
       cspF_Rep_int_choice_Ext_Dist_set
       cspF_Rep_int_choice_Ext_Dist_com
       cspF_Rep_int_choice_Ext_Dist_f

(*-------------------------------*
          !!-input-Dist
 *-------------------------------*)

(* SKIP *)

lemma cspF_Rep_int_choice_input_Dist_SKIP:
  "(!set X:Xs .. (? :X -> Pf)) [+] SKIP =F[M,M]
   (? :(Union Xs) -> Pf) [+] SKIP"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_int_choice_input_Dist)
apply (rule order_antisym)

(* => *)
 apply (rule, simp add: in_traces in_failures)
 apply (elim conjE exE disjE bexE)
 apply (simp_all)
 apply (force)

(* <= *)
 apply (rule, simp add: in_traces in_failures)
 apply (elim conjE exE disjE bexE)
 apply (simp_all)
 apply (force)
done

(* DIV *)

lemma cspF_Rep_int_choice_input_Dist_DIV:
  "(!set X:Xs .. (? :X -> Pf)) [+] DIV =F[M,M] (? :(Union Xs) -> Pf) [+] DIV"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_int_choice_input_Dist)
apply (rule order_antisym)

(* => *)
 apply (rule, simp add: in_traces in_failures)
 apply (elim conjE exE disjE bexE)
 apply (simp_all)
 apply (force)

(* <= *)
 apply (rule, simp add: in_traces in_failures)
 apply (elim conjE exE disjE bexE)
 apply (simp_all)
 apply (force)
done

(* SKIP or DIV *)

lemma cspF_Rep_int_choice_input_Dist:
  "Q = SKIP | Q = DIV ==>
   (!set X:Xs .. (? :X -> Pf)) [+] Q =F[M,M] (? :(Union Xs) -> Pf) [+] Q"
apply (erule disjE)
apply (simp add: cspF_Rep_int_choice_input_Dist_SKIP)
apply (simp add: cspF_Rep_int_choice_input_Dist_DIV)
done

(*-------------------------------*
          !!-Ext-choice-SKIP
 *-------------------------------*)

lemma cspF_Rep_int_choice_sum_Ext_choice:
  "Q = SKIP | Q = DIV ==>
  (!! c:C .. (? :(Xf c) -> Pf c)) [+] Q
    =F[M,M] (? x:Union {(Xf c)|c. c: sumset C} ->
                (!! c:{c:C. x: Xf c}s  .. Pf c x)) [+] Q"
apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (rule cspF_Rep_int_choice_input_set)
apply (rule cspF_reflex)

apply (rule cspF_rw_left)
apply (rule cspF_Rep_int_choice_input_Dist)
apply (simp)
apply (simp)
done

(*** nat ***)

lemma cspF_Rep_int_choice_nat_Ext_choice:
  "Q = SKIP | Q = DIV ==>
  (!nat n:N .. (? :(Xf n) -> Pf n)) [+] Q
    =F[M,M] (? x:Union {(Xf n)|n. n:N} -> (!nat n:{n:N. x: Xf n}  .. Pf n x)) [+] Q"
apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (rule cspF_Rep_int_choice_input_set)
apply (rule cspF_reflex)

apply (rule cspF_rw_left)
apply (rule cspF_Rep_int_choice_input_Dist)
apply (simp)
apply (simp)
done

(*** set ***)

lemma cspF_Rep_int_choice_set_Ext_choice:
  "Q = SKIP | Q = DIV ==>
  (!set X:Xs .. (? :(Xf X) -> Pf X)) [+] Q
    =F[M,M] (? x:Union {(Xf X)|X. X:Xs} -> (!set X:{X:Xs. x: Xf X}  .. Pf X x)) [+] Q"
apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (rule cspF_Rep_int_choice_input_set)
apply (rule cspF_reflex)

apply (rule cspF_rw_left)
apply (rule cspF_Rep_int_choice_input_Dist)
apply (simp)
apply (simp)
done

lemmas cspF_Rep_int_choice_Ext_choice =
       cspF_Rep_int_choice_sum_Ext_choice
       cspF_Rep_int_choice_nat_Ext_choice
       cspF_Rep_int_choice_set_Ext_choice

(* =================================================== *
 |             addition for CSP-Prover 5               |
 * =================================================== *)

(* --------------------------------------------------- *
     distribution hiding over sequential composition
 * --------------------------------------------------- *)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Seq_compo_hide_dist:
  "(P ;; Q) -- X =F[M,M] (P -- X) ;; (Q -- X)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Seq_compo_hide_dist)
apply (rule order_antisym)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim conjE exE disjE)
 apply (simp_all)

  (* 1 *)
 apply (rule disjI1)
 apply (rule_tac x="sa" in exI)
 apply (simp)

  (* 2 *)
 apply (rule disjI2)
 apply (rule_tac x="sb --tr X" in exI)
 apply (rule_tac x="t --tr X" in exI)
 apply (simp)
 apply (rule conjI)
  apply (simp add: in_traces)
  apply (rule_tac x="sb ^^^ <Tick>" in exI)
  apply (simp)
  apply (rule_tac x="t" in exI)
  apply (simp)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE exE)
  (* 1 *)
  apply (rule_tac x="sa" in exI)
  apply (simp)
  (* 2 *)
  apply (simp add: in_traces)
  apply (elim conjE exE)
  apply (insert trace_last_noTick_or_Tick)
  apply (drule_tac x="sc" in spec)
  apply (elim disjE conjE exE)

   apply (subgoal_tac "noTick(sc --tr X)")
   apply (rotate_tac 4)
   apply (drule sym)
   apply (simp del: hide_tr_noTick)
   apply (simp)

   apply (simp)
   apply (rule_tac x="sd ^^^ sb" in exI)
   apply (simp)
   apply (rule disjI2)
   apply (rule_tac x="sd" in exI)
   apply (rule_tac x="sb" in exI)
   apply (simp)
done

(* --------------------------------------------------- *
         distribution hiding over interleaving
 * --------------------------------------------------- *)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Interleave_hide_dist:
  "(P ||| Q) -- X =F[M,M] (P -- X) ||| (Q -- X)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Interleave_hide_dist)
apply (rule order_antisym)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim conjE exE)
 apply (simp)

 apply (rule_tac x="(Ev ` X Un Y) Int Xa" in exI)
 apply (rule_tac x="(Ev ` X Un Z) Int Xa" in exI)
 apply (intro conjI)

 (* 1 *)
  apply (force)

 (* 2 *)
  apply (force)

 (* 3 *)
  apply (rule_tac x="sb --tr X" in exI)
  apply (rule_tac x="t --tr X" in exI)
  apply (simp add: interleave_of_hide_tr_ex)
  apply (intro conjI)

   apply (force)

   apply (rule_tac x="sb" in exI)
   apply (simp)
   apply (subgoal_tac "Ev ` X Un (Ev ` X Un Y) Int Xa <= Y")
   apply (rule memF_F2)
   apply (simp)
   apply (simp)
   apply (force)

   apply (rule_tac x="t" in exI)
   apply (simp)
   apply (subgoal_tac "Ev ` X Un (Ev ` X Un Z) Int Xa <= Z")
   apply (rule memF_F2)
   apply (simp)
   apply (simp)
   apply (force)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim conjE exE)
 apply (simp add: interleave_of_hide_tr_ex)
 apply (elim conjE exE)
 apply (simp)
 apply (rule_tac x="v" in exI)
 apply (simp)
 apply (rule_tac x="Ev ` X Un Y" in exI)
 apply (rule_tac x="Ev ` X Un Z" in exI)
 apply (intro conjI)
  apply (force)
  apply (force)
  apply (force)
done

(* --------------------------------------------------- *
    distribution renaming over sequential composition
 * --------------------------------------------------- *)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Seq_compo_renaming_dist:
  "(P ;; Q) [[r]] =F[M,M] (P [[r]]) ;; (Q [[r]])"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Seq_compo_renaming_dist)
apply (rule order_antisym)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim conjE exE disjE)
 apply (simp_all)

  (* 1 *)
 apply (rule disjI1)
 apply (simp add: ren_tr_noTick_left)
 apply (rule_tac x="sa" in exI)
 apply (simp add: ren_inv_insert_Tick)

  (* 2 *)
 apply (rule disjI2)
 apply (simp add: ren_tr_appt_decompo_left)
 apply (elim conjE exE)
 apply (simp)
 apply (rule_tac x="t1" in exI)
 apply (rule_tac x="t2" in exI)
 apply (simp)
 apply (rule conjI)
  apply (simp add: in_traces)
  apply (rule_tac x="sb ^^^ <Tick>" in exI)
  apply (simp add: ren_tr_noTick_left)

  apply (simp add: ren_tr_noTick_left)
  apply (rule_tac x="t" in exI)
  apply (simp)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE exE)
  (* 1 *)
  apply (rule_tac x="sa" in exI)
  apply (simp add: ren_inv_insert_Tick)
  apply (simp add: ren_tr_noTick_right)

  (* 2 *)
  apply (simp add: in_traces)
  apply (elim conjE exE)
  apply (simp add: ren_tr_appt_decompo_right)
  apply (elim conjE exE)
  apply (simp)
  apply (rule_tac x="s1 ^^^ sb" in exI)
  apply (simp)

  apply (rule conjI)
   apply (rule_tac x="s1" in exI)
   apply (rule_tac x="sb" in exI)
   apply (simp)

   apply (rule disjI2)
   apply (rule_tac x="s1" in exI)
   apply (rule_tac x="sb" in exI)
   apply (simp)
done

(* --------------------------------------------------- *
         distribution renaming over interleaving
 * --------------------------------------------------- *)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Interleave_renaming_dist:
  "(P ||| Q) [[r]] =F[M,M] (P [[r]]) ||| (Q [[r]])"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Interleave_renaming_dist)
apply (rule order_antisym)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim conjE exE disjE)
  apply (case_tac "Tick ~: Y & Tick ~: Z")

  apply (rule_tac x="X" in exI)
  apply (rule_tac x="X" in exI)
  apply (simp)
  apply (insert interleave_of_ren_tr_only_if_all)
  apply (drule_tac x="sa" in spec)
  apply (drule_tac x="r" in spec)
  apply (drule_tac x="s" in spec)
  apply (drule_tac x="sb" in spec)
  apply (drule_tac x="t" in spec)
  apply (simp)
  apply (elim conjE exE)
  apply (rule_tac x="s'" in exI)
  apply (rule_tac x="t'" in exI)
  apply (force)

  apply (subgoal_tac "Tick : X")

  apply (rule_tac x="(X-{Tick}) Un (Y Int {Tick})" in exI)
  apply (rule_tac x="(X-{Tick}) Un (Z Int {Tick})" in exI)
  apply (intro conjI)

   apply (force)
   apply (force)

   apply (drule_tac x="sa" in spec)
   apply (drule_tac x="r" in spec)
   apply (drule_tac x="s" in spec)
   apply (drule_tac x="sb" in spec)
   apply (drule_tac x="t" in spec)
   apply (simp)
   apply (elim conjE exE)
   apply (rule_tac x="s'" in exI)
   apply (rule_tac x="t'" in exI)
   apply (simp)
   apply (intro conjI)

    apply (rule_tac x="sb" in exI)
    apply (simp)
    apply (rule memF_F2)
    apply (simp)
    apply (force)

    apply (rule_tac x="t" in exI)
    apply (simp)
    apply (rule memF_F2)
    apply (simp)
    apply (force)

  apply (simp add: ren_inv_def)
  apply (force)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE exE)
 apply (erule rem_asmE)
 apply (insert interleave_of_ren_tr_if_all)
  apply (drule_tac x="s" in spec)
  apply (drule_tac x="r" in spec)
  apply (drule_tac x="sb" in spec)
  apply (drule_tac x="sc" in spec)
  apply (drule_tac x="sa" in spec)
  apply (drule_tac x="t" in spec)
  apply (simp)
  apply (elim conjE exE)

   apply (rule_tac x="u" in exI)
   apply (simp)
   apply (rule_tac x="[[r]]inv Y" in exI)
   apply (rule_tac x="[[r]]inv Z" in exI)

  apply (simp add: ren_inv_def)
  apply (auto)
done

(* --------------------------------------------------- *
     distribution internal choice over prefix
 * --------------------------------------------------- *)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Act_prefix_dist:
  "a -> (P |~| Q) =F[M,M] (a -> P) |~| (a -> Q)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Act_prefix_dist)
apply (rule order_antisym)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (erule disjE)
  apply (force)

  apply (elim conjE exE disjE bexE)
  apply (force)
  apply (force)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE bexE exE)
  apply (simp)
  apply (simp)
  apply (force)
  apply (force)
done

lemma cspF_Int_choice_Act_prefix_delay:
  "(a -> P) |~| (a -> Q) =F[M,M] a -> (P |~| Q)"
apply (rule cspF_sym)
apply (simp add: cspF_Act_prefix_dist)
done

lemma cspF_Int_choice_Act_prefix_delay_eq:
  "a = b ==> (a -> P) |~| (b -> Q) =F[M,M] a -> (P |~| Q)"
apply (simp add: cspF_Int_choice_Act_prefix_delay)
done

(* --------------------------------------------------- *
     distribution internal choice over prefix choice
 * --------------------------------------------------- *)

(*------------------*
 |      csp law     |
 *------------------*)

lemma cspF_Ext_pre_choice_dist:
  "? x:X -> (Pf x |~| Qf x) =F[M,M] (? x:X -> Pf x) |~| (? x:X -> Qf x)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Ext_pre_choice_dist)
apply (rule order_antisym)

(* <= *)
 apply (rule)
 apply (simp add: in_failures)
 apply (erule disjE)
  apply (force)

  apply (elim conjE exE disjE bexE)
  apply (force)
  apply (force)

(* => *)
 apply (rule)
 apply (simp add: in_failures)
 apply (elim disjE conjE bexE exE)
  apply (simp)
  apply (simp)
  apply (force)
  apply (force)
done

lemma cspF_Int_choice_Ext_pre_choice_delay:
  "(? x:X -> Pf x) |~| (? x:X -> Qf x)  =F[M,M] ? x:X -> (Pf x |~| Qf x)"
apply (rule cspF_sym)
apply (simp add: cspF_Ext_pre_choice_dist)
done

lemma cspF_Int_choice_Ext_pre_choice_delay_eq:
  "X = Y ==> (? x:X -> Pf x) |~| (? x:Y -> Qf x)  =F[M,M] ? x:X -> (Pf x |~| Qf x)"
apply (simp add: cspF_Int_choice_Ext_pre_choice_delay)
done

(*  replicated internal choice *)

lemma cspF_Act_prefix_delay_sum:
  "!! c:C .. (a -> Pf c) =F[M,M]
   IF (sumset C = {}) THEN DIV ELSE (a -> (!! c:C .. (Pf c)))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "sumset C = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Act_prefix_Dist)
done

lemma cspF_Ext_pre_choice_delay_sum:
  "!! c:C .. (? :X -> (Pf c)) =F[M,M]
   IF (sumset C = {}) THEN DIV ELSE (? x:X -> (!! c:C .. (Pf c) x))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "sumset C = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Ext_pre_choice_Dist)
done

lemma cspF_Act_prefix_delay_nat:
  "!nat n:N .. (a -> Pf n) =F[M,M]
   IF (N = {}) THEN DIV ELSE (a -> (!nat n:N .. (Pf n)))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "N = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Act_prefix_Dist)
done

lemma cspF_Ext_pre_choice_delay_nat:
  "!nat n:N .. (? :X -> (Pf n)) =F[M,M]
   IF (N = {}) THEN DIV ELSE (? x:X -> (!nat n:N .. (Pf n) x))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "N = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Ext_pre_choice_Dist)
done

lemma cspF_Act_prefix_delay_set:
  "!set X:Xs .. (a -> Pf X) =F[M,M]
   IF (Xs = {}) THEN DIV ELSE (a -> (!set X:Xs .. (Pf X)))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "Xs = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Act_prefix_Dist)
done

lemma cspF_Ext_pre_choice_delay_set:
  "!set Y:Xs .. (? :X -> (Pf Y)) =F[M,M]
   IF (Xs = {}) THEN DIV ELSE (? x:X -> (!set Y:Xs .. (Pf Y) x))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "Xs = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Ext_pre_choice_Dist)
done

lemma cspF_Act_prefix_delay_com:
  "! x:X .. (a -> Pf x) =F[M,M]
   IF (X = {}) THEN DIV ELSE (a -> (! :X .. Pf))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "X = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Act_prefix_Dist)
done

lemma cspF_Ext_pre_choice_delay_com:
  "! y:Y .. (? :X -> (Pf y)) =F[M,M]
   IF (Y = {}) THEN DIV ELSE (? x:X -> (! y:Y .. (Pf y) x))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "Y = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Ext_pre_choice_Dist)
done

lemma cspF_Act_prefix_delay_f:
  "inj f ==>
   !<f> x:X .. (a -> Pf x) =F[M,M]
   IF (X = {}) THEN DIV ELSE (a -> (!<f> :X .. Pf))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "X = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Act_prefix_Dist)
done

lemma cspF_Ext_pre_choice_delay_f:
  "inj f ==>
   !<f> y:Y .. (? :X -> (Pf y)) =F[M,M]
   IF (Y = {}) THEN DIV ELSE (? x:X -> (!<f> y:Y .. (Pf y) x))"
apply (rule cspF_rw_right)
apply (rule cspF_IF_split)
apply (case_tac "Y = {}")
apply (simp add: cspF_Rep_int_choice_DIV)
apply (simp)
apply (rule cspF_sym)
apply (simp add: cspF_Ext_pre_choice_Dist)
done

lemmas cspF_choice_delay =
       cspF_Int_choice_Act_prefix_delay
       cspF_Int_choice_Ext_pre_choice_delay
       cspF_Act_prefix_delay_sum
       cspF_Ext_pre_choice_delay_sum
       cspF_Act_prefix_delay_nat
       cspF_Ext_pre_choice_delay_nat
       cspF_Act_prefix_delay_set
       cspF_Ext_pre_choice_delay_set
       cspF_Act_prefix_delay_com
       cspF_Ext_pre_choice_delay_com
       cspF_Act_prefix_delay_f
       cspF_Ext_pre_choice_delay_f

lemmas cspF_choice_delay_eq =
       cspF_Int_choice_Act_prefix_delay_eq
       cspF_Int_choice_Ext_pre_choice_delay_eq

(*********************************************************
                       P |[X,Y]| Q
 *********************************************************)

(* ---------- *
    |~| left
 * ---------- *)

lemma cspF_Alpha_Parallel_dist_l:
  "(P1 |~| P2) |[X,Y]| Q =F[M,M]
   (P1 |[X,Y]| Q) |~| (P2 |[X,Y]| Q)"
apply (simp add: Alpha_parallel_def)

apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (simp)
apply (rule cspF_dist)
apply (rule cspF_reflex)
apply (rule cspF_rw_left)
apply (rule cspF_dist)
apply (simp)
done

(* ---------- *
    |~| right
 * ---------- *)
lemma cspF_Alpha_Parallel_dist_r:
  "P |[X,Y]| (Q1 |~| Q2) =F[M,M]
   (P |[X,Y]| Q1) |~| (P |[X,Y]| Q2)"
apply (simp add: Alpha_parallel_def)

apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (simp)
apply (rule cspF_reflex)
apply (rule cspF_dist)
apply (rule cspF_rw_left)
apply (rule cspF_dist)
apply (simp)
done

(* ---------- *
    !! left
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_sum_l_nonempty:
  "sumset C ~= {} ==>
     (!! :C .. Pf) |[X,Y]| Q =F[M,M]
     !! c:C .. (Pf c |[X,Y]| Q)"
apply (simp add: Alpha_parallel_def)

apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (simp)
apply (rule cspF_Parallel_Dist_sum_l_nonempty)
apply (simp)
apply (rule cspF_reflex)
apply (rule cspF_rw_left)
apply (rule cspF_Parallel_Dist_sum_l_nonempty)
apply (simp)
apply (simp)
done

lemma cspF_Alpha_Parallel_Dist_sum_l:
  "(!! :C .. Pf) |[X,Y]| Q =F[M,M]
   IF (sumset C={}) THEN (DIV |[X,Y]| Q) ELSE (!! c:C .. (Pf c |[X,Y]| Q))"
apply (case_tac "sumset C={}")
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_decompo_Alpha_parallel)
apply (simp)+
apply (simp add: cspF_Rep_int_choice_empty)
apply (simp)

apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_Alpha_Parallel_Dist_sum_l_nonempty)
apply (simp)
done

(* ---------- *
    !! right
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_sum_r_nonempty:
  "sumset C ~= {} ==>
     P |[X,Y]| (!! :C .. Qf) =F[M,M]
     !! c:C .. (P |[X,Y]| Qf c)"
apply (rule cspF_rw_left)
apply (rule cspF_Alpha_parallel_commut)
apply (rule cspF_rw_left)
apply (rule cspF_Alpha_Parallel_Dist_sum_l_nonempty, simp)
apply (rule cspF_decompo, simp)
apply (rule cspF_Alpha_parallel_commut)
done

lemma cspF_Alpha_Parallel_Dist_sum_r:
  "P |[X,Y]| (!! :C .. Qf) =F[M,M]
   IF (sumset C={}) THEN (P |[X,Y]| DIV) ELSE (!! c:C .. (P |[X,Y]| Qf c))"
apply (case_tac "sumset C={}")
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_decompo_Alpha_parallel)
apply (simp)+
apply (simp add: cspF_Rep_int_choice_empty)
apply (simp)

apply (rule cspF_rw_right)
apply (rule cspF_IF)
apply (rule cspF_Alpha_Parallel_Dist_sum_r_nonempty)
apply (simp)
done

(* ---------- *
   !nat left
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_nat_l_nonempty:
  "N ~= {} ==>
     (!nat :N .. Pf) |[X,Y]| Q =F[M,M]
     !nat n:N .. (Pf n |[X,Y]| Q)"
by (simp add: Rep_int_choice_ss_def cspF_Alpha_Parallel_Dist_sum_l_nonempty)

(*** Dist ***)

lemma cspF_Alpha_Parallel_Dist_nat_l:
  "(!nat :N .. Pf) |[X,Y]| Q =F[M,M]
   IF (N={}) THEN (DIV |[X,Y]| Q) ELSE (!nat n:N .. (Pf n |[X,Y]| Q))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_sum_l, simp)

(* ---------- *
   !nat right
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_nat_r_nonempty:
  "N ~= {} ==>
     P |[X,Y]| (!nat :N .. Qf) =F[M,M]
     !nat n:N .. (P |[X,Y]| Qf n)"
by (simp add: Rep_int_choice_ss_def cspF_Alpha_Parallel_Dist_sum_r_nonempty)

(*** Dist ***)

lemma cspF_Alpha_Parallel_Dist_nat_r:
  "P |[X,Y]| (!nat :N .. Qf) =F[M,M]
   IF (N={}) THEN (P |[X,Y]| DIV) ELSE (!nat n:N .. (P |[X,Y]| Qf n))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_sum_r, simp)

(* ---------- *
   !set left
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_set_l_nonempty:
  "Xs ~= {} ==>
     (!set :Xs .. Pf) |[Y,Z]| Q =F[M,M]
     !set X:Xs .. (Pf X |[Y,Z]| Q)"
by (simp add: Rep_int_choice_ss_def cspF_Alpha_Parallel_Dist_sum_l_nonempty)

(*** Dist ***)

lemma cspF_Alpha_Parallel_Dist_set_l:
  "(!set :Xs .. Pf) |[Y,Z]| Q =F[M,M]
   IF (Xs={}) THEN (DIV |[Y,Z]| Q) ELSE (!set X:Xs .. (Pf X |[Y,Z]| Q))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_sum_l, simp)

(* ---------- *
   !set right
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_set_r_nonempty:
  "Xs ~= {} ==>
     P |[Y,Z]| (!set :Xs .. Qf) =F[M,M]
     !set X:Xs .. (P |[Y,Z]| Qf X)"
by (simp add: Rep_int_choice_ss_def cspF_Alpha_Parallel_Dist_sum_r_nonempty)

(*** Dist ***)

lemma cspF_Alpha_Parallel_Dist_set_r:
  "P |[Y,Z]| (!set :Xs .. Qf) =F[M,M]
   IF (Xs={}) THEN (P |[Y,Z]| DIV) ELSE (!set X:Xs .. (P |[Y,Z]| Qf X))"
apply (simp add: Rep_int_choice_ss_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_sum_r, simp)

(* ---------- *
     ! left
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_com_l_nonempty:
  "A ~= {}
   ==> (! :A .. Pf) |[X,Y]| Q =F[M,M] ! x:A .. (Pf x |[X,Y]| Q)"
by (simp add: Rep_int_choice_com_def cspF_Alpha_Parallel_Dist_set_l_nonempty)

lemma cspF_Alpha_Parallel_Dist_com_l:
  "(! :A .. Pf) |[X,Y]| Q =F[M,M]
   IF (A ={}) THEN (DIV |[X,Y]| Q) ELSE (! x:A .. (Pf x |[X,Y]| Q))"
apply (simp add: Rep_int_choice_com_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_set_l, simp)

(* ---------- *
     ! right
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_com_r_nonempty:
  "A ~= {}
   ==> P |[X,Y]| (! :A .. Qf) =F[M,M] ! x:A .. (P |[X,Y]| Qf x)"
by (simp add: Rep_int_choice_com_def cspF_Alpha_Parallel_Dist_set_r_nonempty)

lemma cspF_Alpha_Parallel_Dist_com_r:
  "P |[X,Y]| (! :A .. Qf) =F[M,M]
   IF (A ={}) THEN (P |[X,Y]| DIV) ELSE (! x:A .. (P |[X,Y]| Qf x))"
apply (simp add: Rep_int_choice_com_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_set_r, simp)

(* ---------- *
   !<f> left
 * ---------- *)

lemma cspF_Alpha_Parallel_Dist_f_l_nonempty:
  "[| inj f ; A ~= {} |]
   ==> (!<f> :A .. Pf) |[X,Y]| Q =F[M,M] !<f> x:A .. (Pf x |[X,Y]| Q)"
by (simp add: Rep_int_choice_f_def cspF_Alpha_Parallel_Dist_com_l_nonempty)

lemma cspF_Alpha_Parallel_Dist_f_l:
  "(!<f> :A .. Pf) |[X,Y]| Q =F[M,M]
   IF (A ={}) THEN (DIV |[X,Y]| Q) ELSE (!<f> x:A .. (Pf x |[X,Y]| Q))"
apply (simp add: Rep_int_choice_f_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_com_l, simp)

lemma cspF_Alpha_Parallel_Dist_f_r_nonempty:
  "[| inj f ; A ~= {} |]
   ==> P |[X,Y]| (!<f> :A .. Qf) =F[M,M] !<f> x:A .. (P |[X,Y]| Qf x)"
by (simp add: Rep_int_choice_f_def cspF_Alpha_Parallel_Dist_com_r_nonempty)

lemma cspF_Alpha_Parallel_Dist_f_r:
  "P |[X,Y]| (!<f> :A .. Qf) =F[M,M]
   IF (A ={}) THEN (P |[X,Y]| DIV) ELSE (!<f> x:A .. (P |[X,Y]| Qf x))"
apply (simp add: Rep_int_choice_f_def)
by (rule cspF_rw_left, rule cspF_Alpha_Parallel_Dist_com_r, simp)

lemmas cspF_dist_Alpha_Parallel =
       cspF_Alpha_Parallel_dist_l
       cspF_Alpha_Parallel_dist_r

lemmas cspF_Dist_Alpha_Parallel =
      cspF_Alpha_Parallel_Dist_sum_l
      cspF_Alpha_Parallel_Dist_sum_r
      cspF_Alpha_Parallel_Dist_nat_l
      cspF_Alpha_Parallel_Dist_nat_r
      cspF_Alpha_Parallel_Dist_set_l
      cspF_Alpha_Parallel_Dist_set_r
      cspF_Alpha_Parallel_Dist_com_l
      cspF_Alpha_Parallel_Dist_com_r
      cspF_Alpha_Parallel_Dist_f_l
      cspF_Alpha_Parallel_Dist_f_r

lemmas cspF_Dist_Alpha_Parallel_nonempty =
      cspF_Alpha_Parallel_Dist_sum_l_nonempty
      cspF_Alpha_Parallel_Dist_sum_r_nonempty
      cspF_Alpha_Parallel_Dist_nat_l_nonempty
      cspF_Alpha_Parallel_Dist_nat_r_nonempty
      cspF_Alpha_Parallel_Dist_set_l_nonempty
      cspF_Alpha_Parallel_Dist_set_r_nonempty
      cspF_Alpha_Parallel_Dist_com_l_nonempty
      cspF_Alpha_Parallel_Dist_com_r_nonempty
      cspF_Alpha_Parallel_Dist_f_l_nonempty
      cspF_Alpha_Parallel_Dist_f_r_nonempty

(****************** to add them again ******************)

end


theory View
imports DerivedConstructions Frac
begin

subsubsection \<open>View camera\<close>
text \<open>A camera combinator similar to \<^typ>\<open>'m auth\<close>\<close>

definition map_view_rel :: "nat \<Rightarrow> ('a,'b::ofe) fmap \<Rightarrow> ('a\<rightharpoonup>(dfrac\<times>'b ag)) \<Rightarrow> bool" where
  "map_view_rel n m f \<equiv>
    \<forall>k d vag. f k = Some (d,vag) \<longrightarrow> (\<exists>v. n_equiv n vag (to_ag v) \<and> valid d \<and> fmlookup m k = Some v)"

lemma map_view_relE: "\<lbrakk>map_view_rel n m f; f k = Some (d,vag)\<rbrakk> \<Longrightarrow>
  \<exists>v. n_equiv n vag (to_ag v) \<and> valid d \<and> fmlookup m k = Some v"
  by (simp add: map_view_rel_def)

lemma map_view_rel_mono:
  assumes "map_view_rel n1 m1 f1" "n_equiv n2 m1 m2" "n_incl n2 f2 f1" "n2 \<le> n1"
  shows "map_view_rel n2 m2 f2"
proof -
  from assms(1) have rel1: "\<forall>k d vag. f1 k = Some (d,vag) \<longrightarrow> (\<exists>v. n_equiv n1 vag (to_ag v) \<and> valid d
    \<and> fmlookup m1 k = Some v)" by (simp add: map_view_rel_def)
  {
    fix k d vag
    {
      assume f2k: "f2 k = Some (d, vag)"
      then obtain d' vag' where dvag': "f1 k = Some (d', vag')" "n_incl n2 (Some (d,vag)) (Some (d',vag'))"
        using fun_n_incl[OF assms(3)]
        by (metis (no_types, lifting) domIff n_equiv_option_def n_equiv_prod.elims(2) n_incl_def subsetD)
      with rel1 obtain v' where v': "n_equiv n1 vag' (to_ag v')" "valid d'" "fmlookup m1 k = Some v'"
        by blast
      from dvag'(2) have eq_or_incl: "(n_equiv n2 d d' \<and> n_equiv n2 vag vag') \<or>
        (n_incl n2 d d' \<and> n_incl n2 vag vag')" by (auto simp: option_n_incl)
      with v'(1) assms(4) have v'2: "n_equiv n2 vag (to_ag v') \<or> n_incl n2 (to_ag v') vag"
      by (meson ag_valid_n_incl camera_props(8) n_equiv_sprop_def ofe_mono ofe_trans to_ag_n_valid)
      from assms(2) v'(3) obtain v where v: "fmlookup m2 k = Some v" "n_equiv n2 v' v"
        unfolding n_equiv_fmap.rep_eq
        by (metis fmdom'I fmdom'_notI n_equiv_fun_def n_equiv_option_def option.sel)
      from this(2) v'2 have "n_equiv n2 vag (to_ag v) \<or> n_incl n2 (to_ag v) vag"
        using ofe_trans to_ag_n_equiv to_ag_n_incl by blast
      with ag_incl_equiv have "n_incl n2 (to_ag v) vag" using ofe_sym by blast
      from v'(1) to_ag_n_valid have "n_valid vag' n1" using n_valid_ne ofe_sym by blast
      with ag_valid_n_incl[OF this] eq_or_incl assms(4) have "n_equiv n2 vag vag'"
        using Rep_sprop ag_valid_n_incl by blast
      with \<open>n_valid vag' n1\<close> assms(4) have "n_valid vag n2"
        using Rep_sprop n_valid_ne ofe_sym by fastforce
      from eq_or_incl d_equiv n_incl_def v'(2) have "valid d" by (metis camera_valid_op valid_dfrac)
      with ag_valid_n_incl[OF \<open>n_valid vag n2\<close> \<open>n_incl n2 (to_ag v) vag\<close>] v(1)
      have "\<exists>v. n_equiv n2 vag (to_ag v) \<and> valid d \<and> fmlookup m2 k = Some v" using ofe_sym by blast
    }
    then have "f2 k = Some (d,vag) \<longrightarrow> (\<exists>v. n_equiv n2 vag (to_ag v) \<and> valid d \<and> fmlookup m2 k = Some v)"
      by simp
  }
  then show ?thesis unfolding map_view_rel_def by simp
qed

lemma map_view_rel_n_valid: "map_view_rel n a b \<Longrightarrow> n_valid b n"
  apply (auto simp: valid_raw_fun.rep_eq valid_raw_option_def split: option.splits)
  subgoal for k d vag apply (drule map_view_relE)
  apply (auto simp: prod_n_valid_def valid_def valid_raw_ag.rep_eq n_equiv_ag.rep_eq)
  by (metis Set.set_insert ofe_trans_eqR singleton_insert_inj_eq to_ag.rep_eq) done

lemma map_view_rel_unit: "\<exists>a. map_view_rel n a \<epsilon>"
proof -
  have "map_view_rel n fmempty \<epsilon>" by (auto simp: map_view_rel_def \<epsilon>_fun_def \<epsilon>_option_def)
  then show ?thesis by auto
qed

lemma map_view_rel_ne: "\<lbrakk>n_equiv n m1 m2; n_equiv n f1 f2\<rbrakk> \<Longrightarrow> map_view_rel n m1 f1 \<longleftrightarrow> map_view_rel n m2 f2"
  apply (rule iffI)
  using map_view_rel_mono[of n m1 f1 n m2 f2] apply (simp add: ofe_sym total_n_inclI)
  using map_view_rel_mono[of n m2 f2 n m1 f1] by (simp add: ofe_sym total_n_inclI)

lemma map_view_rel_discrete: "map_view_rel 0 (a::('a,'b::discrete) fmap) b \<Longrightarrow> map_view_rel n a b"
  unfolding map_view_rel_def
  by (auto simp: d_equiv)

datatype ('k,'v) map_view =
  MapView (map_view_auth_proj: "((dfrac\<times>('k,'v) fmap ag)) option") (map_view_frag_proj: "('k\<rightharpoonup>(dfrac\<times>'v ag))")

definition view_auth :: "dfrac \<Rightarrow> ('k,'v) fmap \<Rightarrow> ('k,'v::ofe) map_view" ("\<Zspot>V{_} _") where
  "view_auth dq a = MapView (Some (dq, to_ag a)) \<epsilon>"
definition view_frag :: "('k\<rightharpoonup>(dfrac\<times>'v ag)) \<Rightarrow> ('k,'v::ofe) map_view" ("\<circle>V _") where
  "view_frag b = MapView None b"

abbreviation view_auth_disc :: "('k,'v) fmap \<Rightarrow> ('k,'v::ofe) map_view" ("\<Zspot>V\<box> _") where
  "view_auth_disc a \<equiv> \<Zspot>V{DfracDiscarded} a"
abbreviation view_auth_full :: "('k,'v) fmap \<Rightarrow> ('k,'v::ofe) map_view" ("\<Zspot>V _") where
  "view_auth_full a \<equiv> \<Zspot>V{DfracOwn 1} a"

definition map_view_auth :: "dfrac \<Rightarrow> ('k,'v) fmap \<Rightarrow> ('k,'v::ofe) map_view" where
  "map_view_auth dq m = \<Zspot>V{dq} m"
definition map_view_frag :: "'k \<Rightarrow> dfrac \<Rightarrow> 'v \<Rightarrow> ('k,'v::ofe) map_view" where
  "map_view_frag k dq v = \<circle>V [k\<mapsto>(dq,to_ag v)]"

instantiation map_view :: (type,ofe) ofe begin
definition n_equiv_map_view :: "nat \<Rightarrow> ('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view \<Rightarrow> bool" where
  "n_equiv_map_view n v1 v2 \<equiv> n_equiv n (map_view_auth_proj v1) (map_view_auth_proj v2)
    \<and> n_equiv n (map_view_frag_proj v1) (map_view_frag_proj v2)"
definition ofe_eq_map_view :: "('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view \<Rightarrow> bool" where
  "ofe_eq_map_view v1 v2 \<equiv> ofe_eq (map_view_auth_proj v1) (map_view_auth_proj v2)
    \<and> ofe_eq (map_view_frag_proj v1) (map_view_frag_proj v2)"
instance proof (standard)
fix n and x y z :: "('a,'b) map_view"
show "n_equiv n x y \<Longrightarrow> n_equiv n y z \<Longrightarrow> n_equiv n x z"
  unfolding map_view_auth_proj_def map_view_frag_proj_def n_equiv_map_view_def ofe_eq_map_view_def
  apply (cases x; cases y; cases z)
  apply simp
  using ofe_trans by metis
qed (auto simp: map_view_auth_proj_def n_equiv_map_view_def ofe_eq_map_view_def
  ofe_refl ofe_mono ofe_sym ofe_limit intro: ofe_trans split: map_view.splits)
end

instance map_view :: (type,discrete) discrete
  by standard (auto simp: map_view_auth_proj_def n_equiv_map_view_def ofe_eq_map_view_def
    d_equiv d_eq split: map_view.splits)

lemma option_bind_map: "Option.bind x (\<lambda>a. map_option (\<lambda>b. f a b) y) =
  (case x of Some a \<Rightarrow> (case y of Some b \<Rightarrow> Some (f a b) | None \<Rightarrow> None) | None \<Rightarrow> None)"
  by (metis (mono_tags) bind.bind_lunit bind.bind_lzero map_option_case option.case_eq_if option.exhaust_sel)

lemma mv_pcore_alt: "Option.bind (pcore (map_view_auth_proj mv))
  (\<lambda>auth. map_option (\<lambda>frag. MapView auth frag) (pcore (map_view_frag_proj mv)))
  = (case mv of (MapView auth frag) \<Rightarrow>
  (case pcore auth of Some a \<Rightarrow> (case pcore frag of Some b \<Rightarrow> Some (MapView a b) | None \<Rightarrow> None) | None \<Rightarrow> None))"
  using option_bind_map map_view_auth_proj_def map_view_frag_proj_def
  by (auto split: map_view.splits)

instantiation map_view :: (type, ofe) camera begin
lift_definition valid_raw_map_view :: "('a, 'b) map_view \<Rightarrow> sprop" is
  "\<lambda>mv n. case map_view_auth_proj mv of
    Some (dq, ag) \<Rightarrow> n_valid dq n \<and> (\<exists>a. n_equiv n ag (to_ag a) \<and> map_view_rel n a (map_view_frag_proj mv))
  | None \<Rightarrow> \<exists>a. map_view_rel n a (map_view_frag_proj mv)"
  apply (simp add: map_view_auth_proj_def map_view_frag_proj_def split: option.splits map_view.splits)
  apply (meson map_view_rel_mono ofe_refl total_n_inclI)
  by (smt (verit) case_prod_conv dcamera_valid_iff map_view_rel_mono ofe_mono ofe_refl total_n_inclI)
definition pcore_map_view :: "('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view option" where
  "pcore_map_view mv = Option.bind (pcore (map_view_auth_proj mv))
    (\<lambda>auth. map_option (\<lambda>frag. MapView auth frag) (pcore (map_view_frag_proj mv)))"
definition op_map_view :: "('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view" where
  "op_map_view mv1 mv2 = MapView (map_view_auth_proj mv1 \<cdot> map_view_auth_proj mv2)
    (map_view_frag_proj mv1 \<cdot> map_view_frag_proj mv2)"
instance proof
show "non_expansive (valid_raw::('a, 'b) map_view \<Rightarrow> sprop)"
apply (rule non_expansiveI)
apply (auto simp: n_equiv_sprop_def valid_raw_map_view.rep_eq map_view_auth_proj_def
  map_view_frag_proj_def n_equiv_map_view_def n_equiv_option_def split: option.splits map_view.splits)
by (meson map_view_rel_ne ofe_mono ofe_refl ofe_sym ofe_trans)+
next
show "non_expansive (pcore::('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view option)"
proof (rule non_expansiveI)
  fix n and x y :: "('a,'b) map_view"
  assume assm: "n_equiv n x y"
  obtain a1 f1 a2 f2 where xy: "x = MapView a1 f1" "y= MapView a2 f2" by (metis map_view.collapse)
  with assm have "n_equiv n a1 a2" "n_equiv n f1 f2" by (auto simp: n_equiv_map_view_def)
  then have "n_equiv n (pcore a1) (pcore a2)" "n_equiv n (pcore f1) (pcore f2)"
    using pcore_ne by blast+
  then show "n_equiv n (pcore x) (pcore y)"
    unfolding pcore_map_view_def mv_pcore_alt xy
    by (auto simp: n_equiv_option_def n_equiv_map_view_def split: option.splits)
  qed
next
show "non_expansive2 (op::('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view \<Rightarrow> ('a, 'b) map_view)"
  by (rule non_expansive2I) (auto simp: op_map_view_def n_equiv_map_view_def)
next
fix a b c :: "('a,'b) map_view"
show "a \<cdot> b \<cdot> c = a \<cdot> (b \<cdot> c)" by (cases a; cases b; cases c) (auto simp: camera_assoc op_map_view_def)
next
fix a b :: "('a,'b) map_view"
show "a \<cdot> b = b \<cdot> a" by (cases a; cases b) (auto simp: camera_comm op_map_view_def)
next
fix a a' :: "('a,'b) map_view"
show "pcore a = Some a' \<Longrightarrow> a' \<cdot> a = a" apply (cases a; cases a') unfolding pcore_map_view_def
  unfolding mv_pcore_alt by (auto simp: camera_pcore_id op_map_view_def split: option.splits)
next
fix a a' :: "('a,'b) map_view"
show "pcore a = Some a' \<Longrightarrow> pcore a' = pcore a"
  apply (cases a; cases a') unfolding pcore_map_view_def unfolding mv_pcore_alt
  by (auto simp: camera_pcore_idem split: option.splits)
next
fix a a' b :: "('a,'b) map_view"
show "pcore a = Some a' \<Longrightarrow> \<exists>c. b = a \<cdot> c \<Longrightarrow> \<exists>b'. pcore b = Some b' \<and> (\<exists>c. b' = a' \<cdot> c)"
  apply (cases a; cases a'; cases b) unfolding pcore_map_view_def unfolding mv_pcore_alt
  apply (auto simp: op_map_view_def camera_pcore_mono total_pcore pcore_fun_def split: option.splits)
  by (metis camera_pcore_mono map_view.sel(1) map_view.sel(2) option.sel pcore_fun_def)
next
fix a b :: "('a,'b) map_view" and n
show "Rep_sprop (valid_raw (a \<cdot> b)) n \<Longrightarrow> Rep_sprop (valid_raw a) n"
apply (unfold valid_raw_map_view.rep_eq) apply (cases a; cases b)
subgoal for a1 a2 b1 b2 apply (cases a1; cases b1)
subgoal apply (auto simp: map_view_auth_proj_def op_map_view_def op_option_def split: map_view.splits)
  using map_view_rel_mono n_incl_op_extend ofe_refl by blast
subgoal apply (auto simp: map_view_auth_proj_def op_map_view_def op_option_def split: map_view.splits)
  using map_view_rel_mono n_incl_op_extend ofe_refl by blast
subgoal apply (auto simp: map_view_auth_proj_def op_map_view_def op_option_def split: map_view.splits)
  using map_view_rel_mono n_incl_op_extend ofe_refl by blast
apply (simp add: map_view_auth_proj_def op_map_view_def op_option_def op_prod_def split: map_view.splits prod.splits)
subgoal for a1' b1' c1 a11 m a12 b11 b12
  apply auto
  prefer 2 using map_view_rel_mono[of n m "a2\<cdot>b2" n m a2, unfolded n_incl_def]
  apply (meson ag_valid_n_incl camera_props(8) linorder_le_cases n_equiv_sprop_def n_incl_op_extend ofe_refl ofe_trans to_ag_n_valid)
  using camera_valid_op by fast done done
next
fix a b c :: "('a,'b) map_view" and n
assume assms: "Rep_sprop (valid_raw a) n" "n_equiv n a (b \<cdot> c)"
obtain a1 a2 b1 b2 c1 c2 where abc: "a=MapView a1 a2" "b=MapView b1 b2" "c=MapView c1 c2"
  by (metis map_view.collapse)
with assms(2) have n_eq: "n_equiv n a1 (b1\<cdot>c1)" "n_equiv n a2 (b2\<cdot>c2)"
  by (auto simp: op_map_view_def n_equiv_map_view_def)
then have n_eq_prod: "n_equiv n (a1,a2) ((b1,b2)\<cdot>(c1,c2))"
  by (auto simp: op_prod_def)
from assms(1) abc have valid_prod: "n_valid (a1,a2) n"
  apply (cases a1)
  apply (auto simp: valid_raw_map_view.rep_eq prod_n_valid_def valid_raw_option_def map_view_rel_n_valid)
  using n_valid_ne ofe_sym to_ag_n_valid by blast
from camera_extend[OF valid_prod n_eq_prod] obtain d1 d2 e1 e2 where de:
  "(a1, a2) = (d1,d2) \<cdot> (e1,e2)" "n_equiv n (d1,d2) (b1, b2)" "n_equiv n (e1,e2) (c1, c2)"
  by auto
let ?d = "MapView d1 d2" and ?e = "MapView e1 e2"
from de abc have  "a=?d\<cdot>?e" "n_equiv n ?d b" "n_equiv n ?e c"
  by (auto simp: n_equiv_map_view_def op_map_view_def op_prod_def)
then show "\<exists>c1 c2. a = c1 \<cdot> c2 \<and> n_equiv n c1 b \<and> n_equiv n c2 c" by blast
qed
end

instance map_view :: (type,discrete) dcamera proof
  fix x :: "('a,'b) map_view"
  assume assm: "n_valid x 0"
  obtain auth frag where x: "x = MapView auth frag" by (rule map_view.exhaust)
  from assm x have "auth=None \<Longrightarrow> \<exists>a. map_view_rel 0 a frag"
    by (simp add: valid_raw_map_view.rep_eq)
  then have auth_none: "auth=None \<Longrightarrow> \<exists>a. map_view_rel n a frag" for n
    using map_view_rel_discrete by auto
  from assm x have "auth=Some (dq,ag) \<Longrightarrow>
    n_valid dq 0 \<and> (\<exists>a. n_equiv 0 ag (to_ag a) \<and> map_view_rel 0 a frag)" for dq ag
    by (simp add: valid_raw_map_view.rep_eq)
  then have auth_some: "auth=Some (dq,ag) \<Longrightarrow> valid dq \<and> (\<exists>a. ag=(to_ag a) \<and> map_view_rel n a frag)"
    for dq ag n using map_view_rel_discrete by (auto simp: d_equiv d_valid)
  with auth_none have "n_valid x n" for n
    by (simp add: valid_raw_map_view.rep_eq x d_equiv valid_def split: option.splits)
  then show "valid x" unfolding valid_def by blast
qed

instantiation map_view :: (type,ofe) ucamera begin
definition \<epsilon>_map_view :: "('a, 'b) map_view" where "\<epsilon>_map_view = MapView \<epsilon> \<epsilon>"
instance proof
  show "valid (\<epsilon>::('a,'b) map_view)"
    by (simp add: valid_def \<epsilon>_map_view_def valid_raw_map_view.rep_eq map_view_rel_unit \<epsilon>_option_def)
next
  fix a :: "('a,'b) map_view"
  show "\<epsilon> \<cdot> a = a" by (simp add: op_map_view_def \<epsilon>_map_view_def \<epsilon>_left_id)
next
  show "pcore \<epsilon> = Some (\<epsilon>::('a,'b) map_view)"
  unfolding pcore_map_view_def \<epsilon>_map_view_def mv_pcore_alt
  by (simp add: \<epsilon>_pcore split: option.splits)
qed
end

lemma pcore_id_frag: "pcore dq = Some dq \<Longrightarrow> pcore_id_pred (map_view_frag k dq v)"
  unfolding pcore_id_pred_def map_view_frag_def view_frag_def pcore_map_view_def mv_pcore_alt
  apply (auto simp add: fun_eq_iff \<epsilon>_pcore \<epsilon>_option_def[symmetric] comp_def pcore_fun_def
    simp del: \<epsilon>_fun_def \<epsilon>_option_def split: option.splits)
  apply (metis \<epsilon>_option_def not_Some_eq total_pcore)
  by (auto simp: pcore_option_def pcore_prod_def pcore_ag_def)

lemma map_view_auth_valid: "valid (map_view_auth (DfracOwn 1) fmempty)"
  apply (auto simp: map_view_auth_def valid_def valid_raw_map_view.rep_eq map_view_auth_proj_def
    view_auth_def)
  using dcamera_valid_iff valid_dfrac_own apply blast
  apply (auto simp: map_view_rel_def \<epsilon>_fun_def \<epsilon>_option_def)
  using ofe_refl by blast

lemma view_both_valid: "n_valid (\<Zspot>V{dq} a \<cdot> \<circle>V b) n \<longleftrightarrow> map_view_rel n a b \<and> valid dq"
  unfolding view_auth_def view_frag_def valid_raw_map_view.rep_eq
  apply (auto simp: op_map_view_def op_option_def map_empty_left_id to_ag_n_equiv op_fun_def
      \<epsilon>_option_def \<epsilon>_fun_def split: option.splits)
  subgoal for a' using map_view_rel_mono[of n a' b n a b] by (simp add: ofe_sym)
  using dcamera_valid_iff apply blast+
  using ofe_refl by auto

lemma view_both_valid2: "n_valid (\<Zspot>V a \<cdot> \<circle>V b) n \<longleftrightarrow> map_view_rel n a b"
  using view_both_valid valid_dfrac_own by auto

lemma map_view_both_valid: "n_valid (map_view_auth (DfracOwn 1) m \<cdot> map_view_frag k dq v) n \<longleftrightarrow>
  valid dq \<and> n_equiv n (fmlookup m k) (Some v)"
  unfolding map_view_auth_def map_view_frag_def
  unfolding view_both_valid2 map_view_rel_def
  by (auto simp: to_ag_n_equiv n_equiv_option_def ofe_sym)
end