           (*-------------------------------------------*
            |        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_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


(*
   Title: The pi-calculus
   Author/Maintainer: Jesper Bengtson (jebe.dk), 2012
*)
theory Strong_Early_Sim
  imports Early_Semantics Rel
begin

definition "strongSimEarly" :: "pi \<Rightarrow> (pi \<times> pi) set \<Rightarrow> pi \<Rightarrow> bool" ("_ \<leadsto>[_] _" [80, 80, 80] 80) where
  "P \<leadsto>[Rel] Q \<equiv> (\<forall>a y Q'. Q \<longmapsto>a<\<nu>y> \<prec> Q' \<longrightarrow> y \<sharp> P \<longrightarrow> (\<exists>P'. P \<longmapsto>a<\<nu>y> \<prec> P' \<and> (P', Q') \<in> Rel)) \<and>
                 (\<forall>\<alpha> Q'. Q \<longmapsto>\<alpha> \<prec> Q' \<longrightarrow> (\<exists>P'. P \<longmapsto>\<alpha> \<prec> P' \<and> (P', Q') \<in> Rel))"

  assumes "P \<leadsto>[A] P'"
  and     "A \<subseteq> B"

  shows "P \<leadsto>[B] P'"
using assms
by(fastforce simp add: strongSimEarly_def)

lemma freshUnit[simp]:
  fixes y :: name

  shows "y \<sharp> ()"
by(auto simp add: fresh_def supp_unit)

lemma simCasesCont[consumes 1, case_names Bound Free]:
  fixes P   :: pi
  and   Q   :: pi
  and   Rel :: "(pi \<times> pi) set"
  and   C   :: "'a::fs_name"

  assumes Eqvt:  "eqvt Rel"
  and     Bound: "\<And>a y Q'. \<lbrakk>Q \<longmapsto> a<\<nu>y> \<prec> Q'; y \<sharp> P; y \<sharp> Q; y \<sharp> C\<rbrakk> \<Longrightarrow> \<exists>P'. P \<longmapsto> a<\<nu>y> \<prec> P' \<and> (P', Q') \<in> Rel"
  and     Free:  "\<And>\<alpha> Q'. Q \<longmapsto> \<alpha> \<prec> Q' \<Longrightarrow> \<exists>P'. P \<longmapsto> \<alpha> \<prec> P' \<and> (P', Q') \<in> Rel"

  shows "P \<leadsto>[Rel] Q"
proof -
  from Free show ?thesis
  proof(auto simp add: strongSimEarly_def)
    fix Q' a y
    assume yFreshP: "(y::name) \<sharp> P"
    assume Trans: "Q \<longmapsto> a<\<nu>y> \<prec> Q'"
    have "\<exists>c::name. c \<sharp> (P, Q', y, Q, C)" by(blast intro: name_exists_fresh)
    then obtain c::name where cFreshP: "c \<sharp> P" and cFreshQ': "c \<sharp> Q'" and cFreshC: "c \<sharp> C"
                          and cineqy: "c \<noteq> y" and "c \<sharp> Q"
      by(force simp add: fresh_prod name_fresh)

    from Trans cFreshQ' have "Q \<longmapsto> a<\<nu>c> \<prec> ([(y, c)] \<bullet> Q')" by(simp add: alphaBoundOutput)
    hence "\<exists>P'. P \<longmapsto> a<\<nu>c> \<prec> P' \<and> (P', [(y, c)] \<bullet> Q') \<in> Rel" using \<open>c \<sharp> P\<close> \<open>c \<sharp> Q\<close> \<open>c \<sharp> C\<close>
      by(rule Bound)
    then obtain P' where PTrans: "P \<longmapsto> a<\<nu>c> \<prec> P'" and P'RelQ': "(P', [(y, c)] \<bullet> Q') \<in> Rel"
      by blast

    from PTrans yFreshP cineqy have yFreshP': "y \<sharp> P'" by(force intro: freshTransition)
    with PTrans have "P \<longmapsto> a<\<nu>y> \<prec> ([(y, c)] \<bullet> P')" by(simp add: alphaBoundOutput name_swap)
    moreover have "([(y, c)] \<bullet> P', Q') \<in> Rel" (is "?goal")
    proof -
      from Eqvt P'RelQ' have "([(y, c)] \<bullet> P', [(y, c)] \<bullet> [(y, c)] \<bullet> Q') \<in> Rel"
        by(rule eqvtRelI)
      with cineqy show ?goal by(simp add: name_calc)
    qed
    ultimately show "\<exists>P'. P \<longmapsto>a<\<nu>y> \<prec> P' \<and> (P', Q') \<in> Rel" by blast
  qed
qed

lemma simCases[consumes 0, case_names Bound Free]:
  fixes P   :: pi
  and   Q   :: pi
  and   Rel :: "(pi \<times> pi) set"
  and   C   :: "'a::fs_name"

  assumes Bound: "\<And>a y Q'. \<lbrakk>Q \<longmapsto> a<\<nu>y> \<prec> Q'; y \<sharp> P\<rbrakk> \<Longrightarrow> \<exists>P'. P \<longmapsto> a<\<nu>y> \<prec> P' \<and> (P', Q') \<in> Rel"
  and     Free:  "\<And>\<alpha> Q'. Q \<longmapsto> \<alpha> \<prec> Q' \<Longrightarrow> \<exists>P'. P \<longmapsto> \<alpha> \<prec> P' \<and> (P', Q') \<in> Rel"

  shows "P \<leadsto>[Rel] Q"
using assms
by(auto simp add: strongSimEarly_def)

lemma elim:
  fixes P   :: pi
  and   Rel :: "(pi \<times> pi) set"
  and   Q   :: pi
  and   a   :: name
  and   x   :: name
  and   Q'  :: pi

  assumes "P \<leadsto>[Rel] Q"

  shows "Q \<longmapsto> a<\<nu>x> \<prec> Q' \<Longrightarrow> x \<sharp> P \<Longrightarrow> \<exists>P'. P \<longmapsto> a<\<nu>x> \<prec> P' \<and> (P', Q') \<in> Rel"
  and   "Q \<longmapsto> \<alpha> \<prec> Q' \<Longrightarrow> \<exists>P'. P \<longmapsto> \<alpha> \<prec> P' \<and> (P', Q') \<in> Rel"
using assms by(simp add: strongSimEarly_def)+

lemma eqvtI:
  fixes P    :: pi
  and   Q    :: pi
  and   Rel  :: "(pi \<times> pi) set"
  and   perm :: "name prm"

  assumes Sim: "P \<leadsto>[Rel] Q"
  and     RelRel': "Rel \<subseteq> Rel'"
  and     EqvtRel': "eqvt Rel'"

  shows "(perm \<bullet> P) \<leadsto>[Rel'] (perm \<bullet> Q)"
proof(induct rule: simCases)
  case(Bound a y Q')
  have Trans: "(perm \<bullet> Q) \<longmapsto> a<\<nu>y> \<prec> Q'" by fact
  have yFreshP: "y \<sharp> perm \<bullet> P" by fact

  from Trans have "(rev perm \<bullet> (perm \<bullet> Q)) \<longmapsto> rev perm \<bullet> (a<\<nu>y> \<prec> Q')"
    by(rule TransitionsEarly.eqvt)
  hence "Q \<longmapsto> (rev perm \<bullet> a)<\<nu>(rev perm \<bullet> y)> \<prec> (rev perm \<bullet> Q')"
    by(simp add: name_rev_per)
  moreover from yFreshP have "(rev perm \<bullet> y) \<sharp> P" by(simp add: name_fresh_left)
  ultimately have "\<exists>P'. P \<longmapsto> (rev perm \<bullet> a)<\<nu>(rev perm \<bullet> y)> \<prec> P' \<and> (P', rev perm \<bullet> Q') \<in> Rel" using Sim
    by(force intro: elim)
  then obtain P' where PTrans: "P \<longmapsto> (rev perm \<bullet> a)<\<nu>(rev perm \<bullet> y)> \<prec> P'" and P'RelQ': "(P', rev perm \<bullet> Q') \<in> Rel"
    by blast

  from PTrans have "(perm \<bullet> P) \<longmapsto> perm \<bullet> ((rev perm \<bullet> a)<\<nu>(rev perm \<bullet> y)> \<prec> P')" by(rule TransitionsEarly.eqvt)
  hence L1: "(perm \<bullet> P) \<longmapsto> a<\<nu>y> \<prec> (perm \<bullet> P')" by(simp add: name_per_rev)
  from P'RelQ' RelRel' have "(P', rev perm \<bullet> Q') \<in> Rel'" by blast
  with EqvtRel' have "(perm \<bullet> P', perm \<bullet> (rev perm \<bullet> Q')) \<in> Rel'"
    by(rule eqvtRelI)
  hence "(perm \<bullet> P', Q') \<in> Rel'" by(simp add: name_per_rev)
  with L1 show ?case by blast
next
  case(Free \<alpha> Q')
  have Trans: "(perm \<bullet> Q) \<longmapsto> \<alpha> \<prec> Q'" by fact

  from Trans have "(rev perm \<bullet> (perm \<bullet> Q)) \<longmapsto> rev perm \<bullet> (\<alpha> \<prec> Q')"
    by(rule TransitionsEarly.eqvt)
  hence "Q \<longmapsto> (rev perm \<bullet> \<alpha>) \<prec> (rev perm \<bullet> Q')"
    by(simp add: name_rev_per)
  with Sim have "\<exists>P'. P \<longmapsto> (rev perm \<bullet> \<alpha>) \<prec> P' \<and> (P', (rev perm \<bullet> Q')) \<in> Rel"
    by(force intro: elim)
  then obtain P' where PTrans: "P \<longmapsto> (rev perm \<bullet> \<alpha>) \<prec> P'" and PRel: "(P', (rev perm \<bullet> Q')) \<in> Rel" by blast

  from PTrans have "(perm \<bullet> P) \<longmapsto> perm \<bullet> ((rev perm \<bullet> \<alpha>)\<prec> P')" by(rule TransitionsEarly.eqvt)
  hence L1: "(perm \<bullet> P) \<longmapsto> \<alpha> \<prec> (perm \<bullet> P')" by(simp add: name_per_rev)
  from PRel EqvtRel' RelRel'  have "((perm \<bullet> P'), (perm \<bullet> (rev perm \<bullet> Q'))) \<in> Rel'"
    by(force intro: eqvtRelI)
  hence "((perm \<bullet> P'), Q') \<in> Rel'" by(simp add: name_per_rev)
  with L1 show ?case by blast
qed

(*****************Reflexivity and transitivity*********************)

lemma reflexive:
  fixes P   :: pi
  and   Rel :: "(pi \<times> pi) set"

  assumes "Id \<subseteq> Rel"

  shows "P \<leadsto>[Rel] P"
using assms
by(auto simp add: strongSimEarly_def)

lemmas fresh_prod[simp]

  assumes PSimQ: "P \<leadsto>[Rel] Q"
  and     QSimR: "Q \<leadsto>[Rel'] R"
  and     Eqvt': "eqvt Rel''"
  and     Trans: "Rel O Rel' \<subseteq> Rel''"

  shows "P \<leadsto>[Rel''] R"
proof -
  from Eqvt' show ?thesis
  proof(induct rule: simCasesCont[where C=Q])
    case(Bound a y R')
    have RTrans: "R \<longmapsto> a<\<nu>y> \<prec> R'" by fact

    from QSimR RTrans \<open>y \<sharp> Q\<close> have "\<exists>Q'. Q \<longmapsto> a<\<nu>y> \<prec> Q' \<and> (Q', R') \<in> Rel'"
      by(rule elim)
    then obtain Q' where QTrans: "Q \<longmapsto> a<\<nu>y> \<prec> Q'" and Q'Rel'R': "(Q', R') \<in> Rel'" by blast
    from PSimQ QTrans \<open>y \<sharp> P\<close> have "\<exists>P'. P \<longmapsto> a<\<nu>y> \<prec> P' \<and> (P', Q') \<in> Rel"
      by(rule elim)
    then obtain P' where PTrans: "P \<longmapsto> a<\<nu>y> \<prec> P'" and P'RelQ': "(P', Q') \<in> Rel" by blast

    moreover from P'RelQ' Q'Rel'R' Trans have "(P', R') \<in> Rel''" by blast

    ultimately show ?case by blast
  next
    case(Free \<alpha> R')
    have RTrans: "R \<longmapsto> \<alpha> \<prec> R'" by fact
    with QSimR have "\<exists>Q'. Q \<longmapsto> \<alpha> \<prec> Q' \<and> (Q', R') \<in> Rel'" by(rule elim)
    then obtain Q' where QTrans: "Q \<longmapsto> \<alpha> \<prec> Q'" and Q'RelR': "(Q', R') \<in> Rel'" by blast
    from PSimQ QTrans have "\<exists>P'. P \<longmapsto> \<alpha> \<prec> P' \<and> (P', Q') \<in> Rel" by(rule elim)
    then obtain P' where PTrans: "P \<longmapsto> \<alpha> \<prec> P'" and P'RelQ': "(P', Q') \<in> Rel" by blast
    from P'RelQ' Q'RelR' Trans have "(P', R') \<in> Rel''" by blast
    with PTrans show "\<exists>P'. P \<longmapsto> \<alpha> \<prec> P' \<and> (P', R') \<in> Rel''" by blast
  qed
qed

end


theory DBM_Operations_Impl_Refine
  imports
    DBM_Operations_Impl
    "HOL-Library.IArray"
    TA_Library.Imperative_Loops
begin

lemma rev_map_fold_append_aux:
  "fold (\<lambda> x xs. f x # xs) xs zs @ ys = fold (\<lambda> x xs. f x # xs) xs (zs@ys)"
  by (induction xs arbitrary: zs) auto

lemma rev_map_fold:
  "rev (map f xs) = fold (\<lambda> x xs. f x # xs) xs []"
  by (induction xs; simp add: rev_map_fold_append_aux)

lemma map_rev_fold:
  "map f xs = rev (fold (\<lambda> x xs. f x # xs) xs [])"
  using rev_map_fold rev_swap by fastforce

lemma pointwise_cmp_iff:
  "pointwise_cmp P n M M' \<longleftrightarrow> list_all2 P (take ((n + 1) * (n + 1)) xs) (take ((n + 1) * (n + 1)) ys)"
  if "\<forall>i\<le>n. \<forall>j\<le>n. xs ! (i + i * n + j) = M i j"
    "\<forall>i\<le>n. \<forall>j\<le>n. ys ! (i + i * n + j) = M' i j"
    "(n + 1) * (n + 1) \<le> length xs" "(n + 1) * (n + 1) \<le> length ys"
  using that unfolding pointwise_cmp_def
  unfolding list_all2_conv_all_nth
  apply clarsimp
  apply safe
  subgoal premises prems for x
  proof -
    let ?i = "x div (n + 1)" let ?j = "x mod (n + 1)"
    from \<open>x < _\<close> have "?i < Suc n" "?j \<le>n"
      by (simp add: less_mult_imp_div_less)+
    with prems have
      "xs ! (?i + ?i * n + ?j) = M ?i ?j" "ys ! (?i + ?i * n + ?j) = M' ?i ?j"
      "P (M ?i ?j) (M' ?i ?j)"
      by auto
    moreover have "?i + ?i * n + ?j = x"
      by (metis ab_semigroup_add_class.add.commute mod_div_mult_eq mult_Suc_right plus_1_eq_Suc)
    ultimately show \<open>P (xs ! x) (ys ! x)\<close>
      by auto
  qed
  subgoal for i j
    apply (erule allE[of _ i], erule impE, simp)
    apply (erule allE[of _ i], erule impE, simp)
    apply (erule allE[of _ "i + i * n + j"], erule impE)
    subgoal
      by (rule le_imp_less_Suc) (auto intro!: add_mono simp: algebra_simps)
    apply (erule allE[of _ j], erule impE, simp)
    apply (erule allE[of _ j], erule impE, simp)
    apply simp
    done
  done

fun intersperse :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
  "intersperse sep (x # y # xs) = x # sep # intersperse sep (y # xs)" |
  "intersperse _ xs = xs"

lemma the_pure_id_assn_eq[simp]:
  "the_pure (\<lambda>a c. \<up> (c = a)) = Id"
proof -
  have *: "(\<lambda>a c. \<up> (c = a)) = pure Id"
    unfolding pure_def by simp
  show ?thesis
    by (subst *) simp
qed

lemma pure_eq_conv:
  "(\<lambda>a c. \<up> (c = a)) = id_assn"
  using is_pure_assn_def is_pure_iff_pure_assn is_pure_the_pure_id_eq the_pure_id_assn_eq by blast

section \<open>Refinement\<close>

instance DBMEntry :: ("{countable}") countable
  apply (rule
    countable_classI[of
      "(\<lambda>Le (a::'a) \<Rightarrow> to_nat (0::nat,a) |
           DBM.Lt a \<Rightarrow> to_nat (1::nat,a) |
            DBM.INF \<Rightarrow> to_nat (2::nat,undefined::'a) )"])
apply (simp split: DBMEntry.splits)
done

instance DBMEntry :: ("{heap}") heap ..

definition dbm_subset' :: "nat \<Rightarrow> ('t :: {linorder, zero}) DBM' \<Rightarrow> 't DBM' \<Rightarrow> bool" where
  "dbm_subset' n M M' \<equiv> pointwise_cmp (\<le>) n (curry M) (curry M')"

lemma dbm_subset'_alt_def:
  "dbm_subset' n M M' \<equiv>
    list_all (\<lambda>i. list_all (\<lambda>j. (op_mtx_get M (i, j) \<le> op_mtx_get M' (i, j))) [0..<Suc n])
      [0..<Suc n]"
  by (simp add: dbm_subset'_def pointwise_cmp_alt_def neutral)

lemma dbm_subset_alt_def'[code]:
  "dbm_subset n M M' \<longleftrightarrow>
    list_ex (\<lambda>i. op_mtx_get M (i, i) < 0) [0..<Suc n] \<or>
    list_all (\<lambda>i. list_all (\<lambda>j. (op_mtx_get M (i, j) \<le> op_mtx_get M' (i, j))) [0..<Suc n])
      [0..<Suc n]"
  by (simp add: dbm_subset_def check_diag_alt_def pointwise_cmp_alt_def neutral)

definition
  "mtx_line_to_iarray m M = IArray (map (\<lambda>i. M (0, i)) [0..<Suc m])"

definition
  "mtx_line m (M :: _ DBM') = map (\<lambda>i. M (0, i)) [0..<Suc m]"

locale DBM_Impl =
  fixes n :: nat
begin

abbreviation
  mtx_assn :: "(nat \<times> nat \<Rightarrow> ('a :: {linordered_ab_monoid_add, heap})) \<Rightarrow> 'a array \<Rightarrow> assn"
where
  "mtx_assn \<equiv> asmtx_assn (Suc n) id_assn"

abbreviation "clock_assn \<equiv> nbn_assn (Suc n)"

lemmas Relation.IdI[where a = \<infinity>, sepref_import_param]
lemma [sepref_import_param]: "((+),(+)) \<in> Id\<rightarrow>Id\<rightarrow>Id" by simp
lemma [sepref_import_param]: "(uminus,uminus) \<in> (Id::(_*_)set)\<rightarrow>Id" by simp
lemma [sepref_import_param]: "(Lt,Lt) \<in> Id\<rightarrow>Id" by simp
lemma [sepref_import_param]: "(Le,Le) \<in> Id\<rightarrow>Id" by simp
lemma [sepref_import_param]: "(\<infinity>,\<infinity>) \<in> Id" by simp
lemma [sepref_import_param]: "(min :: _ DBMEntry \<Rightarrow> _, min) \<in> Id \<rightarrow> Id \<rightarrow> Id" by simp
lemma [sepref_import_param]: "(Suc, Suc) \<in> Id \<rightarrow> Id" by simp

lemma [sepref_import_param]: "(norm_lower, norm_lower) \<in> Id\<rightarrow>Id\<rightarrow>Id" by simp
lemma [sepref_import_param]: "(norm_upper, norm_upper) \<in> Id\<rightarrow>Id\<rightarrow>Id" by simp
lemma [sepref_import_param]: "(norm_diag,  norm_diag) \<in> Id\<rightarrow>Id" by simp

end

definition zero_clock :: "_ :: linordered_cancel_ab_monoid_add" where
  "zero_clock = 0"

sepref_register zero_clock

lemma [sepref_import_param]: "(zero_clock, zero_clock) \<in> Id" by simp

lemmas [sepref_opt_simps] = zero_clock_def

context
  fixes n :: nat
begin

interpretation DBM_Impl n .

sepref_definition reset_canonical_upd_impl' is
  "uncurry2 (uncurry (\<lambda>x. RETURN ooo reset_canonical_upd x))" ::
  "[\<lambda>(((_,i),j),_). i\<le>n \<and> j\<le>n]\<^sub>a mtx_assn\<^sup>d *\<^sub>a nat_assn\<^sup>k  *\<^sub>a nat_assn\<^sup>k *\<^sub>a id_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding reset_canonical_upd_alt_def op_mtx_set_def[symmetric] by sepref

sepref_definition reset_canonical_upd_impl is
  "uncurry2 (uncurry (\<lambda>x. RETURN ooo reset_canonical_upd x))" ::
  "[\<lambda>(((_,i),j),_). i\<le>n \<and> j\<le>n]\<^sub>a mtx_assn\<^sup>d *\<^sub>a nat_assn\<^sup>k  *\<^sub>a nat_assn\<^sup>k *\<^sub>a id_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding reset_canonical_upd_alt_def op_mtx_set_def[symmetric] by sepref

sepref_definition up_canonical_upd_impl is
  "uncurry (RETURN oo up_canonical_upd)" :: "[\<lambda>(_,i). i\<le>n]\<^sub>a mtx_assn\<^sup>d *\<^sub>a nat_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding up_canonical_upd_def op_mtx_set_def[symmetric] by sepref

lemma [sepref_import_param]:
  "(Le 0, 0) \<in> Id"
  unfolding neutral by simp

(* XXX Not sure if this is dangerous *)
sepref_register 0

sepref_definition check_diag_impl' is
  "uncurry (RETURN oo check_diag)" ::
  "[\<lambda>(i, _). i\<le>n]\<^sub>a nat_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow> bool_assn"
  unfolding check_diag_alt_def list_ex_foldli neutral[symmetric] by sepref

lemma [sepref_opt_simps]:
  "(x = True) = x"
  by simp

sepref_definition dbm_subset'_impl2 is
  "uncurry2 (RETURN ooo dbm_subset')" ::
  "[\<lambda>((i, _), _). i\<le>n]\<^sub>a nat_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow> bool_assn"
unfolding dbm_subset'_alt_def list_all_foldli by sepref

definition
  "dbm_subset'_impl' \<equiv> \<lambda>m a b.
    do {
    imp_for 0 ((m + 1) * (m + 1)) Heap_Monad.return
      (\<lambda>i _. do {
        x \<leftarrow> Array.nth a i; y \<leftarrow> Array.nth b i; Heap_Monad.return (x \<le> y)
      })
      True
    }"

lemma imp_for_list_all2_spec:
  "
  <a \<mapsto>\<^sub>a xs * b \<mapsto>\<^sub>a ys>
  imp_for 0 n' Heap_Monad.return
    (\<lambda>i _. do {
      x \<leftarrow> Array.nth a i; y \<leftarrow> Array.nth b i; Heap_Monad.return (P x y)
    })
    True
  <\<lambda>r. \<up>(r \<longleftrightarrow> list_all2 P (take n' xs) (take n' ys)) * a \<mapsto>\<^sub>a xs * b \<mapsto>\<^sub>a ys>\<^sub>t"
  if "n' \<le> length xs" "n' \<le> length ys"
  apply (rule cons_rule[rotated 2])
    apply (rule imp_for_list_all2'[where xs = xs and ys = ys and R = id_assn and S = id_assn])
        apply (use that in simp; fail)+
    apply (sep_auto simp: pure_def array_assn_def is_array_def)+
  done

lemma dbm_subset'_impl'_refine:
  "(uncurry2 dbm_subset'_impl', uncurry2 (RETURN \<circ>\<circ>\<circ> dbm_subset'))
\<in> [\<lambda>((i, _), _). i = n]\<^sub>a nat_assn\<^sup>k *\<^sub>a local.mtx_assn\<^sup>k *\<^sub>a local.mtx_assn\<^sup>k \<rightarrow> bool_assn"
  apply sepref_to_hoare
  unfolding dbm_subset'_impl'_def
  unfolding amtx_assn_def hr_comp_def is_amtx_def
(* XXX The simp rules for imp_for need a name *)
  apply (sep_auto heap: imp_for_list_all2_spec simp only:)
    apply (simp; intro add_mono mult_mono; simp; fail)+
  apply sep_auto

  subgoal for b bi ba bia l la a bb
    unfolding dbm_subset'_def by (simp add: pointwise_cmp_iff[where xs = l and ys = la])

  subgoal for b bi ba bia l la a bb
    unfolding dbm_subset'_def by (simp add: pointwise_cmp_iff[where xs = l and ys = la])
  done

sepref_register check_diag ::
  "nat \<Rightarrow> _ :: {linordered_cancel_ab_monoid_add,heap} DBMEntry i_mtx \<Rightarrow> bool"

sepref_register dbm_subset' ::
  "nat \<Rightarrow> 'a :: {linordered_cancel_ab_monoid_add,heap} DBMEntry i_mtx \<Rightarrow> 'a DBMEntry i_mtx \<Rightarrow> bool"

lemmas [sepref_fr_rules] = dbm_subset'_impl'_refine check_diag_impl'.refine

sepref_definition dbm_subset_impl' is
  "uncurry2 (RETURN ooo dbm_subset)" ::
  "[\<lambda>((i, _), _). i=n]\<^sub>a nat_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow> bool_assn"
unfolding dbm_subset_def dbm_subset'_def[symmetric] short_circuit_conv by sepref

context
  notes [id_rules] = itypeI[of n "TYPE (nat)"]
    and [sepref_import_param] = IdI[of n]
begin

sepref_definition dbm_subset_impl is
  "uncurry (RETURN oo PR_CONST (dbm_subset n))" :: "mtx_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow>\<^sub>a bool_assn"
  unfolding dbm_subset_def dbm_subset'_def[symmetric] short_circuit_conv PR_CONST_def by sepref

sepref_definition check_diag_impl is
  "RETURN o PR_CONST (check_diag n)" :: "mtx_assn\<^sup>k \<rightarrow>\<^sub>a bool_assn"
  unfolding check_diag_alt_def list_ex_foldli neutral[symmetric] PR_CONST_def by sepref

sepref_definition dbm_subset'_impl is
  "uncurry (RETURN oo PR_CONST (dbm_subset' n))" :: "mtx_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow>\<^sub>a bool_assn"
  unfolding dbm_subset'_alt_def list_all_foldli PR_CONST_def by sepref

end

abbreviation
  "iarray_assn x y \<equiv> pure (br IArray (\<lambda>_. True)) y x"

lemma [sepref_fr_rules]:
  "(uncurry (return oo IArray.sub), uncurry (RETURN oo op_list_get))
  \<in> iarray_assn\<^sup>k *\<^sub>a id_assn\<^sup>k \<rightarrow>\<^sub>a id_assn"
unfolding br_def by sepref_to_hoare sep_auto

lemmas extra_defs = extra_upd_def upd_line_def upd_line_0_def

sepref_definition norm_upd_impl is
  "uncurry2 (RETURN ooo norm_upd)" ::
   "[\<lambda>((_, xs), i). length xs > n \<and> i\<le>n]\<^sub>a mtx_assn\<^sup>d *\<^sub>a iarray_assn\<^sup>k *\<^sub>a nat_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding norm_upd_def extra_defs zero_clock_def[symmetric] by sepref

sepref_definition norm_upd_impl' is
  "uncurry2 (RETURN ooo norm_upd)" ::
   "[\<lambda>((_, xs), i). length xs > n \<and> i\<le>n]\<^sub>a mtx_assn\<^sup>d *\<^sub>a (list_assn id_assn)\<^sup>k *\<^sub>a nat_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding norm_upd_def extra_defs zero_clock_def[symmetric] by sepref

sepref_definition extra_lu_upd_impl is
  "uncurry3 (\<lambda>x. RETURN ooo (extra_lu_upd x))" ::
  "[\<lambda>(((_, ys), xs), i). length xs > n \<and> length ys > n \<and> i\<le>n]\<^sub>a
    mtx_assn\<^sup>d *\<^sub>a iarray_assn\<^sup>k *\<^sub>a iarray_assn\<^sup>k *\<^sub>a nat_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding extra_lu_upd_def extra_defs zero_clock_def[symmetric] by sepref

sepref_definition mtx_line_to_list_impl is
  "uncurry (RETURN oo PR_CONST mtx_line)" ::
  "[\<lambda>(m, _). m \<le> n]\<^sub>a nat_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow> list_assn id_assn"
  unfolding mtx_line_def HOL_list.fold_custom_empty PR_CONST_def map_rev_fold by sepref

context
  fixes m :: nat assumes "m \<le> n"
  notes [id_rules] = itypeI[of m "TYPE (nat)"]
    and [sepref_import_param] = IdI[of m]
begin

sepref_definition mtx_line_to_list_impl2 is
  "RETURN o PR_CONST mtx_line m" :: "mtx_assn\<^sup>k \<rightarrow>\<^sub>a list_assn id_assn"
  unfolding mtx_line_def HOL_list.fold_custom_empty PR_CONST_def map_rev_fold
  apply sepref_dbg_keep
  using \<open>m \<le> n\<close>
  apply sepref_dbg_trans_keep
  apply sepref_dbg_opt
  apply sepref_dbg_cons_solve
  apply sepref_dbg_cons_solve
  apply sepref_dbg_constraints
  done

end

lemma IArray_impl:
  "(return o IArray, RETURN o id) \<in> (list_assn id_assn)\<^sup>k \<rightarrow>\<^sub>a iarray_assn"
  by sepref_to_hoare (sep_auto simp: br_def list_assn_pure_conv pure_eq_conv)

definition
  "mtx_line_to_iarray_impl m M = (mtx_line_to_list_impl2 m M \<bind> return o IArray)"

lemmas mtx_line_to_iarray_impl_ht =
  mtx_line_to_list_impl2.refine[to_hnr, unfolded hn_refine_def hn_ctxt_def, simplified]

lemmas IArray_ht = IArray_impl[to_hnr, unfolded hn_refine_def hn_ctxt_def, simplified]

lemma mtx_line_to_iarray_impl_refine[sepref_fr_rules]:
  "(uncurry mtx_line_to_iarray_impl, uncurry (RETURN \<circ>\<circ> mtx_line))
  \<in> [\<lambda>(m, _). m \<le> n]\<^sub>a nat_assn\<^sup>k *\<^sub>a mtx_assn\<^sup>k \<rightarrow> iarray_assn"
  unfolding mtx_line_to_iarray_impl_def hfref_def
  apply clarsimp
  apply sepref_to_hoare
  apply (sep_auto
    heap: mtx_line_to_iarray_impl_ht IArray_ht simp: br_def pure_eq_conv list_assn_pure_conv)
  apply (simp add: pure_def)
  done

sepref_register "mtx_line" :: "nat \<Rightarrow> ('ef) DBMEntry i_mtx \<Rightarrow> 'ef DBMEntry list"

lemma [sepref_import_param]: "(dbm_lt :: _ DBMEntry \<Rightarrow> _, dbm_lt) \<in> Id \<rightarrow> Id \<rightarrow> Id" by simp

sepref_definition extra_lup_upd_impl is
  "uncurry3 (\<lambda>x. RETURN ooo (extra_lup_upd x))" ::
   "[\<lambda>(((_, ys), xs), i). length xs > n \<and> length ys > n \<and> i\<le>n]\<^sub>a
    mtx_assn\<^sup>d *\<^sub>a iarray_assn\<^sup>k *\<^sub>a iarray_assn\<^sup>k *\<^sub>a nat_assn\<^sup>k \<rightarrow> mtx_assn"
  unfolding extra_lup_upd_alt_def2 extra_defs zero_clock_def[symmetric] mtx_line_def[symmetric]
  by sepref

text \<open>DBM to List\<close>
definition dbm_to_list :: "(nat \<times> nat \<Rightarrow> 'a) \<Rightarrow> 'a list" where
  "dbm_to_list M \<equiv>
  rev $ fold (\<lambda>i xs. fold (\<lambda>j xs. M (i, j) # xs) [0..<Suc n] xs) [0..<Suc n] []"

context
  notes [id_rules] = itypeI[of n "TYPE (nat)"]
    and [sepref_import_param] = IdI[of n]
begin

sepref_definition dbm_to_list_impl is
  "RETURN o PR_CONST dbm_to_list" :: "mtx_assn\<^sup>k \<rightarrow>\<^sub>a list_assn id_assn"
  unfolding dbm_to_list_def HOL_list.fold_custom_empty PR_CONST_def by sepref

text \<open>DBM to String\<close>

context
  fixes show_clock :: "nat \<Rightarrow> string"
    and show_num :: "'a :: {linordered_ab_group_add,heap} \<Rightarrow> string"
begin

definition
  "make_string e i j \<equiv>
    if i = j then if e < 0 then Some (''EMPTY'') else None
    else
    if i = 0 then
    case e of
      DBMEntry.Le a \<Rightarrow> if a = 0 then None else Some (show_clock j @ '' >= '' @ show_num (- a))
    | DBMEntry.Lt a \<Rightarrow> Some (show_clock j @ '' > ''  @ show_num (- a))
    | _ \<Rightarrow> None
    else if j = 0 then
    case e of
      DBMEntry.Le a \<Rightarrow> Some (show_clock i @ '' <= '' @ show_num a)
    | DBMEntry.Lt a \<Rightarrow> Some (show_clock i @ '' < ''  @ show_num a)
    | _ \<Rightarrow> None
    else
    case e of
      DBMEntry.Le a \<Rightarrow> Some (show_clock i @ '' - '' @ show_clock j @ '' <= '' @ show_num a)
    | DBMEntry.Lt a \<Rightarrow> Some (show_clock i @ '' - '' @ show_clock j @ '' < '' @ show_num a)
    | _ \<Rightarrow> None
"

definition
  "dbm_list_to_string xs \<equiv>
  (concat o intersperse '', '' o rev o snd o snd) $ fold (\<lambda>e (i, j, acc).
    let
      v = make_string e i j;
      j = (j + 1) mod (n + 1);
      i = (if j = 0 then i + 1 else i)
    in
    case v of
      None \<Rightarrow> (i, j, acc)
    | Some s \<Rightarrow> (i, j, s # acc)
  ) xs (0, 0, [])
"

lemma [sepref_import_param]:
  "(dbm_list_to_string, PR_CONST dbm_list_to_string) \<in> \<langle>Id\<rangle>list_rel \<rightarrow> \<langle>Id\<rangle>list_rel"
  by simp

definition show_dbm where
  "show_dbm M \<equiv> PR_CONST dbm_list_to_string (dbm_to_list M)"

sepref_register "PR_CONST local.dbm_list_to_string"
sepref_register dbm_to_list :: "'b i_mtx \<Rightarrow> 'b list"

lemmas [sepref_fr_rules] = dbm_to_list_impl.refine

sepref_definition show_dbm_impl is
  "RETURN o show_dbm" :: "mtx_assn\<^sup>k \<rightarrow>\<^sub>a list_assn id_assn"
  unfolding show_dbm_def by sepref

end (* Context for show functions *)

end (* Context for importing n *)

end (* Context for DBM dimension n *)

export_code
  norm_upd_impl
  reset_canonical_upd_impl
  up_canonical_upd_impl
  dbm_subset_impl
  dbm_subset
  show_dbm_impl
checking SML

export_code
  norm_upd_impl
  reset_canonical_upd_impl
  up_canonical_upd_impl
  dbm_subset_impl
  dbm_subset
  show_dbm_impl
checking SML_imp

end