theory flash58Bra  imports flash58Rev

  begin
lemma onInv58:

   assumes  a1:"iInv1 \<le> N" and  a2:"iInv2 \<le> N" and  a3:"iInv3 \<le> N" and  a4:"iInv1~=iInv2  " and  a5:"iInv1~=iInv3  " and  a6:"iInv2~=iInv3  " and

     b1:"r \<in> rules N" and b2:"invf=inv58  iInv1  iInv2  iInv3 "
   shows  "invHoldForRule' s invf r (invariants   N)"
   proof -
have c1:"ex1P N (% iRule1 .  r=NI_Local_GetX_PutX1 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_GetX  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Replace  iRule1 )\<or>ex0P N (  r=NI_ShWb N )\<or>ex0P N (  r=PI_Local_GetX_GetX2 )\<or>ex0P N (  r=NI_Local_PutXAcksDone )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX7 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Nak2  iRule1 )\<or>ex0P N (  r=NI_ReplaceHomeShrVld )\<or>ex1P N (% iRule1 .  r=NI_Remote_Put  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX5 N  iRule1 )\<or>ex0P N (  r=NI_Wb )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Get  iRule1 )\<or>ex0P N (  r=PI_Local_Replace )\<or>ex1P N (% iRule1 .  r=NI_ReplaceShrVld  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Local_GetX_PutX8 N  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_InvAck_2 N  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_Get_Nak2  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=PI_Remote_Replace  iRule1 )\<or>ex0P N (  r=NI_Nak_Home )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Put2  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_InvAck_1  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX11 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX6 N  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_Get_Put2  iRule1  iRule2 )\<or>ex0P N (  r=PI_Local_Get_Put )\<or>ex0P N (  r=PI_Local_GetX_PutX1 N )\<or>ex1P N (% iRule1 .  r=NI_InvAck_1_Home  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_Get_Nak1  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Nak1  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_Nak2  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX10_home N  iRule1 )\<or>ex1P N (% iRule1 .  r=PI_Remote_Get  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_Nak3  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Local_GetX_PutX10 N  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX2 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_Get_Put1  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_PutX  iRule1 )\<or>ex1P N (% iRule1 .  r=Store  iRule1 )\<or>ex0P N (  r=NI_FAck )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX3 N  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_PutX3 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_GetX_PutX  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX8_home N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Put1 N  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_GetX1 )\<or>ex0P N (  r=StoreHome )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_GetX_Nak  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Inv  iRule1 )\<or>ex1P N (% iRule1 .  r=PI_Remote_PutX  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_PutX4 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX4 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Nak  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_PutX2 N )\<or>ex0P N (  r=NI_Local_Put )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_Nak1  iRule1 )\<or>ex0P N (  r=NI_Nak_Clear )\<or>ex0P N (  r=PI_Local_PutX )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Nak3  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_GetX_Nak_Home  iRule1 )\<or>ex0P N (  r=PI_Local_Get_Get )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX9 N  iRule1 )\<or>ex1P N (% iRule1 .  r=PI_Remote_GetX  iRule1 )\<or>ex0P N (  r=NI_ReplaceHome )\<or>ex1P N (% iRule1 .  r=NI_Remote_GetX_PutX_Home  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Put3  iRule1 )"

        apply(cut_tac  b1)
        apply auto
        done      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX1 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX1 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX1 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_GetX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_GetX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_GetX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_GetXVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Replace  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Replace  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Replace  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_ReplaceVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_ShWb N )
"

         from c1 have c2:" r= NI_ShWb N "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_ShWb N ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_ShWbVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_GetX2 )
"

         from c1 have c2:" r= PI_Local_GetX_GetX2 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_GetX_GetX2 ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_GetX_GetX2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= NI_Local_PutXAcksDone )
"

         from c1 have c2:" r= NI_Local_PutXAcksDone "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_PutXAcksDone ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_Local_PutXAcksDoneVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX7 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX7 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX7 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX7VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Nak2  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Nak2  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Nak2  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_Nak2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_ReplaceHomeShrVld )
"

         from c1 have c2:" r= NI_ReplaceHomeShrVld "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_ReplaceHomeShrVld ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_ReplaceHomeShrVldVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_Put  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_Put  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_Put  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_PutVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX5 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX5 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX5 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX5VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_Wb )
"

         from c1 have c2:" r= NI_Wb "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Wb ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_WbVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Get  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Get  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Get  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_GetVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_Replace )
"

         from c1 have c2:" r= PI_Local_Replace "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_Replace ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_ReplaceVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_ReplaceShrVld  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_ReplaceShrVld  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_ReplaceShrVld  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_ReplaceShrVldVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Local_GetX_PutX8 N  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Local_GetX_PutX8 N  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX8 N  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX8VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_InvAck_2 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_InvAck_2 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_InvAck_2 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_InvAck_2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_Get_Nak2  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_Get_Nak2  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_Get_Nak2  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_Get_Nak2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_Replace  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_Replace  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Remote_Replace  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis PI_Remote_ReplaceVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_Nak_Home )
"

         from c1 have c2:" r= NI_Nak_Home "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Nak_Home ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_Nak_HomeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Put2  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Put2  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Put2  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_Put2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_InvAck_1  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_InvAck_1  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_InvAck_1  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_InvAck_1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX11 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX11 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX11 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX11VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX6 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX6 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX6 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX6VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_Get_Put2  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_Get_Put2  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_Get_Put2  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_Get_Put2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_Get_Put )
"

         from c1 have c2:" r= PI_Local_Get_Put "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_Get_Put ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_Get_PutVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX1 N )
"

         from c1 have c2:" r= PI_Local_GetX_PutX1 N "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_GetX_PutX1 N ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_GetX_PutX1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_InvAck_1_Home  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_InvAck_1_Home  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_InvAck_1_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_InvAck_1_HomeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_Get_Nak1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_Get_Nak1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_Get_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_Get_Nak1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Nak1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Nak1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_Nak1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_Nak2  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_Nak2  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_Nak2  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_Nak2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX10_home N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX10_home N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX10_home N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX10_homeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_Get  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_Get  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Remote_Get  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis PI_Remote_GetVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_Nak3  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_Nak3  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_Nak3  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_Nak3VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Local_GetX_PutX10 N  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Local_GetX_PutX10 N  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX10 N  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX10VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX2 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX2 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX2 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_Get_Put1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_Get_Put1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_Get_Put1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_Get_Put1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_PutX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_PutX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_PutX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_PutXVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= Store  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= Store  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (Store  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis StoreVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_FAck )
"

         from c1 have c2:" r= NI_FAck "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_FAck ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_FAckVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX3 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX3 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX3 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX3VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX3 )
"

         from c1 have c2:" r= PI_Local_GetX_PutX3 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_GetX_PutX3 ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_GetX_PutX3VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_GetX_PutX  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_GetX_PutX  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_GetX_PutX  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_GetX_PutXVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX8_home N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX8_home N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX8_home N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX8_homeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Put1 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Put1 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Put1 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_Put1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_GetX1 )
"

         from c1 have c2:" r= PI_Local_GetX_GetX1 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_GetX_GetX1 ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_GetX_GetX1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= StoreHome )
"

         from c1 have c2:" r= StoreHome "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (StoreHome ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis StoreHomeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_GetX_Nak  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_GetX_Nak  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_GetX_Nak  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_GetX_NakVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Inv  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Inv  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Inv  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_InvVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_PutX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_PutX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Remote_PutX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis PI_Remote_PutXVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX4 )
"

         from c1 have c2:" r= PI_Local_GetX_PutX4 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_GetX_PutX4 ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_GetX_PutX4VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX4 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX4 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX4 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX4VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Nak  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Nak  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Nak  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_NakVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX2 N )
"

         from c1 have c2:" r= PI_Local_GetX_PutX2 N "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_GetX_PutX2 N ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_GetX_PutX2VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= NI_Local_Put )
"

         from c1 have c2:" r= NI_Local_Put "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Put ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_Local_PutVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_Nak1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_Nak1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_Nak1VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_Nak_Clear )
"

         from c1 have c2:" r= NI_Nak_Clear "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Nak_Clear ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_Nak_ClearVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= PI_Local_PutX )
"

         from c1 have c2:" r= PI_Local_PutX "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_PutX ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_PutXVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Nak3  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Nak3  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Nak3  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_Nak3VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_GetX_Nak_Home  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_GetX_Nak_Home  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_GetX_Nak_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_GetX_Nak_HomeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_Get_Get )
"

         from c1 have c2:" r= PI_Local_Get_Get "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Local_Get_Get ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis PI_Local_Get_GetVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX9 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX9 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_GetX_PutX9 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_GetX_PutX9VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_GetX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_GetX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (PI_Remote_GetX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis PI_Remote_GetXVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_ReplaceHome )
"

         from c1 have c2:" r= NI_ReplaceHome "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_ReplaceHome ) (invariants N) "
            apply(cut_tac   a1  a2  a3  a4  a5  a6   b2 c2 )
            by (metis NI_ReplaceHomeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_GetX_PutX_Home  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_GetX_PutX_Home  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Remote_GetX_PutX_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Remote_GetX_PutX_HomeVsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Put3  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Put3  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv58  iInv1  iInv2  iInv3 ) (NI_Local_Get_Put3  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3  a4  a5  a6 )
            by (metis NI_Local_Get_Put3VsInv58 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }ultimately show "invHoldForRule' s invf r (invariants N) "
          by blast
     qed
end


(*****************************************************************************
 * Featherweight-OCL --- A Formal Semantics for UML-OCL Version OCL 2.5
 *                       for the OMG Standard.
 *                       http://www.brucker.ch/projects/hol-testgen/
 *
 * UML_Pair.thy --- Library definitions.
 * This file is part of HOL-TestGen.
 *
 * Copyright (c) 2012-2015 Université Paris-Saclay, Univ. Paris-Sud, France
 *               2013-2015 IRT SystemX, France
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *
 *     * Neither the name of the copyright holders nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************)

theory  UML_Pair
imports "../UML_PropertyProfiles"
begin

section\<open>Collection Type Pairs: Operations \label{sec:collection_pairs}\<close>

text\<open>The OCL standard provides the concept of \emph{Tuples}, \ie{} a family of record-types
with projection functions. In FeatherWeight OCL,  only the theory of a special case is
developped, namely the type of Pairs, which is, however, sufficient for all applications
since it can be used to mimick all tuples. In particular, it can be used to express operations
with multiple arguments, roles of n-ary associations, ...\<close>

subsection\<open>Semantic Properties of the Type Constructor\<close>

lemma A[simp]:"Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x \<noteq> None \<Longrightarrow> Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x \<noteq> null \<Longrightarrow> (fst \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x\<rceil>\<rceil>) \<noteq> bot"
by(insert Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e[of x],auto simp:null_option_def bot_option_def)

lemma A'[simp]:" x \<noteq> bot \<Longrightarrow>  x \<noteq> null \<Longrightarrow> (fst \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x\<rceil>\<rceil>) \<noteq> bot"
apply(insert Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e[of x], simp add: bot_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def null_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def)
apply(auto simp:null_option_def bot_option_def)
apply(erule contrapos_np[of "x = Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e None"])
apply(subst Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject[symmetric], simp)
apply(subst Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e.Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inverse, simp_all,simp add: bot_option_def)
apply(erule contrapos_np[of "x = Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e \<lfloor>None\<rfloor>"])
apply(subst Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject[symmetric], simp)
apply(subst Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e.Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inverse, simp_all,simp add: null_option_def bot_option_def)
done

lemma B[simp]:"Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x \<noteq> None \<Longrightarrow> Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x \<noteq> null \<Longrightarrow> (snd \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x\<rceil>\<rceil>) \<noteq> bot"
by(insert Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e[of x],auto simp:null_option_def bot_option_def)

lemma B'[simp]:"x \<noteq> bot \<Longrightarrow> x \<noteq> null \<Longrightarrow> (snd \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e x\<rceil>\<rceil>) \<noteq> bot"
apply(insert Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e[of x], simp add: bot_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def null_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def)
apply(auto simp:null_option_def bot_option_def)
apply(erule contrapos_np[of "x = Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e None"])
apply(subst Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject[symmetric], simp)
apply(subst Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e.Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inverse, simp_all,simp add: bot_option_def)
apply(erule contrapos_np[of "x = Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e \<lfloor>None\<rfloor>"])
apply(subst Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject[symmetric], simp)
apply(subst Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e.Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inverse, simp_all,simp add: null_option_def bot_option_def)
done

subsection\<open>Fundamental Properties of Strict Equality \label{sec:pair-strict-eq}\<close>

text\<open>After the part of foundational operations on sets, we detail here equality on sets.
Strong equality is inherited from the OCL core, but we have to consider
the case of the strict equality. We decide to overload strict equality in the
same way we do for other value's in OCL:\<close>

overloading
  StrictRefEq \<equiv> "StrictRefEq :: [('\<AA>,'\<alpha>::null,'\<beta>::null)Pair,('\<AA>,'\<alpha>::null,'\<beta>::null)Pair] \<Rightarrow> ('\<AA>)Boolean"
begin
  definition StrictRefEq\<^sub>P\<^sub>a\<^sub>i\<^sub>r :
    "((x::('\<AA>,'\<alpha>::null,'\<beta>::null)Pair) \<doteq> y) \<equiv> (\<lambda> \<tau>. if (\<upsilon> x) \<tau> = true \<tau> \<and> (\<upsilon> y) \<tau> = true \<tau>
                                                     then (x \<triangleq> y)\<tau>
                                                     else invalid \<tau>)"
end

text\<open>Property proof in terms of @{term "profile_bin\<^sub>S\<^sub>t\<^sub>r\<^sub>o\<^sub>n\<^sub>g\<^sub>E\<^sub>q_\<^sub>v_\<^sub>v"}\<close>
interpretation  StrictRefEq\<^sub>P\<^sub>a\<^sub>i\<^sub>r : profile_bin\<^sub>S\<^sub>t\<^sub>r\<^sub>o\<^sub>n\<^sub>g\<^sub>E\<^sub>q_\<^sub>v_\<^sub>v "\<lambda> x y. (x::('\<AA>,'\<alpha>::null,'\<beta>::null)Pair) \<doteq> y"
                by unfold_locales (auto simp:  StrictRefEq\<^sub>P\<^sub>a\<^sub>i\<^sub>r)

subsection\<open>Standard Operations Definitions\<close>

text\<open>This part provides a collection of operators for the Pair type.\<close>

subsubsection\<open>Definition: Pair Constructor\<close>

definition OclPair::"('\<AA>, '\<alpha>) val \<Rightarrow>
                     ('\<AA>, '\<beta>) val \<Rightarrow>
                     ('\<AA>,'\<alpha>::null,'\<beta>::null) Pair"  ("Pair{(_),(_)}")
where     "Pair{X,Y} \<equiv> (\<lambda> \<tau>. if (\<upsilon> X) \<tau> = true \<tau> \<and> (\<upsilon> Y) \<tau> = true \<tau>
                              then Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e \<lfloor>\<lfloor>(X \<tau>, Y \<tau>)\<rfloor>\<rfloor>
                              else invalid \<tau>)"

interpretation OclPair : profile_bin\<^sub>v_\<^sub>v
               OclPair "\<lambda> x y. Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e \<lfloor>\<lfloor>(x, y)\<rfloor>\<rfloor>"
               apply(unfold_locales, auto simp:  OclPair_def bot_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def null_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def)
               by(auto simp: Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject null_option_def bot_option_def)

subsubsection\<open>Definition: First\<close>

definition OclFirst::" ('\<AA>,'\<alpha>::null,'\<beta>::null) Pair \<Rightarrow> ('\<AA>, '\<alpha>) val"  (" _ .First'(')")
where     "X .First() \<equiv> (\<lambda> \<tau>. if (\<delta> X) \<tau> = true \<tau>
                              then fst \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e (X \<tau>)\<rceil>\<rceil>
                              else invalid \<tau>)"

interpretation OclFirst : profile_mono\<^sub>d OclFirst "\<lambda>x.  fst \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e (x)\<rceil>\<rceil>"
                          by unfold_locales (auto simp:  OclFirst_def)

subsubsection\<open>Definition: Second\<close>

definition OclSecond::" ('\<AA>,'\<alpha>::null,'\<beta>::null) Pair \<Rightarrow> ('\<AA>, '\<beta>) val"  ("_ .Second'(')")
where     "X .Second() \<equiv> (\<lambda> \<tau>. if (\<delta> X) \<tau> = true \<tau>
                               then snd \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e (X \<tau>)\<rceil>\<rceil>
                               else invalid \<tau>)"

interpretation OclSecond : profile_mono\<^sub>d OclSecond "\<lambda>x.  snd \<lceil>\<lceil>Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e (x)\<rceil>\<rceil>"
                           by unfold_locales  (auto simp:  OclSecond_def)

subsection\<open>Logical Properties\<close>

lemma 1 : "\<tau> \<Turnstile> \<upsilon> Y \<Longrightarrow> \<tau> \<Turnstile> Pair{X,Y} .First() \<triangleq> X"
apply(case_tac "\<not>(\<tau> \<Turnstile> \<upsilon> X)")
apply(erule foundation7'[THEN iffD2, THEN foundation15[THEN iffD2,
                                       THEN StrongEq_L_subst2_rev]],simp_all add:foundation18')
apply(auto simp: OclValid_def valid_def defined_def StrongEq_def OclFirst_def OclPair_def
                true_def false_def invalid_def bot_fun_def null_fun_def)
apply(auto simp: Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject null_option_def bot_option_def bot_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def null_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def)
by(simp add: Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inverse)

lemma 2 : "\<tau> \<Turnstile> \<upsilon> X \<Longrightarrow> \<tau> \<Turnstile> Pair{X,Y} .Second() \<triangleq> Y"
apply(case_tac "\<not>(\<tau> \<Turnstile> \<upsilon> Y)")
apply(erule foundation7'[THEN iffD2, THEN foundation15[THEN iffD2,
                                       THEN StrongEq_L_subst2_rev]],simp_all add:foundation18')
apply(auto simp: OclValid_def valid_def defined_def StrongEq_def OclSecond_def OclPair_def
                true_def false_def invalid_def bot_fun_def null_fun_def)
apply(auto simp: Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject null_option_def bot_option_def bot_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def null_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def)
by(simp add: Abs_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inverse)

subsection\<open>Algebraic Execution Properties\<close>

lemma proj1_exec [simp, code_unfold] : "Pair{X,Y} .First() = (if (\<upsilon> Y) then X else invalid endif)"
apply(rule ext, rename_tac "\<tau>", simp add: foundation22[symmetric])
apply(case_tac "\<not>(\<tau> \<Turnstile> \<upsilon> Y)")
apply(erule foundation7'[THEN iffD2,
                         THEN foundation15[THEN iffD2,
                                           THEN StrongEq_L_subst2_rev]],simp_all)
apply(subgoal_tac "\<tau> \<Turnstile> \<upsilon> Y")
apply(erule foundation13[THEN iffD2, THEN StrongEq_L_subst2_rev], simp_all)
by(erule 1)

lemma proj2_exec [simp, code_unfold] : "Pair{X,Y} .Second() = (if (\<upsilon> X) then Y else invalid endif)"
apply(rule ext, rename_tac "\<tau>", simp add: foundation22[symmetric])
apply(case_tac "\<not>(\<tau> \<Turnstile> \<upsilon> X)")
apply(erule foundation7'[THEN iffD2, THEN foundation15[THEN iffD2,
                                  THEN StrongEq_L_subst2_rev]],simp_all)
apply(subgoal_tac "\<tau> \<Turnstile> \<upsilon> X")
apply(erule foundation13[THEN iffD2, THEN StrongEq_L_subst2_rev], simp_all)
by(erule 2)

(* < *)

subsection\<open>Test Statements\<close>
(*
Assert   "(\<tau> \<Turnstile> (Pair{\<lambda>_. \<lfloor>\<lfloor>x\<rfloor>\<rfloor>,\<lambda>_. \<lfloor>\<lfloor>x\<rfloor>\<rfloor>} \<doteq> Pair{\<lambda>_. \<lfloor>\<lfloor>x\<rfloor>\<rfloor>,\<lambda>_. \<lfloor>\<lfloor>x\<rfloor>\<rfloor>}))"
Assert   "(\<tau> \<Turnstile> (Pair{\<lambda>_. \<lfloor>x\<rfloor>,\<lambda>_. \<lfloor>x\<rfloor>} \<doteq> Pair{\<lambda>_. \<lfloor>x\<rfloor>,\<lambda>_. \<lfloor>x\<rfloor>}))"
*)

instantiation Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e  :: (equal,equal)equal
begin
  definition "HOL.equal k l \<longleftrightarrow>  (k::('a::equal,'b::equal)Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e) =  l"
  instance   by standard (rule equal_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_def)
end

lemma equal_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_code [code]:
  "HOL.equal k (l::('a::{equal,null},'b::{equal,null})Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e) \<longleftrightarrow> Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e k = Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e l"
  by (auto simp add: equal Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e.Rep_Pair\<^sub>b\<^sub>a\<^sub>s\<^sub>e_inject)

Assert "\<tau> \<Turnstile> invalid .First() \<triangleq> invalid "
Assert "\<tau> \<Turnstile> null .First() \<triangleq> invalid "
Assert "\<tau> \<Turnstile> null .Second() \<triangleq> invalid .Second() "
Assert "\<tau> \<Turnstile> Pair{invalid, true} \<triangleq> invalid "
Assert "\<tau> \<Turnstile> \<upsilon>(Pair{null, true}.First())"
Assert "\<tau> \<Turnstile> (Pair{null, true}).First() \<triangleq> null "
Assert "\<tau> \<Turnstile> (Pair{null, Pair{true,invalid}}).First() \<triangleq> invalid "

(*
Assert   "\<not> (\<tau> \<Turnstile> (Pair{\<one>,\<two>} \<doteq> Pair{\<two>,\<one>}))"
*)

(* > *)

end


section\<open>The Axiom of Pairing in $M[G]$\<close>

theory Pairing_Axiom
  imports
    Names
begin

context G_generic1
begin

lemma val_Upair :
  "\<one> \<in> G \<Longrightarrow> val(G,{\<langle>\<tau>,\<one>\<rangle>,\<langle>\<rho>,\<one>\<rangle>}) = {val(G,\<tau>),val(G,\<rho>)}"
  by (rule trans, subst def_val,auto)

lemma pairing_in_MG : "upair_ax(##M[G])"
proof -
  {
    fix x y
    assume "x \<in> M[G]" "y \<in> M[G]"
    moreover from this
    obtain \<tau> \<rho> where "val(G,\<tau>) = x" "val(G,\<rho>) = y" "\<rho> \<in> M"  "\<tau> \<in> M"
      using GenExtD by blast
    moreover from this
    have "\<langle>\<tau>,\<one>\<rangle> \<in> M" "\<langle>\<rho>,\<one>\<rangle>\<in>M"
      using pair_in_M_iff by auto
    moreover from this
    have "{\<langle>\<tau>,\<one>\<rangle>,\<langle>\<rho>,\<one>\<rangle>} \<in> M" (is "?\<sigma> \<in> _")
      using upair_in_M_iff by simp
    moreover from this
    have "val(G,?\<sigma>) \<in> M[G]"
      using GenExtI by simp
    moreover from calculation
    have "{val(G,\<tau>),val(G,\<rho>)} \<in> M[G]"
      using val_Upair one_in_G by simp
    ultimately
    have "{x,y} \<in> M[G]"
      by simp
  }
  then
  show ?thesis
    unfolding upair_ax_def upair_def by auto
qed

end \<comment> \<open>\<^locale>\<open>G_generic1\<close>\<close>

end


section \<open>Deterministic Büchi Automata Combinations\<close>

theory DBA_Combine
imports DBA DGBA
begin

  global_interpretation degeneralization: automaton_degeneralization_run
    dgba dgba.alphabet dgba.initial dgba.transition dgba.accepting "\<lambda> P w r p. gen infs P (p ## r)"
    dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    fst id
    defines degeneralize = degeneralization.degeneralize
    by (unfold_locales) (auto simp flip: sscan_smap)

  lemmas degeneralize_language[simp] = degeneralization.degeneralize_language[folded DBA.language_def]
  lemmas degeneralize_nodes_finite[iff] = degeneralization.degeneralize_nodes_finite[folded DBA.nodes_def]
  lemmas degeneralize_nodes_card = degeneralization.degeneralize_nodes_card[folded DBA.nodes_def]

  global_interpretation intersection: automaton_intersection_run
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    dgba.dgba dgba.alphabet dgba.initial dgba.transition dgba.accepting "\<lambda> P w r p. gen infs P (p ## r)"
    "\<lambda> c\<^sub>1 c\<^sub>2. [c\<^sub>1 \<circ> fst, c\<^sub>2 \<circ> snd]"
    defines intersect' = intersection.product
    by unfold_locales auto

  lemmas intersect'_language[simp] = intersection.product_language[folded DGBA.language_def]
  lemmas intersect'_nodes_finite = intersection.product_nodes_finite[folded DGBA.nodes_def]
  lemmas intersect'_nodes_card = intersection.product_nodes_card[folded DGBA.nodes_def]

  global_interpretation union: automaton_union_run
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    "\<lambda> c\<^sub>1 c\<^sub>2 pq. (c\<^sub>1 \<circ> fst) pq \<or> (c\<^sub>2 \<circ> snd) pq"
    defines union = union.product
    by (unfold_locales) (simp del: comp_apply)

  lemmas union_language = union.product_language
  lemmas union_nodes_finite = union.product_nodes_finite
  lemmas union_nodes_card = union.product_nodes_card

  global_interpretation intersection_list: automaton_intersection_list_run
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    dgba.dgba dgba.alphabet dgba.initial dgba.transition dgba.accepting "\<lambda> P w r p. gen infs P (p ## r)"
    "\<lambda> cs. map (\<lambda> k pp. (cs ! k) (pp ! k)) [0 ..< length cs]"
    defines intersect_list' = intersection_list.product
    by (unfold_locales) (auto simp: gen_def comp_def)

  lemmas intersect_list'_language[simp] = intersection_list.product_language[folded DGBA.language_def]
  lemmas intersect_list'_nodes_finite = intersection_list.product_nodes_finite[folded DGBA.nodes_def]
  lemmas intersect_list'_nodes_card = intersection_list.product_nodes_card[folded DGBA.nodes_def]

  global_interpretation union_list: automaton_union_list_run
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    dba.dba dba.alphabet dba.initial dba.transition dba.accepting "\<lambda> P w r p. infs P (p ## r)"
    "\<lambda> cs pp. \<exists> k < length cs. (cs ! k) (pp ! k)"
    defines union_list = union_list.product
    by (unfold_locales) (simp add: comp_def)

  lemmas union_list_language = union_list.product_language
  lemmas union_list_nodes_finite = union_list.product_nodes_finite
  lemmas union_list_nodes_card = union_list.product_nodes_card

  (* TODO: these compound definitions are annoying, can we move those into Deterministic theory *)

  abbreviation intersect where "intersect A B \<equiv> degeneralize (intersect' A B)"

  lemma intersect_language[simp]: "DBA.language (intersect A B) = DBA.language A \<inter> DBA.language B"
    by simp
  lemma intersect_nodes_finite:
    assumes "finite (DBA.nodes A)" "finite (DBA.nodes B)"
    shows "finite (DBA.nodes (intersect A B))"
    using intersect'_nodes_finite assms by simp
  lemma intersect_nodes_card:
    assumes "finite (DBA.nodes A)" "finite (DBA.nodes B)"
    shows "card (DBA.nodes (intersect A B)) \<le> 2 * card (DBA.nodes A) * card (DBA.nodes B)"
  proof -
    have "card (DBA.nodes (intersect A B)) \<le>
      max 1 (length (dgba.accepting (intersect' A B))) * card (DGBA.nodes (intersect' A B))"
      using degeneralize_nodes_card by this
    also have "length (dgba.accepting (intersect' A B)) = 2" by simp
    also have "card (DGBA.nodes (intersect' A B)) \<le> card (DBA.nodes A) * card (DBA.nodes B)"
      using intersect'_nodes_card assms by this
    finally show ?thesis by simp
  qed

  abbreviation intersect_list where "intersect_list AA \<equiv> degeneralize (intersect_list' AA)"

  lemma intersect_list_language[simp]: "DBA.language (intersect_list AA) = \<Inter> (DBA.language ` set AA)"
    by simp
  lemma intersect_list_nodes_finite:
    assumes "list_all (finite \<circ> DBA.nodes) AA"
    shows "finite (DBA.nodes (intersect_list AA))"
    using intersect_list'_nodes_finite assms by simp
  lemma intersect_list_nodes_card:
    assumes "list_all (finite \<circ> DBA.nodes) AA"
    shows "card (DBA.nodes (intersect_list AA)) \<le> max 1 (length AA) * prod_list (map (card \<circ> DBA.nodes) AA)"
  proof -
    have "card (DBA.nodes (intersect_list AA)) \<le>
      max 1 (length (dgba.accepting (intersect_list' AA))) * card (DGBA.nodes (intersect_list' AA))"
      using degeneralize_nodes_card by this
    also have "length (dgba.accepting (intersect_list' AA)) = length AA" by simp
    also have "card (DGBA.nodes (intersect_list' AA)) \<le> prod_list (map (card \<circ> DBA.nodes) AA)"
      using intersect_list'_nodes_card assms by this
    finally show ?thesis by simp
  qed

end


section \<open>Abstract Theory of Ample Set Partial Order Reduction\<close>

theory Ample_Abstract
imports
  Transition_System_Interpreted_Traces
  "Extensions/Relation_Extensions"
begin

  (*
    formalization of the abstract partial order reduction theory
    definitions and proofs adapted from
      [1] "Combining Partial Order Reductions with On-the-Fly Model-Checking"
        Doron Peled, FMSD, 1996
      [2] "Formal Verification of a Partial-Order Reduction Technique for Model Checking"
        Ching-Tsun Chou and Doron Peled, TACAS, 1996
  *)

  locale ample_base =
    transition_system_interpreted_traces ex en int ind +
    wellfounded_relation src
    for ex :: "'action \<Rightarrow> 'state \<Rightarrow> 'state"
    and en :: "'action \<Rightarrow> 'state \<Rightarrow> bool"
    and int :: "'state \<Rightarrow> 'interpretation"
    and ind :: "'action \<Rightarrow> 'action \<Rightarrow> bool"
    and src :: "'state \<Rightarrow> 'state \<Rightarrow> bool"
  begin

    definition ample_set :: "'state \<Rightarrow> 'action set \<Rightarrow> bool"
      where "ample_set q A \<equiv>
        A \<subseteq> {a. en a q} \<and>
        (A \<subset> {a. en a q} \<longrightarrow> A \<noteq> {}) \<and>
        (\<forall> a. A \<subset> {a. en a q} \<longrightarrow> a \<in> A \<longrightarrow> src (ex a q) q) \<and>
        (A \<subset> {a. en a q} \<longrightarrow> A \<subseteq> invisible) \<and>
        (\<forall> w. A \<subset> {a. en a q} \<longrightarrow> path w q \<longrightarrow> A \<inter> set w = {} \<longrightarrow> Ind A (set w))"

    (* implicit in [1, 2] *)
    lemma ample_subset:
      assumes "ample_set q A"
      shows "A \<subseteq> {a. en a q}"
      using assms unfolding ample_set_def by auto
    (* implicit in [1], condition C0 in [2] *)
    lemma ample_nonempty:
      assumes "ample_set q A" "A \<subset> {a. en a q}"
      shows "A \<noteq> {}"
      using assms unfolding ample_set_def by auto
    (* condition C2 in [1, 2] *)
    lemma ample_wellfounded:
      assumes "ample_set q A" "A \<subset> {a. en a q}" "a \<in> A"
      shows "src (ex a q) q"
      using assms unfolding ample_set_def by auto
    (* condition C3' in [1], not needed in [2] *)
    lemma ample_invisible:
      assumes "ample_set q A" "A \<subset> {a. en a q}"
      shows "A \<subseteq> invisible"
      using assms unfolding ample_set_def by auto
    (* condition C1 in [1, 2] *)
    lemma ample_independent:
      assumes "ample_set q A" "A \<subset> {a. en a q}" "path w q" "A \<inter> set w = {}"
      shows "Ind A (set w)"
      using assms unfolding ample_set_def by auto

    lemma ample_en[intro]: "ample_set q {a. en a q}" unfolding ample_set_def by blast

  end

  locale ample_abstract =
    S?: transition_system_complete ex en init int +
    R: transition_system_complete ex ren init int +
    ample_base ex en int ind src
    for ex :: "'action \<Rightarrow> 'state \<Rightarrow> 'state"
    and en :: "'action \<Rightarrow> 'state \<Rightarrow> bool"
    and init :: "'state \<Rightarrow> bool"
    and int :: "'state \<Rightarrow> 'interpretation"
    and ind :: "'action \<Rightarrow> 'action \<Rightarrow> bool"
    and src :: "'state \<Rightarrow> 'state \<Rightarrow> bool"
    and ren :: "'action \<Rightarrow> 'state \<Rightarrow> bool"
    +
    assumes reduction_ample: "q \<in> nodes \<Longrightarrow> ample_set q {a. ren a q}"
  begin

    lemma reduction_words_fin:
      assumes "q \<in> nodes" "R.path w q"
      shows "S.path w q"
      using assms(2, 1) ample_subset reduction_ample by induct auto
    lemma reduction_words_inf:
      assumes "q \<in> nodes" "R.run w q"
      shows "S.run w q"
      using reduction_words_fin assms by (auto intro: words_infI_construct)

    (* lemma 3.7 in [1] *)
    lemma reduction_step:
      assumes "q \<in> nodes" "run w q"
      obtains
        (deferred) a where "ren a q" "[a] \<preceq>\<^sub>F\<^sub>I w" |
        (omitted) "{a. ren a q} \<subseteq> invisible" "Ind {a. ren a q} (sset w)"
    proof (cases "{a. en a q} = {a. ren a q}")
      case True
      have 1: "run (shd w ## sdrop 1 w) q" using assms(2) by simp
      show ?thesis
      proof (rule deferred)
        show "ren (shd w) q" using True 1 by blast
        show "[shd w] \<preceq>\<^sub>F\<^sub>I w" by simp
      qed
    next
      case False
      have 1: "{a. ren a q} \<subset> {a. en a q}" using ample_subset reduction_ample assms(1) False by auto
      show ?thesis
      proof (cases "{a. ren a q} \<inter> sset w = {}")
        case True
        show ?thesis
        proof (rule omitted)
          show "{a. ren a q} \<subseteq> invisible" using ample_invisible reduction_ample assms(1) 1 by auto
          show "Ind {a. ren a q} (sset w)"
          proof safe
            fix a b
            assume 2: "b \<in> sset w" "ren a q"
            obtain u v where 3: "w = u @- b ## v" using split_stream_first' 2(1) by this
            have 4: "Ind {a. ren a q} (set (u @ [b]))"
            proof (rule ample_independent)
              show "ample_set q {a. ren a q}" using reduction_ample assms(1) by this
              show "{a. ren a q} \<subset> {a. en a q}" using 1 by this
              show "path (u @ [b]) q" using assms(2) 3 by blast
              show "{a. ren a q} \<inter> set (u @ [b]) = {}" using True 3 by auto
            qed
            show "ind a b" using 2 3 4 by auto
          qed
        qed
      next
        case False
        obtain u a v where 2: "w = u @- a ## v" "{a. ren a q} \<inter> set u = {}" "ren a q"
          using split_stream_first[OF False] by auto
        have 3: "path u q" using assms(2) unfolding 2(1) by auto
        have 4: "Ind {a. ren a q} (set u)"
          using ample_independent reduction_ample assms(1) 1 3 2(2) by this
        have 5: "Ind (set [a]) (set u)" using 4 2(3) by simp
        have 6: "[a] @ u =\<^sub>F u @ [a]" using 5 by blast
        show ?thesis
        proof (rule deferred)
          show "ren a q" using 2(3) by this
          have "[a] \<preceq>\<^sub>F\<^sub>I [a] @- u @- v" by blast
          also have "[a] @- u @- v = ([a] @ u) @- v" by simp
          also have "([a] @ u) @- v =\<^sub>I (u @ [a]) @- v" using 6 by blast
          also have "(u @ [a]) @- v = u @- [a] @- v" by simp
          also have "\<dots> = w" unfolding 2(1) by simp
          finally show "[a] \<preceq>\<^sub>F\<^sub>I w" by this
        qed
      qed
    qed

    (* theorem 3.9 in [1] *)
    lemma reduction_chunk:
      assumes "q \<in> nodes" "run ([a] @- v) q"
      obtains b b\<^sub>1 b\<^sub>2 u
      where
        "R.path (b @ [a]) q"
        "Ind {a} (set b)" "set b \<subseteq> invisible"
        "b =\<^sub>F b\<^sub>1 @ b\<^sub>2" "b\<^sub>1 @- u =\<^sub>I v" "Ind (set b\<^sub>2) (sset u)"
    using wellfounded assms
    proof (induct q arbitrary: thesis v rule: wfP_induct_rule)
      case (less q)
      show ?case
      proof (cases "ren a q")
        case (True)
        show ?thesis
        proof (rule less(2))
          show "R.path ([] @ [a]) q" using True by auto
          show "Ind {a} (set [])" by auto
          show "set [] \<subseteq> invisible" by auto
          show "[] =\<^sub>F [] @ []" by auto
          show "[] @- v =\<^sub>I v" by auto
          show "Ind (set []) (sset v)" by auto
        qed
      next
        case (False)
        have 0: "{a. en a q} \<noteq> {a. ren a q}" using False less(4) by auto
        show ?thesis
        using less(3, 4)
        proof (cases rule: reduction_step)
          case (deferred c)
          have 1: "ren c q" using deferred(1) by simp
          have 2: "ind a c"
          proof (rule le_fininf_ind'')
            show "[a] \<preceq>\<^sub>F\<^sub>I [a] @- v" by blast
            show "[c] \<preceq>\<^sub>F\<^sub>I [a] @- v" using deferred(2) by this
            show "a \<noteq> c" using False 1 by auto
          qed
          obtain v' where 3: "[a] @- v =\<^sub>I [c] @- [a] @- v'"
          proof -
            have 10: "[c] \<preceq>\<^sub>F\<^sub>I v"
            proof (rule le_fininf_not_member')
              show "[c] \<preceq>\<^sub>F\<^sub>I [a] @- v" using deferred(2) by this
              show "c \<notin> set [a]" using False 1 by auto
            qed
            obtain v' where 11: "v =\<^sub>I [c] @- v'" using 10 by blast
            have 12: "Ind (set [a]) (set [c])" using 2 by auto
            have 13: "[a] @ [c] =\<^sub>F [c] @ [a]" using 12 by blast
            have "[a] @- v =\<^sub>I [a] @- [c] @- v'" using 11 by blast
            also have "\<dots> = ([a] @ [c]) @- v'" by simp
            also have "\<dots> =\<^sub>I ([c] @ [a]) @- v'" using 13 by blast
            also have "\<dots> = [c] @- [a] @- v'" by simp
            finally show ?thesis using that by auto
          qed
          have 4: "run ([c] @- [a] @- v') q" using eq_inf_word 3 less(4) by this
          show ?thesis
          proof (rule less(1))
            show "src (ex c q) q"
              using ample_wellfounded ample_subset reduction_ample less(3) 0 1 by blast
            have 100: "en c q" using less(4) deferred(2) le_fininf_word by auto
            show "ex c q \<in> nodes" using less(3) 100 by auto
            show "run ([a] @- v') (ex c q)" using 4 by auto
          next
            fix b b\<^sub>1 b\<^sub>2 u
            assume 5: "R.path (b @ [a]) (ex c q)"
            assume 6: "Ind {a} (set b)"
            assume 7: "set b \<subseteq> invisible"
            assume 8: "b =\<^sub>F b\<^sub>1 @ b\<^sub>2"
            assume 9: "b\<^sub>1 @- u =\<^sub>I v'"
            assume 10: "Ind (set b\<^sub>2) (sset u)"
            show "thesis"
            proof (rule less(2))
              show "R.path (([c] @ b) @ [a]) q" using 1 5 by auto
              show "Ind {a} (set ([c] @ b))" using 6 2 by auto
              have 11: "c \<in> invisible"
                using ample_invisible ample_subset reduction_ample less(3) 0 1 by blast
              show "set ([c] @ b) \<subseteq> invisible" using 7 11 by auto
              have "[c] @ b =\<^sub>F [c] @ b\<^sub>1 @ b\<^sub>2" using 8 by blast
              also have "[c] @ b\<^sub>1 @ b\<^sub>2 = ([c] @ b\<^sub>1) @ b\<^sub>2" by simp
              finally show "[c] @ b =\<^sub>F ([c] @ b\<^sub>1) @ b\<^sub>2" by this
              show "([c] @ b\<^sub>1) @- u =\<^sub>I v"
              proof -
                have 10: "Ind (set [a]) (set [c])" using 2 by auto
                have 11: "[a] @ [c] =\<^sub>F [c] @ [a]" using 10 by blast
                have "[a] @- v =\<^sub>I [c] @- [a] @- v'" using 3 by this
                also have "\<dots> = ([c] @ [a]) @- v'" by simp
                also have "\<dots> =\<^sub>I ([a] @ [c]) @- v'" using 11 by blast
                also have "\<dots> = [a] @- [c] @- v'" by simp
                finally have 12: "[a] @- v =\<^sub>I [a] @- [c] @- v'" by this
                have 12: "v =\<^sub>I [c] @- v'" using 12 by blast
                have "([c] @ b\<^sub>1) @- u = [c] @- b\<^sub>1 @- u" by simp
                also have "\<dots> =\<^sub>I [c] @- v'" using 9 by blast
                also have "\<dots> =\<^sub>I v" using 12 by blast
                finally show ?thesis by this
              qed
              show "Ind (set b\<^sub>2) (sset u)" using 10 by this
            qed
          qed
        next
          case (omitted)
          have 1: "{a. ren a q} \<subseteq> invisible" using omitted(1) by simp
          have 2: "Ind {a. ren a q} (sset ([a] @- v))" using omitted(2) by simp
          obtain c where 3: "ren c q"
          proof -
            have 1: "en a q" using less(4) by auto
            show ?thesis using reduction_ample ample_nonempty less(3) 1 that by blast
          qed
          have 4: "Ind (set [c]) (sset ([a] @- v))" using 2 3 by auto
          have 6: "path [c] q" using reduction_ample ample_subset less(3) 3 by auto
          have 7: "run ([a] @- v) (target [c] q)" using diamond_fin_word_inf_word 4 6 less(4) by this
          show ?thesis
          proof (rule less(1))
            show "src (ex c q) q"
              using reduction_ample ample_wellfounded ample_subset less(3) 0 3 by blast
            show "ex c q \<in> nodes" using less(3) 6 by auto
            show "run ([a] @- v) (ex c q)" using 7 by auto
          next
            fix b s b\<^sub>1 b\<^sub>2 u
            assume 5: "R.path (b @ [a]) (ex c q)"
            assume 6: "Ind {a} (set b)"
            assume 7: "set b \<subseteq> invisible"
            assume 8: "b =\<^sub>F b\<^sub>1 @ b\<^sub>2"
            assume 9: "b\<^sub>1 @- u =\<^sub>I v"
            assume 10: "Ind (set b\<^sub>2) (sset u)"
            show "thesis"
            proof (rule less(2))
              show "R.path (([c] @ b) @ [a]) q" using 3 5 by auto
              show "Ind {a} (set ([c] @ b))"
              proof -
                have 1: "ind c a" using 4 by simp
                have 2: "ind a c" using independence_symmetric 1 by this
                show ?thesis using 6 2 by auto
              qed
              have 11: "c \<in> invisible" using 1 3 by auto
              show "set ([c] @ b) \<subseteq> invisible" using 7 11 by auto
              have 12: "Ind (set [c]) (set b\<^sub>1)"
              proof -
                have 1: "set b\<^sub>1 \<subseteq> sset v" using 9 by force
                have 2: "Ind (set [c]) (sset v)" using 4 by simp
                show ?thesis using 1 2 by auto
              qed
              have "[c] @ b =\<^sub>F [c] @ b\<^sub>1 @ b\<^sub>2" using 8 by blast
              also have "\<dots> = ([c] @ b\<^sub>1) @ b\<^sub>2" by simp
              also have "\<dots> =\<^sub>F (b\<^sub>1 @ [c]) @ b\<^sub>2" using 12 by blast
              also have "\<dots> = b\<^sub>1 @ [c] @ b\<^sub>2" by simp
              finally show "[c] @ b =\<^sub>F b\<^sub>1 @ [c] @ b\<^sub>2" by this
              show "b\<^sub>1 @- u =\<^sub>I v" using 9 by this
              have 13: "Ind (set [c]) (sset u)"
              proof -
                have 1: "sset u \<subseteq> sset v" using 9 by force
                have 2: "Ind (set [c]) (sset v)" using 4 by simp
                show ?thesis using 1 2 by blast
              qed
              show "Ind (set ([c] @ b\<^sub>2)) (sset u)" using 10 13 by auto
            qed
          qed
        qed
      qed
    qed

    (*
      q: initial state
      v\<^sub>1: operations of the original run processed so far
      v\<^sub>2: operations of the original run remaining
      l: operations executed in the reduced run, but not yet in the original run
      w: reduced run processed so far
      w\<^sub>1: selected reduced run processed so far
      w\<^sub>2: unselected reduced run processed so far
      u: continuation of w
    *)
    inductive reduced_run :: "'state \<Rightarrow> 'action list \<Rightarrow> 'action stream \<Rightarrow> 'action list \<Rightarrow>
      'action list \<Rightarrow> 'action list \<Rightarrow> 'action list \<Rightarrow> 'action stream \<Rightarrow> bool"
      where
        init: "reduced_run q [] v [] [] [] [] v" |
        absorb: "reduced_run q v\<^sub>1 ([a] @- v\<^sub>2) l w w\<^sub>1 w\<^sub>2 u \<Longrightarrow> a \<in> set l \<Longrightarrow>
          reduced_run q (v\<^sub>1 @ [a]) v\<^sub>2 (remove1 a l) w w\<^sub>1 w\<^sub>2 u" |
        extend: "reduced_run q v\<^sub>1 ([a] @- v\<^sub>2) l w w\<^sub>1 w\<^sub>2 u \<Longrightarrow> a \<notin> set l \<Longrightarrow>
          R.path (b @ [a]) (target w q) \<Longrightarrow>
          Ind {a} (set b) \<Longrightarrow> set b \<subseteq> invisible \<Longrightarrow>
          b =\<^sub>F b\<^sub>1 @ b\<^sub>2 \<Longrightarrow> [a] @- b\<^sub>1 @- u' =\<^sub>I u \<Longrightarrow> Ind (set b\<^sub>2) (sset u') \<Longrightarrow>
          reduced_run q (v\<^sub>1 @ [a]) v\<^sub>2 (l @ b\<^sub>1) (w @ b @ [a]) (w\<^sub>1 @ b\<^sub>1 @ [a]) (w\<^sub>2 @ b\<^sub>2) u'"

    lemma reduced_run_words_fin:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "R.path w q"
      using assms by induct auto

    lemma reduced_run_invar_2:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "v\<^sub>2 =\<^sub>I l @- u"
    using assms
    proof induct
      case (init q v)
      show ?case by simp
    next
      case (absorb q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u)
      obtain l\<^sub>1 l\<^sub>2 where 10: "l = l\<^sub>1 @ [a] @ l\<^sub>2" "a \<notin> set l\<^sub>1"
        using split_list_first[OF absorb(3)] by auto
      have 11: "Ind {a} (set l\<^sub>1)"
      proof (rule le_fininf_ind')
        show "[a] \<preceq>\<^sub>F\<^sub>I l @- u" using absorb(2) by auto
        show "l\<^sub>1 \<preceq>\<^sub>F\<^sub>I l @- u" unfolding 10(1) by auto
        show "a \<notin> set l\<^sub>1" using 10(2) by this
      qed
      have 12: "Ind (set [a]) (set l\<^sub>1)" using 11 by auto
      have "[a] @ remove1 a l = [a] @ l\<^sub>1 @ l\<^sub>2" unfolding 10(1) remove1_append using 10(2) by auto
      also have "\<dots> =\<^sub>F ([a] @ l\<^sub>1) @ l\<^sub>2" by simp
      also have "\<dots> =\<^sub>F (l\<^sub>1 @ [a]) @ l\<^sub>2" using 12 by blast
      also have "\<dots> = l" unfolding 10(1) by simp
      finally have 13: "[a] @ remove1 a l =\<^sub>F l" by this
      have "[a] @- remove1 a l @- u = ([a] @ remove1 a l) @- u" unfolding conc_conc by simp
      also have "\<dots> =\<^sub>I l @- u" using 13 by blast
      also have "\<dots> =\<^sub>I [a] @- v\<^sub>2" using absorb(2) by auto
      finally show ?case by blast
    next
      case (extend q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u b b\<^sub>1 b\<^sub>2 u')
      have 11: "Ind {a} (set l)"
      proof (rule le_fininf_ind')
        show "[a] \<preceq>\<^sub>F\<^sub>I l @- u" using extend(2) by auto
        show "l \<preceq>\<^sub>F\<^sub>I l @- u" by auto
        show "a \<notin> set l" using extend(3) by this
      qed
      have 11: "Ind (set [a]) (set l)" using 11 by auto
      have 12: "eq_fin ([a] @ l) (l @ [a])" using 11 by blast
      have 131: "set b\<^sub>1 \<subseteq> set b" using extend(7) by auto
      have 132: "Ind (set [a]) (set b)" using extend(5) by auto
      have 13: "Ind (set [a]) (set b\<^sub>1)" using 131 132 by auto
      have 14: "eq_fin ([a] @ b\<^sub>1) (b\<^sub>1 @ [a])" using 13 by blast
      have "[a] @- ((l @ b\<^sub>1) @- u') = ([a] @ l) @- b\<^sub>1 @- u'" by simp
      also have "eq_inf \<dots> ((l @ [a]) @- b\<^sub>1 @- u')" using 12 by blast
      also have "\<dots> = l @- [a] @- b\<^sub>1 @- u'" by simp
      also have "eq_inf \<dots> (l @- u)" using extend(8) by blast
      also have "eq_inf \<dots> ([a] @- v\<^sub>2)" using extend(2) by auto
      finally show ?case by blast
    qed

    lemma reduced_run_invar_1:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "v\<^sub>1 @ l =\<^sub>F w\<^sub>1"
    using assms
    proof induct
      case (init q v)
      show ?case by simp
    next
      case (absorb q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u)
      have 1: "[a] @- v\<^sub>2 =\<^sub>I l @- u" using reduced_run_invar_2 absorb(1) by this
      obtain l\<^sub>1 l\<^sub>2 where 10: "l = l\<^sub>1 @ [a] @ l\<^sub>2" "a \<notin> set l\<^sub>1"
        using split_list_first[OF absorb(3)] by auto
      have 11: "Ind {a} (set l\<^sub>1)"
      proof (rule le_fininf_ind')
        show "[a] \<preceq>\<^sub>F\<^sub>I l @- u" using 1 by auto
        show "l\<^sub>1 \<preceq>\<^sub>F\<^sub>I l @- u" unfolding 10(1) by auto
        show "a \<notin> set l\<^sub>1" using 10(2) by this
      qed
      have 12: "Ind (set [a]) (set l\<^sub>1)" using 11 by auto
      have "[a] @ remove1 a l = [a] @ l\<^sub>1 @ l\<^sub>2" unfolding 10(1) remove1_append using 10(2) by auto
      also have "\<dots> =\<^sub>F ([a] @ l\<^sub>1) @ l\<^sub>2" by simp
      also have "\<dots> =\<^sub>F (l\<^sub>1 @ [a]) @ l\<^sub>2" using 12 by blast
      also have "\<dots> = l" unfolding 10(1) by simp
      finally have 13: "[a] @ remove1 a l =\<^sub>F l" by this
      have "w\<^sub>1 =\<^sub>F v\<^sub>1 @ l" using absorb(2) by auto
      also have "\<dots> =\<^sub>F v\<^sub>1 @ ([a] @ remove1 a l)" using 13 by blast
      also have "\<dots> = (v\<^sub>1 @ [a]) @ remove1 a l" by simp
      finally show ?case by auto
    next
      case (extend q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u b b\<^sub>1 b\<^sub>2 u')
      have 1: "[a] @- v\<^sub>2 =\<^sub>I l @- u" using reduced_run_invar_2 extend(1) by this
      have 11: "Ind {a} (set l)"
      proof (rule le_fininf_ind')
        show "[a] \<preceq>\<^sub>F\<^sub>I l @- u" using 1 by auto
        show "l \<preceq>\<^sub>F\<^sub>I l @- u" by auto
        show "a \<notin> set l" using extend(3) by auto
      qed
      have 11: "Ind (set [a]) (set l)" using 11 by auto
      have 12: "eq_fin ([a] @ l) (l @ [a])" using 11 by blast
      have 131: "set b\<^sub>1 \<subseteq> set b" using extend(7) by auto
      have 132: "Ind (set [a]) (set b)" using extend(5) by auto
      have 13: "Ind (set [a]) (set b\<^sub>1)" using 131 132 by auto
      have 14: "eq_fin ([a] @ b\<^sub>1) (b\<^sub>1 @ [a])" using 13 by blast
      have "eq_fin (w\<^sub>1 @ b\<^sub>1 @ [a]) (w\<^sub>1 @ [a] @ b\<^sub>1)" using 14 by blast
      also have "eq_fin \<dots> ((v\<^sub>1 @ l) @ [a] @ b\<^sub>1)" using extend(2) by blast
      also have "eq_fin \<dots> (v\<^sub>1 @ (l @ [a]) @ b\<^sub>1)" by simp
      also have "eq_fin \<dots> (v\<^sub>1 @ ([a] @ l) @ b\<^sub>1)" using 12 by blast
      also have "\<dots> = (v\<^sub>1 @ [a]) @ l @ b\<^sub>1" by simp
      finally show ?case by auto
    qed

    lemma reduced_run_invisible:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "set w\<^sub>2 \<subseteq> invisible"
    using assms
    proof induct
      case (init q v)
      show ?case by simp
    next
      case (absorb q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u)
      show ?case using absorb(2) by this
    next
      case (extend q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u b b\<^sub>1 b\<^sub>2 u')
      have 1: "set b\<^sub>2 \<subseteq> set b" using extend(7) by auto
      show ?case unfolding set_append using extend(2) extend(6) 1 by blast
    qed

    lemma reduced_run_ind:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "Ind (set w\<^sub>2) (sset u)"
    using assms
    proof induct
      case (init q v)
      show ?case by simp
    next
      case (absorb q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u)
      show ?case using absorb(2) by this
    next
      case (extend q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u b b\<^sub>1 b\<^sub>2 u')
      have 1: "sset u' \<subseteq> sset u" using extend(8) by force
      show ?case using extend(2) extend(9) 1 unfolding set_append by blast
    qed

    lemma reduced_run_decompose:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "w =\<^sub>F w\<^sub>1 @ w\<^sub>2"
    using assms
    proof induct
      case (init q v)
      show ?case by simp
    next
      case (absorb q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u)
      show ?case using absorb(2) by this
    next
      case (extend q v\<^sub>1 a v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u b b\<^sub>1 b\<^sub>2 u')
      have 1: "Ind (set [a]) (set b\<^sub>2)" using extend(5) extend(7) by auto
      have 2: "Ind (set w\<^sub>2) (set (b\<^sub>1 @ [a]))"
      proof -
        have 1: "Ind (set w\<^sub>2) (sset u)" using reduced_run_ind extend(1) by this
        have 2: "u =\<^sub>I [a] @- b\<^sub>1 @- u'" using extend(8) by auto
        have 3: "sset u = sset ([a] @- b\<^sub>1 @- u')" using 2 by blast
        show ?thesis unfolding set_append using 1 3 by simp
      qed
      have "w @ b @ [a] =\<^sub>F (w\<^sub>1 @ w\<^sub>2) @ b @ [a]" using extend(2) by blast
      also have "\<dots> =\<^sub>F (w\<^sub>1 @ w\<^sub>2) @ (b\<^sub>1 @ b\<^sub>2) @ [a]" using extend(7) by blast
      also have "\<dots> = w\<^sub>1 @ w\<^sub>2 @ b\<^sub>1 @ (b\<^sub>2 @ [a])" by simp
      also have "\<dots> =\<^sub>F w\<^sub>1 @ w\<^sub>2 @ b\<^sub>1 @ ([a] @ b\<^sub>2)" using 1 by blast
      also have "\<dots> =\<^sub>F w\<^sub>1 @ (w\<^sub>2 @ (b\<^sub>1 @ [a])) @ b\<^sub>2" by simp
      also have "\<dots> =\<^sub>F w\<^sub>1 @ ((b\<^sub>1 @ [a]) @ w\<^sub>2) @ b\<^sub>2" using 2 by blast
      also have "\<dots> =\<^sub>F (w\<^sub>1 @ b\<^sub>1 @ [a]) @ w\<^sub>2 @ b\<^sub>2" by simp
      finally show ?case by this
    qed

    lemma reduced_run_project:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "project visible w\<^sub>1 = project visible w"
    proof -
      have 1: "w\<^sub>1 @ w\<^sub>2 =\<^sub>F w" using reduced_run_decompose assms by auto
      have 2: "set w\<^sub>2 \<subseteq> invisible" using reduced_run_invisible assms by this
      have 3: "project visible w\<^sub>2 = []" unfolding filter_empty_conv using 2 by auto
      have "project visible w\<^sub>1 = project visible w\<^sub>1 @ project visible w\<^sub>2" using 3 by simp
      also have "\<dots> = project visible (w\<^sub>1 @ w\<^sub>2)" by simp
      also have "\<dots> = list_of (lproject visible (llist_of (w\<^sub>1 @ w\<^sub>2)))" by simp
      also have "\<dots> = list_of (lproject visible (llist_of w))"
        using eq_fin_lproject_visible 1 by metis
      also have "\<dots> = project visible w" by simp
      finally show ?thesis by this
    qed

    lemma reduced_run_length_1:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "length v\<^sub>1 \<le> length w\<^sub>1"
      using reduced_run_invar_1 assms by force
    lemma reduced_run_length:
      assumes "reduced_run q v\<^sub>1 v\<^sub>2 l w w\<^sub>1 w\<^sub>2 u"
      shows "length v\<^sub>1 \<le> length w"
    proof -
      have "length v\<^sub>1 \<le> length w\<^sub>1" using reduced_run_length_1 assms by this
      also have "\<dots> \<le> length w" using reduced_run_decompose assms by force
      finally show ?thesis by this
    qed

    lemma reduced_run_step:
      assumes "q \<in> nodes" "run (v\<^sub>1 @- [a] @- v\<^sub>2) q"
      assumes "reduced_run q v\<^sub>1 ([a] @- v\<^sub>2) l w w\<^sub>1 w\<^sub>2 u"
      obtains l' w' w\<^sub>1' w\<^sub>2' u'
      where "reduced_run q (v\<^sub>1 @ [a]) v\<^sub>2 l' (w @ w') (w\<^sub>1 @ w\<^sub>1') (w\<^sub>2 @ w\<^sub>2') u'"
    proof (cases "a \<in> set l")
      case True
      show ?thesis
      proof (rule that, rule absorb)
        show "reduced_run q v\<^sub>1 ([a] @- v\<^sub>2) l (w @ []) (w\<^sub>1 @ []) (w\<^sub>2 @ []) u" using assms(3) by simp
        show "a \<in> set l" using True by this
      qed
    next
      case False
      have 1: "v\<^sub>1 @ l =\<^sub>F w\<^sub>1" using reduced_run_invar_1 assms(3) by this
      have 2: "[a] @- v\<^sub>2 =\<^sub>I l @- u" using reduced_run_invar_2 assms(3) by this
      have 3: "w =\<^sub>F w\<^sub>1 @ w\<^sub>2" using reduced_run_decompose assms(3) by this
      have "v\<^sub>1 @ l @ w\<^sub>2 = (v\<^sub>1 @ l) @ w\<^sub>2" by simp
      also have "\<dots> =\<^sub>F w\<^sub>1 @ w\<^sub>2" using 1 by blast
      also have "\<dots> =\<^sub>F w" using 3 by blast
      finally have 4: "v\<^sub>1 @ l @ w\<^sub>2 =\<^sub>F w" by this
      have 5: "run ((v\<^sub>1 @ l) @- w\<^sub>2 @- u) q"
      proof (rule diamond_fin_word_inf_word')
        show "Ind (set w\<^sub>2) (sset u)" using reduced_run_ind assms(3) by this
        have 6: "R.path w q" using reduced_run_words_fin assms(3) by this
        have 7: "path w q" using reduction_words_fin assms(1) 6 by auto
        show "path ((v\<^sub>1 @ l) @ w\<^sub>2) q" using eq_fin_word 4 7 by auto
        have 8: "v\<^sub>1 @- [a] @- v\<^sub>2 =\<^sub>I v\<^sub>1 @- l @- u" using 2 by blast
        show "run ((v\<^sub>1 @ l) @- u) q" using eq_inf_word assms(2) 8 by auto
      qed
      have 6: "run (w @- u) q" using eq_inf_word 4 5 by (metis eq_inf_concat_end shift_append)
      have 7: "[a] \<preceq>\<^sub>F\<^sub>I l @- u" using 2 by blast
      have 8: "[a] \<preceq>\<^sub>F\<^sub>I u" using le_fininf_not_member' 7 False by this
      obtain u' where 9: "u =\<^sub>I [a] @- u'" using 8 by rule
      have 101: "target w q \<in> nodes" using assms(1) 6 by auto
      have 10: "run ([a] @- u') (target w q)" using eq_inf_word 9 6 by blast
      obtain b b\<^sub>1 b\<^sub>2 u'' where 11:
        "R.path (b @ [a]) (target w q)"
        "Ind {a} (set b)" "set b \<subseteq> invisible"
        "b =\<^sub>F b\<^sub>1 @ b\<^sub>2" "b\<^sub>1 @- u'' =\<^sub>I u'" "Ind (set b\<^sub>2) (sset u'')"
        using reduction_chunk 101 10 by this
      show ?thesis
      proof (rule that, rule extend)
        show "reduced_run q v\<^sub>1 ([a] @- v\<^sub>2) l w w\<^sub>1 w\<^sub>2 u" using assms(3) by this
        show "a \<notin> set l" using False by this
        show "R.path (b @ [a]) (target w q)" using 11(1) by this
        show "Ind {a} (set b)" using 11(2) by this
        show "set b \<subseteq> invisible" using 11(3) by this
        show "b =\<^sub>F b\<^sub>1 @ b\<^sub>2" using 11(4) by this
        show "[a] @- b\<^sub>1 @- u'' =\<^sub>I u" using 9 11(5) by blast
        show "Ind (set b\<^sub>2) (sset u'')" using 11(6) by this
      qed
    qed

    (* theorem 3.11 in [1] *)
    lemma reduction_word:
      assumes "q \<in> nodes" "run v q"
      obtains u w
      where
        "R.run w q"
        "v =\<^sub>I u" "u \<preceq>\<^sub>I w"
        "lproject visible (llist_of_stream u) = lproject visible (llist_of_stream w)"
    proof -
      define P where "P \<equiv> \<lambda> k w w\<^sub>1. \<exists> l w\<^sub>2 u. reduced_run q (stake k v) (sdrop k v) l w w\<^sub>1 w\<^sub>2 u"
      obtain w w\<^sub>1 where 1: "\<And> k. P k (w k) (w\<^sub>1 k)" "chain w" "chain w\<^sub>1"
      proof (rule chain_construct_2'[of P])
        show "P 0 [] []" unfolding P_def using init by force
      next
        fix k w w\<^sub>1
        assume 1: "P k w w\<^sub>1"
        obtain l w\<^sub>2 u where 2: "reduced_run q (stake k v) (sdrop k v) l w w\<^sub>1 w\<^sub>2 u"
          using 1 unfolding P_def by auto
        obtain l' w' w\<^sub>1' w\<^sub>2' u' where 3:
          "reduced_run q (stake k v @ [v !! k]) (sdrop (Suc k) v) l' (w @ w') (w\<^sub>1 @ w\<^sub>1') (w\<^sub>2 @ w\<^sub>2') u'"
        proof (rule reduced_run_step)
          show "q \<in> nodes" using assms(1) by this
          show "run (stake k v @- [v !! k] @- sdrop (Suc k) v) q"
            using assms(2) by (metis shift_append stake_Suc stake_sdrop)
          show "reduced_run q (stake k v) ([v !! k] @- sdrop (Suc k) v) l w w\<^sub>1 w\<^sub>2 u"
            using 2 by (metis sdrop_simps shift.simps stream.collapse)
        qed
        show "\<exists> w' w\<^sub>1'. P (Suc k) w' w\<^sub>1' \<and> w \<le> w' \<and> w\<^sub>1 \<le> w\<^sub>1'"
          unfolding P_def using 3 by (metis prefix_fin_append stake_Suc)
        show "k \<le> length w" using reduced_run_length 2 by force
        show "k \<le> length w\<^sub>1" using reduced_run_length_1 2 by force
      qed rule
      obtain l w\<^sub>2 u where 2:
        "\<And> k. reduced_run q (stake k v) (sdrop k v) (l k) (w k) (w\<^sub>1 k) (w\<^sub>2 k) (u k)"
        using 1(1) unfolding P_def by metis
      show ?thesis
      proof
        show "R.run (Word_Prefixes.limit w) q" using reduced_run_words_fin 1(2) 2 by blast
        show "v =\<^sub>I Word_Prefixes.limit w\<^sub>1"
        proof
          show "v \<preceq>\<^sub>I Word_Prefixes.limit w\<^sub>1"
          proof (rule le_infI_chain_right')
            show "chain w\<^sub>1" using 1(3) by this
            show "\<And> k. stake k v \<preceq>\<^sub>F w\<^sub>1 k" using reduced_run_invar_1[OF 2] by auto
          qed
          show "Word_Prefixes.limit w\<^sub>1 \<preceq>\<^sub>I v"
          proof (rule le_infI_chain_left)
            show "chain w\<^sub>1" using 1(3) by this
          next
            fix k
            have "w\<^sub>1 k =\<^sub>F stake k v @ l k" using reduced_run_invar_1 2 by blast
            also have "\<dots> \<le>\<^sub>F\<^sub>I stake k v @- l k @- u k" by auto
            also have "\<dots> =\<^sub>I stake k v @- sdrop k v" using reduced_run_invar_2[OF 2] by blast
            also have "\<dots> = v" by simp
            finally show "w\<^sub>1 k \<preceq>\<^sub>F\<^sub>I v" by this
          qed
        qed
        show "Word_Prefixes.limit w\<^sub>1 \<preceq>\<^sub>I Word_Prefixes.limit w"
        proof (rule le_infI_chain_left)
          show "chain w\<^sub>1" using 1(3) by this
        next
          fix k
          have "w\<^sub>1 k \<preceq>\<^sub>F w k" using reduced_run_decompose[OF 2] by blast
          also have "\<dots> \<le>\<^sub>F\<^sub>I Word_Prefixes.limit w" using chain_prefix_limit 1(2) by this
          finally show "w\<^sub>1 k \<preceq>\<^sub>F\<^sub>I Word_Prefixes.limit w" by this
        qed
        show "lproject visible (llist_of_stream (Word_Prefixes.limit w\<^sub>1)) =
          lproject visible (llist_of_stream (Word_Prefixes.limit w))"
          using lproject_eq_limit_chain reduced_run_project 1 unfolding P_def by metis
      qed
    qed

    (* theorem 3.12 in [1] *)
    lemma reduction_equivalent:
      assumes "q \<in> nodes" "run u q"
      obtains v
      where "R.run v q" "snth (smap int (q ## trace u q)) \<approx> snth (smap int (q ## trace v q))"
    proof -
      obtain v w where 1: "R.run w q" "u =\<^sub>I v" "v \<preceq>\<^sub>I w"
        "lproject visible (llist_of_stream v) = lproject visible (llist_of_stream w)"
        using reduction_word assms by this
      show ?thesis
      proof
        show "R.run w q" using 1(1) by this
        show "snth (smap int (q ## trace u q)) \<approx> snth (smap int (q ## trace w q))"
        proof (rule execute_inf_visible)
          show "run u q" using assms(2) by this
          show "run w q" using reduction_words_inf assms(1) 1(1) by auto
          have "u =\<^sub>I v" using 1(2) by this
          also have "\<dots> \<preceq>\<^sub>I w" using 1(3) by this
          finally show "u \<preceq>\<^sub>I w" by this
          show "w \<preceq>\<^sub>I w" by simp
          have "lproject visible (llist_of_stream u) = lproject visible (llist_of_stream v)"
            using eq_inf_lproject_visible 1(2) by this
          also have "\<dots> = lproject visible (llist_of_stream w)" using 1(4) by this
          finally show "lproject visible (llist_of_stream u) = lproject visible (llist_of_stream w)" by this
        qed
      qed
    qed

    lemma reduction_language_subset: "R.language \<subseteq> S.language"
      unfolding S.language_def R.language_def using reduction_words_inf by blast

    lemma reduction_language_stuttering:
      assumes "u \<in> S.language"
      obtains v
      where "v \<in> R.language" "snth u \<approx> snth v"
    proof -
      obtain q v where 1: "u = smap int (q ## trace v q)" "init q" "S.run v q" using assms by rule
      obtain v' where 2: "R.run v' q" "snth (smap int (q ## trace v q)) \<approx> snth (smap int (q ## trace v' q))"
        using reduction_equivalent 1(2, 3) by blast
      show ?thesis
      proof (intro that R.languageI)
        show "smap int (q ## trace v' q) = smap int (q ## trace v' q)" by rule
        show "init q" using 1(2) by this
        show "R.run v' q" using 2(1) by this
        show "snth u \<approx> snth (smap int (q ## trace v' q))" unfolding 1(1) using 2(2) by this
      qed
    qed

  end

end