theory flash1Bra  imports flash1Rev

  begin
lemma onInv1:

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

     b1:"r \<in> rules N" and b2:"invf=inv1  iInv1  iInv2 "
   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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX1 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_GetX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_GetXVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Replace  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_ReplaceVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_ShWb N ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_ShWbVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_GetX_GetX2 ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_GetX_GetX2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_PutXAcksDone ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_Local_PutXAcksDoneVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX7 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX7VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Nak2  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_Nak2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_ReplaceHomeShrVld ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_ReplaceHomeShrVldVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_Put  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_PutVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX5 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX5VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Wb ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_WbVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Get  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_GetVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_Replace ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_ReplaceVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_ReplaceShrVld  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_ReplaceShrVldVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX8 N  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX8VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_InvAck_2 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_InvAck_2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_Get_Nak2  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_Get_Nak2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Remote_Replace  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis PI_Remote_ReplaceVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Nak_Home ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_Nak_HomeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Put2  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_Put2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_InvAck_1  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_InvAck_1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX11 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX11VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX6 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX6VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_Get_Put2  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_Get_Put2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_Get_Put ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_Get_PutVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_GetX_PutX1 N ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_GetX_PutX1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_InvAck_1_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_InvAck_1_HomeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_Get_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_Get_Nak1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_Nak1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_Nak2  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_Nak2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX10_home N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX10_homeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Remote_Get  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis PI_Remote_GetVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_Nak3  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_Nak3VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX10 N  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX10VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX2 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_Get_Put1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_Get_Put1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_PutX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_PutXVsInv1 )
          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 (inv1  iInv1  iInv2 ) (Store  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis StoreVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_FAck ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_FAckVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX3 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX3VsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_GetX_PutX3 ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_GetX_PutX3VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_GetX_PutX  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_GetX_PutXVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX8_home N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX8_homeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Put1 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_Put1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_GetX_GetX1 ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_GetX_GetX1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (StoreHome ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis StoreHomeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_GetX_Nak  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_GetX_NakVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Inv  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_InvVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Remote_PutX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis PI_Remote_PutXVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_GetX_PutX4 ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_GetX_PutX4VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX4 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX4VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Nak  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_NakVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_GetX_PutX2 N ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_GetX_PutX2VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Put ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_Local_PutVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_Nak1VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Nak_Clear ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_Nak_ClearVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_PutX ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_PutXVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Nak3  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_Nak3VsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_GetX_Nak_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_GetX_Nak_HomeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Local_Get_Get ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis PI_Local_Get_GetVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_GetX_PutX9 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_GetX_PutX9VsInv1 )
          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 (inv1  iInv1  iInv2 ) (PI_Remote_GetX  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis PI_Remote_GetXVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_ReplaceHome ) (invariants N) "
            apply(cut_tac   a1  a2  a3   b2 c2 )
            by (metis NI_ReplaceHomeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Remote_GetX_PutX_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Remote_GetX_PutX_HomeVsInv1 )
          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 (inv1  iInv1  iInv2 ) (NI_Local_Get_Put3  iRule1 ) (invariants N) "
            apply(cut_tac  c2   a1  a2  a3 )
            by (metis NI_Local_Get_Put3VsInv1 )
          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


theory Example
  imports
    "../Map_Interface"
    List_Less
    List_Copy
    Arl_Ext
    "../Export_Wrappers"
begin

definition "string_dr_assn \<equiv> mk_assn string_assn"

abbreviation "string_list_assn strs strsi \<equiv> arl_elem_assn string_dr_assn strs strsi"

lemma string_dr_assn_eq [simp]: "\<upharpoonleft>string_dr_assn = string_assn"
  unfolding string_dr_assn_def
  by fastforce

interpretation map: rbt_map
  list_le
  string_dr_assn
  arl_free
  snat.assn
  "\<lambda>x. Mreturn ()"
  "TYPE(nat list)"
  "TYPE((8 word, 'l::len2) array_list)"
  _
  _
  "\<lambda>x. Mreturn x"
proof(standard, goal_cases)
  case (1 lhs lhsi rhs rhsi)
  then show ?case
    using list_le_rule by fastforce
next
  case (2 k ki)
  then show ?case by vcg
next
  case (3 v vi)
  then show ?case by vcg
next
  case (4 v vi)
  then show ?case by vcg
qed

definition list_id_map :: "'a list \<Rightarrow> (nat \<rightharpoonup> 'a)" where
  "list_id_map xs = (\<lambda>i. if i < length xs then Some (xs ! i) else None)"

definition is_id_bijection :: "'a list \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('b \<rightharpoonup> 'a) \<Rightarrow> bool" where
  "is_id_bijection xs m1 m2 \<equiv> (\<forall> x \<in> set xs. (m2 \<circ>\<^sub>m m1) x = Some x)"

type_synonym stringi = "(8 word, 64) array_list"

type_synonym 'a array_list_64 = "('a, 64) array_list"

interpretation copy: arl_copy "TYPE(8 word)" unat.assn "\<lambda>x. Mreturn x"
  by (standard, vcg)

interpretation monad_syntax_M_loc .

lemma arl_mems_nth_rule [vcg_rules]:
"
  llvm_htriple
  (arl_elem_assn_ex A xs xsi arl {} ** \<upharpoonleft>snat.assn i ii ** \<up>(i < length xs))
  (arl_nth arl ii)
  (\<lambda>elem. arl_elem_assn_ex A xs xsi arl {i} ** \<upharpoonleft>A (xs ! i) elem ** \<up>(elem = xsi ! i))
"
  unfolding arl_elem_assn_ex_def
  apply vcg
  apply vcg_compat
  apply (sep | find_sep)+
    apply ((auto dest!: list_assn_pure_partD))
  unfolding idxe_map_def
  by (simp add: restrict_map_insert)

partial_function (M) make_id_map_rec' where [llvm_code]:
  "make_id_map_rec' strs i =
  do {
    len \<leftarrow> arl_len strs;
    if i < len
    then do {
      ip1 \<leftarrow> ll_add i 1;
      m \<leftarrow> make_id_map_rec' strs ip1;
      str \<leftarrow> arl_nth strs i;
      str_copy \<leftarrow> copy.arl_copy str;
      map.insert_opt str_copy i m
    }
    else map.empty
  }"

definition make_id_map_loop' where [llvm_code]:
  "make_id_map_loop' strs =
  do {
    len \<leftarrow> arl_len strs;
    empty_map \<leftarrow> map.empty;
    llc_for_range 0 len
    (\<lambda>i m. do {
        str \<leftarrow> arl_nth strs i;
        str_copy \<leftarrow> copy.arl_copy str;
        map.insert_opt str_copy i m
    })
    empty_map
  }"

definition "make_id_map_loop'_inv strs strsi i mi \<equiv>
  (
    EXS m. map.rbt_map_assn m mi **
    string_list_assn strs strsi **
    \<up>(is_id_bijection (take i strs) m (list_id_map strs))
  )"

declare string_dr_assn_eq[simp del]

lemma pure_part_pure_conjI:
  "\<lbrakk>sep_is_pure_assn X; sep_is_pure_assn Y; pure_part X; pure_part Y\<rbrakk> \<Longrightarrow> pure_part (X ** Y)"
  by (metis pure_part_pure_conj_eq pure_part_pure_eq)

lemma pure_sep_set_img_pure_partI:
  assumes
    fin: "finite X" and
    pps: "\<And>x. x\<in>X \<longrightarrow> sep_is_pure_assn (P x) \<and> pure_part (P x)"
  shows
    "pure_part (\<Union>*x\<in>X. P x)" and "sep_is_pure_assn (\<Union>*x\<in>X. P x)"
  using fin pps
proof(induction X arbitrary: )
  case empty
  {
    case 1 thus ?case by auto
  next
    case 2 thus ?case by simp
  }
next
  case (insert x F)
  {
    case 1 with insert show ?case
      apply auto
      apply (rule pure_part_pure_conjI)
      apply auto
      done
  next
    case 2 thus ?case
      by (blast intro: sep_is_pure_assn_imgI)
  }
qed

lemma string_assn_arl_elem_assnI:
"\<upharpoonleft>string_dr_assn str (stri::(8 word, 'l::len2) array_list)
   \<turnstile> arl_elem_assn unat.assn str stri ** \<up>(4 < LENGTH('l))"
  unfolding string_dr_assn_eq arl_elem_assn_def'
  apply (sep | find_sep)+
  apply isep_intro_ex
  apply (sep | find_sep)+
  unfolding LLVM_DS_List_Assn.list_assn_def
  apply (simp_all add: pure_true_conv)
proof -
  fix x::"8 word list"
  assume assm: "\<forall>i<length str. \<flat>\<^sub>punat.assn (str ! i) (x ! i)"
  have 1: "sep_is_pure_assn (\<Union>*xa\<in>{0..<length str}. \<upharpoonleft>unat.assn (str ! xa) (x ! xa))"
    apply (rule sep_is_pure_assn_imgI)
    by (simp add: unat.assn_def)

  have 2: "pure_part (\<Union>*xa\<in>{0..<length str}. \<upharpoonleft>unat.assn (str ! xa) (x ! xa))"
    apply (rule pure_sep_set_img_pure_partI)
     apply auto
    apply (simp add: unat.assn_def)
    using assm by (simp add: thin_dr_pure_asm)

  from 1 2 show "\<box> \<turnstile> (\<Union>*xa\<in>{0..<length str}. \<upharpoonleft>unat.assn (str ! xa) (x ! xa))"
    by (metis (mono_tags, lifting) pure_part_pure_eq sep_pureI)
qed

lemma arl_elem_assn_string_assnI:
  "arl_elem_assn unat.assn str (stri::(8 word, 'l::len2) array_list) **
   \<up>(4 < LENGTH('l)) \<turnstile> \<upharpoonleft>string_dr_assn str stri"
    unfolding string_dr_assn_eq arl_elem_assn_def'
    apply (sepE | find_sep)+
    subgoal unfolding LLVM_DS_List_Assn.list_assn_def
      apply simp
      apply (rule pure_entails_boxI sep_is_pure_assn_conjI | simp)+
      apply (rule sep_is_pure_assn_imgI)
      by (simp add: unat.assn_def)

    apply (auto dest: list_assn_pure_partD)[1]
    apply (simp add: dr_assn_pure_asm_prefix_def list_assn_pure_partD unat.assn_pure)
    done

lemma arl_elem_assn_update:
  assumes "i < length xs" and "i\<in>ex"
  shows
  "arl_elem_assn_ex A xs xsi arl ex ** \<upharpoonleft>A (xs ! i) (xsi ! i) \<turnstile>
   arl_elem_assn_ex A xs xsi arl (ex - {i})"
  unfolding arl_elem_assn_ex_def
  apply isep_extract_pure
  apply (isep_drule drule: LLVM_DS_List_Assn.list_assn_update[where i=i])
  using assms apply (auto simp: idxe_map_def dest: list_assn_pure_partD)
  apply sep
  done

lemma make_id_map_rec'_rule:
  "
  llvm_htriple
  (string_list_assn strs strsi ** \<upharpoonleft>snat.assn i ii)
  (make_id_map_rec' strsi ii)
  (\<lambda>mi. (EXS m. map.rbt_map_assn m mi **
                  string_list_assn strs strsi **
                  \<up>(is_id_bijection (drop i strs) m (list_id_map strs))))
"
proof(induction "length strs - i" arbitrary: i ii)
  case 0
  from 0 show ?case
    apply (subst make_id_map_rec'.simps)
    apply vcg
    apply vcg_compat
    apply (sepE | find_sep)+
    unfolding is_id_bijection_def
    by simp
next
  case (Suc x)
  note Suc(1)[vcg_rules]
  show ?case
    apply (subst make_id_map_rec'.simps)
    apply vcg
    subgoal using Suc(2) by simp
    subgoal
      apply vcg
      apply vcg_rl
       apply vcg_compat
       apply (isep_drule drule: string_assn_arl_elem_assnI)
       apply isep_extract_pure
       apply (isep_rule rule: sep_pureI, simp)
       apply (sepE | find_sep)+
      apply vcg_solve
      apply vcg_rl
       apply vcg_compat

       apply (isep_rule rule: arl_elem_assn_string_assnI)
       apply (isep_rule rule: pure_pure_asm_prefixI, simp)
       apply (sepEwith simp)
       apply simp

      apply vcg_solve
      apply vcg

      apply vcg_compat
      apply isep_intro_ex
      apply isep_assumption

      apply (isep_drule drule: arl_elem_assn_string_assnI)
        apply (sepEwith simp)
       apply isep_assumption

      apply (isep_drule drule: arl_elem_assn_update)
        apply simp_all
      apply (sepEwith simp)
      unfolding is_id_bijection_def list_id_map_def map_comp_def
      apply auto
      by (simp add: drop_Suc_nth)
    subgoal using Suc by simp (*unreachable*)
    done
qed

lemma make_id_map_loop'_rule:
  "
  llvm_htriple
  (string_list_assn strs strsi)
  (make_id_map_loop' strsi)
  (\<lambda>mi. (EXS m. map.rbt_map_assn m mi **
                  string_list_assn strs strsi **
                  \<up>(is_id_bijection strs m (list_id_map strs))))
  "
  unfolding make_id_map_loop'_def
  supply llc_for_range_rule[where I="make_id_map_loop'_inv strs strsi", vcg_rules]
  apply vcg
  apply vcg_rl
  (*precond*)
  unfolding make_id_map_loop'_inv_def
  apply vcg_try_solve
  apply vcg_compat
  unfolding is_id_bijection_def apply simp
    apply (sepEwith simp)
  subgoal for asf x r ra s ia iia si (*step*)
    apply vcg
      (*arl copy*)
    apply vcg_rl
     apply vcg_compat
     apply (isep_drule drule: string_assn_arl_elem_assnI)
     apply isep_extract_pure
     apply (isep_rule rule: sep_pureI, simp)
     apply (sepE | find_sep)+
    (*done*)
    apply vcg_solve
    (*insert*)
    apply vcg_rl
     apply vcg_compat
     apply (isep_rule rule: arl_elem_assn_string_assnI)
     apply (isep_rule rule: pure_pure_asm_prefixI, simp)
     apply (sepEwith simp)
    (*done*)
    apply vcg_solve
    apply vcg
        apply vcg_compat
      apply isep_intro_ex
      apply isep_assumption

      apply (isep_drule drule: arl_elem_assn_string_assnI)
        apply (sepEwith simp)
       apply isep_assumption

      apply (isep_drule drule: arl_elem_assn_update)
        apply simp_all
    apply (sep | find_sep)+
      unfolding is_id_bijection_def list_id_map_def map_comp_def
      apply (simp add: take_Suc_conv_app_nth)
      done
    subgoal (*post loop*) by vcg_solve+
    done

definition make_id_map_rec
  :: "stringi array_list_64 \<Rightarrow> ((stringi, 64 word) rbti \<times> stringi array_list_64) llM" where
  "make_id_map_rec strs =
  do {
    m \<leftarrow> make_id_map_rec' strs 0;
    return (m, strs)
  }"

definition make_id_map_loop
  :: "stringi array_list_64 \<Rightarrow> ((stringi, 64 word) rbti \<times> stringi array_list_64) llM" where
  "make_id_map_loop strs =
  do {
    m \<leftarrow> make_id_map_loop' strs;
    return (m, strs)
  }"

lemmas [llvm_code] = make_id_map_rec_def make_id_map_loop_def

lemma make_id_map_rec_rule:
  "
  llvm_htriple
  (string_list_assn strs strsi)
  (make_id_map_rec strsi)
  (\<lambda>(mi, li). EXS m l. map.rbt_map_assn m mi ** string_list_assn l li ** \<up>(is_id_bijection strs m (list_id_map l)))
"
  supply make_id_map_rec'_rule[vcg_rules]
  unfolding make_id_map_rec_def
  apply vcg
  done

lemma make_id_map_loop_rule:
  "
  llvm_htriple
  (string_list_assn strs strsi)
  (make_id_map_loop strsi)
  (\<lambda>(mi, li). (EXS m l. map.rbt_map_assn m mi ** string_list_assn l li ** \<up>(is_id_bijection strs m (list_id_map l))))
"
  supply make_id_map_loop'_rule[vcg_rules]
  unfolding make_id_map_loop_def
  apply vcg
  done

end


header {* \isaheader{Equivalence} *}

theory WEquivalence imports Semantics WCFG begin

subsection {* From @{term "prog \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"} to\\
  @{term "c \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"} with @{term transfers} and @{term preds} *}

lemma Skip_WCFG_edge_Exit:
  "\<lbrakk>labels prog l Skip\<rbrakk> \<Longrightarrow> prog \<turnstile> (_ l _) -\<Up>id\<rightarrow> (_Exit_)"
proof(induct prog l Skip rule:labels.induct)
  case Labels_Base
  show ?case by(fastforce intro:WCFG_Skip)
next
  case (Labels_LAss V e)
  show ?case by(rule WCFG_LAssSkip)
next
  case (Labels_Seq2 c\<^sub>2 l c\<^sub>1)
  from `c\<^sub>2 \<turnstile> (_ l _) -\<Up>id\<rightarrow> (_Exit_)`
  have "c\<^sub>1;;c\<^sub>2 \<turnstile> (_ l _) \<oplus> #:c\<^sub>1 -\<Up>id\<rightarrow> (_Exit_) \<oplus> #:c\<^sub>1"
    by(fastforce intro:WCFG_SeqSecond)
  thus ?case by(simp del:id_apply)
next
  case (Labels_CondTrue c\<^sub>1 l b c\<^sub>2)
  from `c\<^sub>1 \<turnstile> (_ l _) -\<Up>id\<rightarrow> (_Exit_)`
  have "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> (_ l _) \<oplus> 1 -\<Up>id\<rightarrow> (_Exit_) \<oplus> 1"
    by(fastforce intro:WCFG_CondThen)
  thus ?case by(simp del:id_apply)
next
  case (Labels_CondFalse c\<^sub>2 l b c\<^sub>1)
  from `c\<^sub>2 \<turnstile> (_ l _) -\<Up>id\<rightarrow> (_Exit_)`
  have "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> (_ l _) \<oplus> (#:c\<^sub>1 + 1) -\<Up>id\<rightarrow> (_Exit_) \<oplus> (#:c\<^sub>1 + 1)"
    by(fastforce intro:WCFG_CondElse)
  thus ?case by(simp del:id_apply)
next
  case (Labels_WhileExit b c')
  show ?case by(rule WCFG_WhileFalseSkip)
qed

lemma step_WCFG_edge:
  assumes "prog \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"
  obtains et where "prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)" and "transfer et s = s'"
  and "pred et s"
proof -
  from `prog \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>`
  have "\<exists>et. prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _) \<and> transfer et s = s' \<and> pred et s"
  proof(induct rule:step.induct)
    case (StepLAss V e s)
    have "pred \<Up>(\<lambda>s. s(V:=(interpret e s))) s" by simp
    have "V:=e \<turnstile> (_0_) -\<Up>(\<lambda>s. s(V:=(interpret e s)))\<rightarrow> (_1_)"
      by(rule WCFG_LAss)
    have "transfer \<Up>(\<lambda>s. s(V:=(interpret e s))) s = s(V:=(interpret e s))" by simp
    with `pred \<Up>(\<lambda>s. s(V:=(interpret e s))) s`
      `V:=e \<turnstile> (_0_) -\<Up>(\<lambda>s. s(V:=(interpret e s)))\<rightarrow> (_1_)` show ?case by blast
  next
    case (StepSeq c\<^sub>1 c\<^sub>2 l s)
    from `labels (c\<^sub>1;;c\<^sub>2) l (Skip;;c\<^sub>2)` `l < #:c\<^sub>1` have "labels c\<^sub>1 l Skip"
      by(auto elim:labels.cases intro:Labels_Base)
    hence "c\<^sub>1 \<turnstile> (_ l _) -\<Up>id\<rightarrow> (_Exit_)"
      by(fastforce intro:Skip_WCFG_edge_Exit)
    hence "c\<^sub>1;;c\<^sub>2 \<turnstile> (_ l _) -\<Up>id\<rightarrow> (_0_) \<oplus> #:c\<^sub>1"
      by(rule WCFG_SeqConnect,simp)
    thus ?case by auto
  next
    case (StepSeqWhile b cx l s)
    from `labels (while (b) cx) l (Skip;;while (b) cx)`
    obtain lx where "labels cx lx Skip"
      and [simp]:"l = lx + 2" by(auto elim:labels.cases)
    hence "cx \<turnstile> (_ lx _) -\<Up>id\<rightarrow> (_Exit_)"
      by(fastforce intro:Skip_WCFG_edge_Exit)
    hence "while (b) cx \<turnstile> (_ lx _) \<oplus> 2 -\<Up>id\<rightarrow> (_0_)"
      by(fastforce intro:WCFG_WhileBodyExit)
    thus ?case by auto
  next
    case (StepCondTrue b s c\<^sub>1 c\<^sub>2)
    from `interpret b s = Some true`
    have "pred (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s" by simp
    moreover
    have "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> (_0_) -(\<lambda>s. interpret b s = Some true)\<^sub>\<surd>\<rightarrow> (_0_) \<oplus> 1"
      by(rule WCFG_CondTrue)
    moreover
    have "transfer (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s = s" by simp
    ultimately show ?case by auto
  next
    case (StepCondFalse b s c\<^sub>1 c\<^sub>2)
    from `interpret b s = Some false`
    have "pred (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s" by simp
    moreover
    have "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> (_0_) -(\<lambda>s. interpret b s = Some false)\<^sub>\<surd>\<rightarrow>
                                   (_0_) \<oplus> (#:c\<^sub>1 + 1)"
      by(rule WCFG_CondFalse)
    moreover
    have "transfer (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s = s" by simp
    ultimately show ?case by auto
  next
    case (StepWhileTrue b s c)
    from `interpret b s = Some true`
    have "pred (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s" by simp
    moreover
    have "while (b) c \<turnstile> (_0_) -(\<lambda>s. interpret b s = Some true)\<^sub>\<surd>\<rightarrow> (_0_) \<oplus> 2"
      by(rule WCFG_WhileTrue)
    moreover
    have "transfer (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s = s" by simp
    ultimately show ?case by(auto simp del:add_2_eq_Suc')
  next
    case (StepWhileFalse b s c)
    from `interpret b s = Some false`
    have "pred (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s" by simp
    moreover
    have "while (b) c \<turnstile> (_0_) -(\<lambda>s. interpret b s = Some false)\<^sub>\<surd>\<rightarrow> (_1_)"
      by(rule WCFG_WhileFalse)
    moreover
    have "transfer (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s = s" by simp
    ultimately show ?case by auto
  next
    case (StepRecSeq1 prog c s l c' s' l' c\<^sub>2)
    from `\<exists>et. prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _) \<and> transfer et s = s' \<and> pred et s`
    obtain et where "prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"
      and "transfer et s = s'" and "pred et s" by blast
    moreover
    from `prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)` have "prog;;c\<^sub>2 \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"
      by(fastforce intro:WCFG_SeqFirst)
    ultimately show ?case by blast
  next
    case (StepRecSeq2 prog c s l c' s' l' c\<^sub>1)
    from `\<exists>et. prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _) \<and> transfer et s = s' \<and> pred et s`
    obtain et where "prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"
      and "transfer et s = s'" and "pred et s" by blast
    moreover
    from `prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)`
    have "c\<^sub>1;;prog \<turnstile> (_ l _) \<oplus> #:c\<^sub>1 -et\<rightarrow> (_ l' _) \<oplus> #:c\<^sub>1"
      by(fastforce intro:WCFG_SeqSecond)
    ultimately show ?case by simp blast
  next
    case (StepRecCond1 prog c s l c' s' l' b c\<^sub>2)
    from `\<exists>et. prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _) \<and> transfer et s = s' \<and> pred et s`
    obtain et where "prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"
      and "transfer et s = s'" and "pred et s" by blast
    moreover
    from `prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)`
    have "if (b) prog else c\<^sub>2 \<turnstile> (_ l _) \<oplus> 1 -et\<rightarrow> (_ l' _) \<oplus> 1"
      by(fastforce intro:WCFG_CondThen)
    ultimately show ?case by simp blast
  next
    case (StepRecCond2 prog c s l c' s' l' b c\<^sub>1)
    from `\<exists>et. prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _) \<and> transfer et s = s' \<and> pred et s`
    obtain et where "prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"
      and "transfer et s = s'" and "pred et s" by blast
    moreover
    from `prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)`
    have "if (b) c\<^sub>1 else prog \<turnstile> (_ l _) \<oplus> (#:c\<^sub>1 + 1) -et\<rightarrow> (_ l' _) \<oplus> (#:c\<^sub>1 + 1)"
      by(fastforce intro:WCFG_CondElse)
    ultimately show ?case by simp blast
  next
    case (StepRecWhile cx c s l c' s' l' b)
    from `\<exists>et. cx \<turnstile> (_ l _) -et\<rightarrow> (_ l' _) \<and> transfer et s = s' \<and> pred et s`
    obtain et where "cx \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"
      and "transfer et s = s'" and "pred et s" by blast
    moreover
    hence "while (b) cx \<turnstile> (_ l _) \<oplus> 2 -et\<rightarrow> (_ l' _) \<oplus> 2"
      by(fastforce intro:WCFG_WhileBody)
    ultimately show ?case by simp blast
  qed
  with that show ?thesis by blast
qed

subsection {* From @{term "c \<turnstile> (_ l _) -et\<rightarrow> (_ l' _)"} with @{term transfers}
  and @{term preds} to\\
  @{term "prog \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"} *}

(*<*)declare One_nat_def [simp del] add_2_eq_Suc' [simp del](*>*)

lemma WCFG_edge_Exit_Skip:
  "\<lbrakk>prog \<turnstile> n -et\<rightarrow> (_Exit_); n \<noteq> (_Entry_)\<rbrakk>
  \<Longrightarrow> \<exists>l. n = (_ l _) \<and> labels prog l Skip \<and> et = \<Up>id"
proof(induct prog n et "(_Exit_)" rule:WCFG_induct)
  case WCFG_Skip show ?case by(fastforce intro:Labels_Base)
next
  case WCFG_LAssSkip show ?case by(fastforce intro:Labels_LAss)
next
  case (WCFG_SeqSecond c\<^sub>2 n et n' c\<^sub>1)
  note IH = `\<lbrakk>n' = (_Exit_); n \<noteq> (_Entry_)\<rbrakk>
    \<Longrightarrow> \<exists>l. n = (_ l _) \<and> labels c\<^sub>2 l Skip \<and> et = \<Up>id`
  from `n' \<oplus> #:c\<^sub>1 = (_Exit_)` have "n' = (_Exit_)" by(cases n') auto
  from IH[OF this `n \<noteq> (_Entry_)`] obtain l where [simp]:"n = (_ l _)" "et = \<Up>id"
    and "labels c\<^sub>2 l Skip" by blast
  hence "labels (c\<^sub>1;;c\<^sub>2) (l + #:c\<^sub>1) Skip" by(fastforce intro:Labels_Seq2)
  thus ?case by(fastforce simp:id_def)
next
  case (WCFG_CondThen c\<^sub>1 n et n' b c\<^sub>2)
  note IH = `\<lbrakk>n' = (_Exit_); n \<noteq> (_Entry_)\<rbrakk>
    \<Longrightarrow> \<exists>l. n = (_ l _) \<and> labels c\<^sub>1 l Skip \<and> et = \<Up>id`
  from `n' \<oplus> 1 = (_Exit_)` have "n' = (_Exit_)" by(cases n') auto
  from IH[OF this `n \<noteq> (_Entry_)`] obtain l where [simp]:"n = (_ l _)" "et = \<Up>id"
    and "labels c\<^sub>1 l Skip" by blast
  hence "labels (if (b) c\<^sub>1 else c\<^sub>2) (l + 1) Skip"
    by(fastforce intro:Labels_CondTrue)
  thus ?case by(fastforce simp:id_def)
next
  case (WCFG_CondElse c\<^sub>2 n et n' b c\<^sub>1)
  note IH = `\<lbrakk>n' = (_Exit_); n \<noteq> (_Entry_)\<rbrakk>
    \<Longrightarrow> \<exists>l. n = (_ l _) \<and> labels c\<^sub>2 l Skip \<and> et = \<Up>id`
  from `n' \<oplus> #:c\<^sub>1 + 1 = (_Exit_)` have "n' = (_Exit_)" by(cases n') auto
  from IH[OF this `n \<noteq> (_Entry_)`] obtain l where [simp]:"n = (_ l _)" "et = \<Up>id"
    and label:"labels c\<^sub>2 l Skip" by blast
  hence "labels (if (b) c\<^sub>1 else c\<^sub>2) (l + #:c\<^sub>1 + 1) Skip"
    by(fastforce intro:Labels_CondFalse)
  thus ?case by(fastforce simp:add.assoc id_def)
next
  case WCFG_WhileFalseSkip show ?case by(fastforce intro:Labels_WhileExit)
next
  case (WCFG_WhileBody c' n et n' b) thus ?case by(cases n') auto
qed simp_all

lemma WCFG_edge_step:
  "\<lbrakk>prog \<turnstile> (_ l _) -et\<rightarrow> (_ l' _); transfer et s = s'; pred et s\<rbrakk>
  \<Longrightarrow> \<exists>c c'. prog \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle> \<and> labels prog l c \<and> labels prog l' c'"
proof(induct prog "(_ l _)" et "(_ l' _)" arbitrary:l l' rule:WCFG_induct)
  case (WCFG_LAss V e)
  from `transfer \<Up>\<lambda>s. s(V:=(interpret e s)) s = s'`
  have [simp]:"s' = s(V:=(interpret e s))" by(simp del:fun_upd_apply)
  have "labels (V:=e) 0 (V:=e)" by(fastforce intro:Labels_Base)
  moreover
  hence "labels (V:=e) 1 Skip" by(fastforce intro:Labels_LAss)
  ultimately show ?case
    apply(rule_tac x="V:=e" in exI)
    apply(rule_tac x="Skip" in exI)
    by(fastforce intro:StepLAss simp del:fun_upd_apply)
next
  case (WCFG_SeqFirst c\<^sub>1 et c\<^sub>2)
  note IH = `\<lbrakk>transfer et s = s'; pred et s\<rbrakk>
    \<Longrightarrow> \<exists>c c'. c\<^sub>1 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle> \<and> labels c\<^sub>1 l c \<and> labels c\<^sub>1 l' c'`
  from IH[OF `transfer et s = s'` `pred et s`]
  obtain c c' where "c\<^sub>1 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"
    and "labels c\<^sub>1 l c" and "labels c\<^sub>1 l' c'" by blast
  from `c\<^sub>1 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>` have "c\<^sub>1;;c\<^sub>2 \<turnstile> \<langle>c;;c\<^sub>2,s,l\<rangle> \<leadsto> \<langle>c';;c\<^sub>2,s',l'\<rangle>"
    by(rule StepRecSeq1)
  moreover
  from `labels c\<^sub>1 l c` have "labels (c\<^sub>1;;c\<^sub>2) l (c;;c\<^sub>2)"
    by(fastforce intro:Labels_Seq1)
  moreover
  from `labels c\<^sub>1 l' c'` have "labels (c\<^sub>1;;c\<^sub>2) l' (c';;c\<^sub>2)"
    by(fastforce intro:Labels_Seq1)
  ultimately show ?case by blast
next
  case (WCFG_SeqConnect c\<^sub>1 et c\<^sub>2)
  from `c\<^sub>1 \<turnstile> (_ l _) -et\<rightarrow> (_Exit_)`
  have "labels c\<^sub>1 l Skip" and [simp]:"et = \<Up>id"
    by(auto dest:WCFG_edge_Exit_Skip)
  from `transfer et s = s'` have [simp]:"s' = s" by simp
  have "labels c\<^sub>2 0 c\<^sub>2" by(fastforce intro:Labels_Base)
  hence "labels (c\<^sub>1;;c\<^sub>2) #:c\<^sub>1 c\<^sub>2" by(fastforce dest:Labels_Seq2)
  moreover
  from `labels c\<^sub>1 l Skip` have "labels (c\<^sub>1;;c\<^sub>2) l (Skip;;c\<^sub>2)"
    by(fastforce intro:Labels_Seq1)
  moreover
  from `labels c\<^sub>1 l Skip` have "l < #:c\<^sub>1" by(rule label_less_num_inner_nodes)
  ultimately
  have "c\<^sub>1;;c\<^sub>2 \<turnstile> \<langle>Skip;;c\<^sub>2,s,l\<rangle> \<leadsto> \<langle>c\<^sub>2,s,#:c\<^sub>1\<rangle>" by -(rule StepSeq)
  with `labels (c\<^sub>1;;c\<^sub>2) l (Skip;;c\<^sub>2)`
    `labels (c\<^sub>1;;c\<^sub>2) #:c\<^sub>1 c\<^sub>2` `(_0_) \<oplus> #:c\<^sub>1 = (_ l' _)` show ?case by simp blast
next
  case (WCFG_SeqSecond c\<^sub>2 n et n' c\<^sub>1)
  note IH = `\<And>l l'. \<lbrakk>n = (_ l _); n' = (_ l' _); transfer et s = s'; pred et s\<rbrakk>
    \<Longrightarrow> \<exists>c c'. c\<^sub>2 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle> \<and> labels c\<^sub>2 l c \<and> labels c\<^sub>2 l' c'`
  from `n \<oplus> #:c\<^sub>1 = (_ l _)` obtain lx where "n = (_ lx _)"
    and [simp]:"l = lx + #:c\<^sub>1"
    by(cases n) auto
  from `n' \<oplus> #:c\<^sub>1 = (_ l' _)` obtain lx' where "n' = (_ lx' _)"
    and [simp]:"l' = lx' + #:c\<^sub>1"
    by(cases n') auto
  from IH[OF `n = (_ lx _)` `n' = (_ lx' _)` `transfer et s = s'` `pred et s`]
  obtain c c' where "c\<^sub>2 \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>"
    and "labels c\<^sub>2 lx c" and "labels c\<^sub>2 lx' c'" by blast
  from `c\<^sub>2 \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>` have "c\<^sub>1;;c\<^sub>2 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"
    by(fastforce intro:StepRecSeq2)
  moreover
  from `labels c\<^sub>2 lx c` have "labels (c\<^sub>1;;c\<^sub>2) l c" by(fastforce intro:Labels_Seq2)
  moreover
  from `labels c\<^sub>2 lx' c'` have "labels (c\<^sub>1;;c\<^sub>2) l' c'" by(fastforce intro:Labels_Seq2)
  ultimately show ?case by blast
next
  case (WCFG_CondTrue b c\<^sub>1 c\<^sub>2)
  from `(_0_) \<oplus> 1 = (_ l' _)` have [simp]:"l' = 1" by simp
  from `transfer (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s = s'` have [simp]:"s' = s" by simp
  have "labels (if (b) c\<^sub>1 else c\<^sub>2) 0 (if (b) c\<^sub>1 else c\<^sub>2)"
    by(fastforce intro:Labels_Base)
  have "labels c\<^sub>1 0 c\<^sub>1" by(fastforce intro:Labels_Base)
  hence "labels (if (b) c\<^sub>1 else c\<^sub>2) 1 c\<^sub>1" by(fastforce dest:Labels_CondTrue)
  from `pred (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s`
  have "interpret b s = Some true" by simp
  hence "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> \<langle>if (b) c\<^sub>1 else c\<^sub>2,s,0\<rangle> \<leadsto> \<langle>c\<^sub>1,s,1\<rangle>"
    by(rule StepCondTrue)
  with  `labels (if (b) c\<^sub>1 else c\<^sub>2) 0 (if (b) c\<^sub>1 else c\<^sub>2)`
    `labels (if (b) c\<^sub>1 else c\<^sub>2) 1 c\<^sub>1` show ?case by simp blast
next
  case (WCFG_CondFalse b c\<^sub>1 c\<^sub>2)
  from `(_0_) \<oplus> #:c\<^sub>1 + 1 = (_ l' _)` have [simp]:"l' = #:c\<^sub>1 + 1" by simp
  from `transfer (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s = s'` have [simp]:"s' = s"
    by simp
  have "labels (if (b) c\<^sub>1 else c\<^sub>2) 0 (if (b) c\<^sub>1 else c\<^sub>2)"
    by(fastforce intro:Labels_Base)
  have "labels c\<^sub>2 0 c\<^sub>2" by(fastforce intro:Labels_Base)
  hence "labels (if (b) c\<^sub>1 else c\<^sub>2) (#:c\<^sub>1 + 1) c\<^sub>2" by(fastforce dest:Labels_CondFalse)
  from `pred (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s`
  have "interpret b s = Some false" by simp
  hence "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> \<langle>if (b) c\<^sub>1 else c\<^sub>2,s,0\<rangle> \<leadsto> \<langle>c\<^sub>2,s,#:c\<^sub>1 + 1\<rangle>"
    by(rule StepCondFalse)
  with `labels (if (b) c\<^sub>1 else c\<^sub>2) 0 (if (b) c\<^sub>1 else c\<^sub>2)`
    `labels (if (b) c\<^sub>1 else c\<^sub>2) (#:c\<^sub>1 + 1) c\<^sub>2` show ?case by simp blast
next
  case (WCFG_CondThen c\<^sub>1 n et n' b c\<^sub>2)
  note IH = `\<And>l l'. \<lbrakk>n = (_ l _); n' = (_ l' _); transfer et s = s'; pred et s\<rbrakk>
    \<Longrightarrow> \<exists>c c'. c\<^sub>1 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle> \<and> labels c\<^sub>1 l c \<and> labels c\<^sub>1 l' c'`
  from `n \<oplus> 1 = (_ l _)` obtain lx where "n = (_ lx _)" and [simp]:"l = lx + 1"
    by(cases n) auto
  from `n' \<oplus> 1 = (_ l' _)` obtain lx' where "n' = (_ lx' _)" and [simp]:"l' = lx' + 1"
    by(cases n') auto
  from IH[OF `n = (_ lx _)` `n' = (_ lx' _)` `transfer et s = s'` `pred et s`]
  obtain c c'  where "c\<^sub>1 \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>"
    and "labels c\<^sub>1 lx c" and "labels c\<^sub>1 lx' c'" by blast
  from `c\<^sub>1 \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>` have "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"
    by(fastforce intro:StepRecCond1)
  moreover
  from `labels c\<^sub>1 lx c` have "labels (if (b) c\<^sub>1 else c\<^sub>2) l c"
    by(fastforce intro:Labels_CondTrue)
  moreover
  from `labels c\<^sub>1 lx' c'` have "labels (if (b) c\<^sub>1 else c\<^sub>2) l' c'"
    by(fastforce intro:Labels_CondTrue)
  ultimately show ?case by blast
next
  case (WCFG_CondElse c\<^sub>2 n et n' b c\<^sub>1)
  note IH = `\<And>l l'. \<lbrakk>n = (_ l _); n' = (_ l' _); transfer et s = s'; pred et s\<rbrakk>
    \<Longrightarrow> \<exists>c c'. c\<^sub>2 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle> \<and> labels c\<^sub>2 l c \<and> labels c\<^sub>2 l' c'`
  from `n \<oplus> #:c\<^sub>1 + 1 = (_ l _)` obtain lx where "n = (_ lx _)"
    and [simp]:"l = lx + #:c\<^sub>1 + 1"
    by(cases n) auto
  from `n' \<oplus> #:c\<^sub>1 + 1 = (_ l' _)` obtain lx' where "n' = (_ lx' _)"
    and [simp]:"l' = lx' + #:c\<^sub>1 + 1"
    by(cases n') auto
  from IH[OF `n = (_ lx _)` `n' = (_ lx' _)` `transfer et s = s'` `pred et s`]
  obtain c c' where "c\<^sub>2 \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>"
    and "labels c\<^sub>2 lx c" and "labels c\<^sub>2 lx' c'" by blast
  from `c\<^sub>2 \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>` have "if (b) c\<^sub>1 else c\<^sub>2 \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle>"
    by(fastforce intro:StepRecCond2)
  moreover
  from `labels c\<^sub>2 lx c` have "labels (if (b) c\<^sub>1 else c\<^sub>2) l c"
    by(fastforce intro:Labels_CondFalse)
  moreover
  from `labels c\<^sub>2 lx' c'` have "labels (if (b) c\<^sub>1 else c\<^sub>2) l' c'"
    by(fastforce intro:Labels_CondFalse)
  ultimately show ?case by blast
next
  case (WCFG_WhileTrue b cx)
  from `(_0_) \<oplus> 2 = (_ l' _)` have [simp]:"l' = 2" by simp
  from `transfer (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s = s'` have [simp]:"s' = s" by simp
  have "labels (while (b) cx) 0 (while (b) cx)"
    by(fastforce intro:Labels_Base)
  have "labels cx 0 cx" by(fastforce intro:Labels_Base)
  hence "labels (while (b) cx) 2 (cx;;while (b) cx)"
    by(fastforce dest:Labels_WhileBody)
  from `pred (\<lambda>s. interpret b s = Some true)\<^sub>\<surd> s` have "interpret b s = Some true" by simp
  hence "while (b) cx \<turnstile> \<langle>while (b) cx,s,0\<rangle> \<leadsto> \<langle>cx;;while (b) cx,s,2\<rangle>"
    by(rule StepWhileTrue)
  with `labels (while (b) cx) 0 (while (b) cx)`
    `labels (while (b) cx) 2 (cx;;while (b) cx)` show ?case by simp blast
next
  case (WCFG_WhileFalse b cx)
  from `transfer (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s = s'` have [simp]:"s' = s"
    by simp
  have "labels (while (b) cx) 0 (while (b) cx)" by(fastforce intro:Labels_Base)
  have "labels (while (b) cx) 1 Skip" by(fastforce intro:Labels_WhileExit)
  from `pred (\<lambda>s. interpret b s = Some false)\<^sub>\<surd> s` have "interpret b s = Some false"
    by simp
  hence "while (b) cx \<turnstile> \<langle>while (b) cx,s,0\<rangle> \<leadsto> \<langle>Skip,s,1\<rangle>"
    by(rule StepWhileFalse)
  with `labels (while (b) cx) 0 (while (b) cx)` `labels (while (b) cx) 1 Skip`
  show ?case by simp blast
next
  case (WCFG_WhileBody cx n et n' b)
  note IH = `\<And>l l'. \<lbrakk>n = (_ l _); n' = (_ l' _); transfer et s = s'; pred et s\<rbrakk>
    \<Longrightarrow> \<exists>c c'. cx \<turnstile> \<langle>c,s,l\<rangle> \<leadsto> \<langle>c',s',l'\<rangle> \<and> labels cx l c \<and> labels cx l' c'`
  from `n \<oplus> 2 = (_ l _)` obtain lx where "n = (_ lx _)" and [simp]:"l = lx + 2"
    by(cases n) auto
  from `n' \<oplus> 2 = (_ l' _)` obtain lx' where "n' = (_ lx' _)"
    and [simp]:"l' = lx' + 2" by(cases n') auto
  from IH[OF `n = (_ lx _)` `n' = (_ lx' _)` `transfer et s = s'` `pred et s`]
  obtain c c' where "cx \<turnstile> \<langle>c,s,lx\<rangle> \<leadsto> \<langle>c',s',lx'\<rangle>"
    and "labels cx lx c" and "labels cx lx' c'" by blast
  hence "while (b) cx \<turnstile> \<langle>c;;while (b) cx,s,l\<rangle> \<leadsto> \<langle>c';;while (b) cx,s',l'\<rangle>"
    by(fastforce intro:StepRecWhile)
  moreover
  from `labels cx lx c` have "labels (while (b) cx) l (c;;while (b) cx)"
    by(fastforce intro:Labels_WhileBody)
  moreover
  from `labels cx lx' c'` have "labels (while (b) cx) l' (c';;while (b) cx)"
    by(fastforce intro:Labels_WhileBody)
  ultimately show ?case by blast
next
  case (WCFG_WhileBodyExit cx n et b)
  from `n \<oplus> 2 = (_ l _)` obtain lx where [simp]:"n = (_ lx _)" and [simp]:"l = lx + 2"
    by(cases n) auto
  from `cx \<turnstile> n -et\<rightarrow> (_Exit_)` have "labels cx lx Skip" and [simp]:"et = \<Up>id"
    by(auto dest:WCFG_edge_Exit_Skip)
  from `transfer et s = s'` have [simp]:"s' = s" by simp
  from `labels cx lx Skip` have "labels (while (b) cx) l (Skip;;while (b) cx)"
    by(fastforce intro:Labels_WhileBody)
  hence "while (b) cx \<turnstile> \<langle>Skip;;while (b) cx,s,l\<rangle> \<leadsto> \<langle>while (b) cx,s,0\<rangle>"
    by(rule StepSeqWhile)
  moreover
  have "labels (while (b) cx) 0 (while (b) cx)"
    by(fastforce intro:Labels_Base)
  ultimately show ?case
    using `labels (while (b) cx) l (Skip;;while (b) cx)` by simp blast
qed

end


theory Balance_Opt
  imports "../Balance"
begin

context rbt_impl
begin
interpretation rbt_impl_deps .

definition "rotate_left n_p \<equiv>
  do {
    r_p \<leftarrow> right n_p;
    rl_p \<leftarrow> left r_p;
    set_left_p n_p r_p;
    set_right_p rl_p n_p;
    return r_p
  }
"

definition "rotate_right n_p \<equiv>
  do {
    l_p \<leftarrow> left n_p;
    lr_p \<leftarrow> right l_p;
    set_right_p n_p l_p;
    set_left_p lr_p n_p;
    return l_p
  }
"

definition "balance_opt_case_1 n_p \<equiv>
  do {
    n \<leftarrow> ll_load n_p;
    set_color_p 0 n_p;
    set_color_p 1 (rbt_node.left n);
    set_color_p 1 (rbt_node.right n);
    return n_p
  }"

definition "balance_opt_case_2 n_p \<equiv>
  do {
    n2_p \<leftarrow> rotate_right n_p;
    l_p \<leftarrow> left n2_p;
    set_color_p 1 l_p;
    return n2_p
  }"

definition "balance_opt_case_3 n_p \<equiv>
  do {
    l_p \<leftarrow> left n_p;
    l2_p \<leftarrow> rotate_left l_p;
    set_left_p l2_p n_p;
    n2_p \<leftarrow> rotate_right n_p;
    set_color_p 1 l_p;
    return n2_p
  }"

definition "balance_opt_case_4 n_p \<equiv>
  do {
    n2_p \<leftarrow> rotate_left n_p;
    r_p \<leftarrow> right n2_p;
    set_color_p 1 r_p;
    return n2_p
  }"

definition "balance_opt_case_5 n_p \<equiv>
  do {
    r_p \<leftarrow> right n_p;
    r2_p \<leftarrow> rotate_right r_p;
    set_right_p r2_p n_p;
    n2_p \<leftarrow> rotate_left n_p;
    set_color_p 1 r_p;
    return n2_p
  }"

definition "balance_opt n_p \<equiv>
  do {
    if! ll_matches_rbt
        (RP_Branch CP_Var
          (RP_Branch CP_R RP_Var RP_Var)
          (RP_Branch CP_R RP_Var RP_Var)
        ) n_p
    then! balance_opt_case_1 n_p
    else!
    do {
      n \<leftarrow> ll_load n_p;
      l_p \<leftarrow> return rbt_node.left n;
      r_p \<leftarrow> return rbt_node.right n;
      if! ll_matches_rbt
        (RP_Branch CP_R (RP_Branch CP_R RP_Var RP_Var) RP_Var) l_p
      then! balance_opt_case_2 n_p
      else! if! ll_matches_rbt
        (RP_Branch CP_R RP_Var (RP_Branch CP_R RP_Var RP_Var)) l_p
      then! balance_opt_case_3 n_p
      else! if! ll_matches_rbt
        (RP_Branch CP_R RP_Var (RP_Branch CP_R RP_Var RP_Var)) r_p
      then! balance_opt_case_4 n_p
      else! if! ll_matches_rbt
        (RP_Branch CP_R (RP_Branch CP_R RP_Var RP_Var) RP_Var) r_p
      then! balance_opt_case_5 n_p
      else! return n_p
    }
  }
"

lemmas [llvm_inline] =
    balance_opt_case_1_def
    balance_opt_case_2_def
    balance_opt_case_3_def
    balance_opt_case_4_def
    balance_opt_case_5_def
    rotate_left_def
    rotate_right_def

lemmas [llvm_code] = balance_opt_def

lemma balance_opt_correct [vcg_rules]:
  "llvm_htriple
  (
    \<upharpoonleft>ll_bpto (RBT_NODE ci li ki vi ri) n_p **
    rbt_assn l li **
    rbt_assn r ri **
    \<upharpoonleft>key_assn k ki **
    \<upharpoonleft>value_assn v vi **
    color_assn color.B ci
  )
  (balance_opt n_p)
  (\<lambda>res. rbt_assn (rbt_balance l k v r) res)
  "
  unfolding
    balance_opt_def
    balance_opt_case_1_def
    balance_opt_case_2_def
    balance_opt_case_3_def
    balance_opt_case_4_def
    balance_opt_case_5_def
    rotate_left_def
    rotate_right_def

  apply vcg
  subgoal (*Case 1*)
    apply (cases "(l, k, v, r)" rule: RBT_Impl.balance.cases)
                        apply auto
    apply vcg
    done
  subgoal (*Case 2+*)
    apply vcg
    subgoal (*Case 3*)
      apply (cases "(l, k, v, r)" rule: RBT_Impl.balance.cases)
                          apply auto
       apply vcg
      done
    subgoal (*Case 4+*)
      apply vcg
      subgoal (*Case 4*)
        apply (cases "(l, k, v, r)" rule: RBT_Impl.balance.cases)
                            apply auto
           apply vcg
        done
      subgoal (*Case 5+*)
        apply vcg
        subgoal (*Case 5*)
          apply (cases "(l, k, v, r)" rule: RBT_Impl.balance.cases)
                              apply auto
           apply vcg
          done
        subgoal (*Case 6*)
          apply (cases "(l, k, v, r)" rule: RBT_Impl.balance.cases)
                              apply auto
                              apply vcg
          done
        done
      done
    done
  done

end

end


(*  Title:      HOL/Auth/n_germanSimp.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSimp Protocol Case Study*}

theory n_germanSimp imports n_germanSimp_lemma_invs_on_rules n_germanSimp_on_inis
begin
lemma main:
assumes a1: "s \<in> reachableSet {andList (allInitSpecs N)} (rules N)"
and a2: "0 < N"
shows "\<forall> f. f \<in> (invariants N) --> formEval f s"
proof (rule consistentLemma)
show "consistent (invariants N) {andList (allInitSpecs N)} (rules N)"
proof (cut_tac a1, unfold consistent_def, rule conjI)
show "\<forall> f ini s. f \<in> (invariants N) --> ini \<in> {andList (allInitSpecs N)} --> formEval ini s --> formEval f s"
proof ((rule allI)+, (rule impI)+)
  fix f ini s
  assume b1: "f \<in> (invariants N)" and b2: "ini \<in> {andList (allInitSpecs N)}" and b3: "formEval ini s"
  have b4: "formEval (andList (allInitSpecs N)) s"
  apply (cut_tac b2 b3, simp) done
  show "formEval f s"
  apply (rule on_inis, cut_tac b1, assumption, cut_tac b2, assumption, cut_tac b3, assumption) done
qed
next show "\<forall> f r s. f \<in> invariants N --> r \<in> rules N --> invHoldForRule s f r (invariants N)"
proof ((rule allI)+, (rule impI)+)
  fix f r s
  assume b1: "f \<in> invariants N" and b2: "r \<in> rules N"
  show "invHoldForRule s f r (invariants N)"
  apply (rule invs_on_rules, cut_tac b1, assumption, cut_tac b2, assumption) done
qed
qed
next show "s \<in> reachableSet {andList (allInitSpecs N)} (rules N)"
  apply (metis a1) done
qed
end


           (*-------------------------------------------*
            |        CSP-Prover on Isabelle2004         |
            |                    May 2005               |
            |                   June 2005  (modified)   |
            |              September 2005  (modified)   |
            |                                           |
            |        CSP-Prover on Isabelle2005         |
            |               November 2005  (modified)   |
            |                  March 2007  (modified)   |
            |                                           |
            |        CSP-Prover on Isabelle2017         |
            |                  April 2018  (modified)   |
            |                                           |
            |        Yoshinao Isobe (AIST JAPAN)        |
            *-------------------------------------------*)

theory CSP_F_law_rep_par
imports CSP_F_law_alpha_par CSP_F_op_rep_par CSP_T.CSP_T_law_rep_par
begin

(*  The following simplification rules are deleted in this theory file *)
(*  because they unexpectly rewrite UnionT and InterT.                 *)
(*                  Union (B ` A) = (UN x:A. B x)                      *)
(*                  Inter (B ` A) = (INT x:A. B x)                     *)
(*
declare Union_image_eq [simp del]
declare Inter_image_eq [simp del]
*)
(* no simp rules in Isabelle 2017
declare Sup_image_eq [simp del]
declare Inf_image_eq [simp del]
*)

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

         1. associativity of [||]:I
         2. commutativity of [||]:I
         3.
         4.

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

(*****************************************************
   replace an index set with another equal index set
 *****************************************************)

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

lemma cspF_Rep_parallel_index_eq_lm1:
   "[| inj_on f I1 ; ALL i:I1. PXf2 (f i) = PXf1 i |] ==>
    Union {(Yf i Int insert Tick (Ev ` snd (PXf1 i))) |i. i : I1} =
    Union {(Yf (inv_on I1 f i) Int insert Tick (Ev ` snd (PXf2 i))) |i. i : f ` I1}"
apply (rule)

 (* => *)
 apply (rule, simp)
 apply (elim conjE exE)
 apply (rule_tac x="(Yf i) Int insert Tick (Ev ` snd (PXf2 (f i)))" in exI)
 apply (simp)
 apply (rule_tac x="f i" in exI)
 apply (simp add: inv_f_f_on)

 (* <= *)
 apply (rule, simp)
 apply (simp add: image_iff)
 apply (elim conjE exE bexE)
 apply (rule_tac x=
   "(Yf xb) Int insert Tick (Ev ` snd (PXf1 xb))" in exI)
 apply (simp)
 apply (simp add: inv_f_f_on)
 apply (rule_tac x="xb" in exI)
 apply (simp)
done

lemma cspF_Rep_parallel_index_eq_lm2:
   "ALL i:I1. PXf2 (f i) = PXf1 i ==>
    Union {(Yf i Int insert Tick (Ev ` snd (PXf2 i))) |i. i : f ` I1} =
    Union {(Yf (f i) Int insert Tick (Ev ` snd (PXf1 i))) |i. i : I1}"
apply (rule)

 (* => *)
 apply (rule, simp)
 apply (simp add: image_iff)
 apply (elim conjE exE bexE)
 apply (simp)
 apply (rule_tac x="xa" in exI)
 apply (simp)
 apply (rule_tac x="xb" in exI)
 apply (simp)

 (* <= *)
 apply (rule, simp)
 apply (elim conjE exE)
 apply (rule_tac x="xa" in exI)
 apply (simp)
 apply (rule_tac x="f i" in exI)
 apply (simp)
done

(* main *)

lemma cspF_Rep_parallel_index_eq:
   "[| finite I1 ;
       EX f. I2 = f ` I1 & inj_on f I1 &
             (ALL i:I1. PXf2 (f i) = PXf1 i) |]
     ==> [||]:I1 PXf1 =F[M,M] [||]:I2 PXf2"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_parallel_index_eq)
apply (case_tac "I1 = {}", simp)
apply (rule order_antisym)

 (* <= *)
 apply (rule)
 apply (elim conjE exE)
 apply (simp add: in_failures_Rep_parallel)
 apply (subgoal_tac "Union (snd ` PXf2 ` f ` I1) = Union (snd ` PXf1 ` I1)")
 apply (simp)
 apply (elim conjE exE)
 apply (rule_tac x="(%i. Yf (inv_on I1 f i))" in exI)
 apply (simp add: inv_f_f_on)
 apply (simp add: cspF_Rep_parallel_index_eq_lm1)
 apply (simp add: Union_index_fun)

 (* => *)
 apply (rule)
 apply (elim conjE exE)
 apply (simp add: in_failures_Rep_parallel)
 apply (subgoal_tac "Union (snd ` PXf2 ` f ` I1) = Union (snd ` PXf1 ` I1)")
 apply (simp)
 apply (elim conjE exE)
 apply (rule_tac x="(%i. Yf (f i))" in exI)
 apply (simp)
 apply (simp add: cspF_Rep_parallel_index_eq_lm2)
 apply (simp add: Union_index_fun)
done

(*********************************************************
                [||]:I PXf ==> [||] PXs
 *********************************************************)

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

lemma cspF_Index_to_Inductive_parallel:
  "[| finite I ; Is isListOf I |] ==>
   [||]:I PXf =F[M,M] [||] (map PXf Is)"
apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Index_to_Inductive_parallel)
apply (case_tac "I = {}", simp)

apply (case_tac "map PXf Is = []")
apply (simp)
apply (rule order_antisym)

 (* <= *)
 apply (rule)
 apply (simp add: in_failures_Rep_parallel)
 apply (simp add: in_failures_Inductive_parallel_nth)
 apply (simp add: isListOf_set_eq)
 apply (elim conjE exE)
  apply (rule_tac x= "map Yf Is" in exI)
  apply (simp)
  apply (rule conjI)
  apply (rule in_failures_Rep_parallel_lm2, simp)
  apply (intro allI impI)
  apply (drule_tac x="Is ! i" in bspec)
  apply (simp add: isListOf_nth_in_index)
  apply (simp)

 (* => *)
 apply (rule)
 apply (simp add: in_failures_Rep_parallel)
 apply (simp add: in_failures_Inductive_parallel_nth)
 apply (simp add: isListOf_set_eq)
 apply (elim conjE exE)
 apply (rule_tac x= "(%i. (Ys!(THE n. (Is!n) = i & n<length Is)))" in exI)
  apply (rule conjI)
  apply (simp add: in_failures_Rep_parallel_lm1)
  apply (rule ballI)

  apply (erule isListOf_index_to_nthE)
  apply (drule_tac x="i" in bspec, simp)
  apply (elim conjE exE, simp)

  apply (drule_tac x="n" in spec, simp)
  apply (rotate_tac 4)
  apply (drule sym)
  apply (simp add: isListOf_THE_nth)
done

(************************************
 |       [||]:I PXf and SKIP        |
 ************************************)

lemma cspF_SKIP_Rep_parallel_right_lm1:
  "I ~= {} ==>
   insert Tick (Union {(Yf i Int insert Tick (Ev ` snd (PXf i))) |i. i : I})
   = Union {(insert Tick (Yf i Int Ev ` snd (PXf i))) |i. i : I}"
by (auto)

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

lemma cspF_SKIP_Rep_parallel_right:
  "finite I ==>
   (([||]:I PXf) |[Union (snd `  PXf ` I), {}]| SKIP) =F[M,M]
   ([||]:I PXf)"
apply (case_tac "I={}")
apply (simp add: cspF_SKIP_Alpha_parallel)

  apply (simp add: cspF_cspT_semantics)
(* Isabelle 2017 *)
apply (simp add: cspT_SKIP_Rep_parallel_right[simplified])
apply (rule order_antisym)

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

  apply (case_tac "Tick ~: Z")
  apply (simp)
  apply (rule_tac x="Yf" in exI)
  apply (rule conjI)
  apply (subgoal_tac "Z Int {Tick} = {}")
  apply (simp (no_asm_simp))
  apply (simp)

  apply (intro ballI)
  apply (drule_tac x="i" in bspec, simp)
  apply (subgoal_tac " snd (PXf i) <= Union (snd ` PXf ` I)")
  apply (simp add: rest_tr_of_rest_tr_subset)
  apply (force)

  apply (simp add: in_failures)
  apply (erule disjE)
  apply (simp add: Evset_def)
  apply (force)

  apply (rule_tac x="(%i. insert Tick (Yf i))" in exI)
  apply (simp)
  apply (subgoal_tac "Z Int {Tick} = {Tick}", simp)
  apply (simp add: cspF_SKIP_Rep_parallel_right_lm1)

  apply (intro ballI)
  apply (drule_tac x="i" in bspec, simp)
  apply (subgoal_tac " snd (PXf i) <= Union (snd ` PXf ` I)")
  apply (simp add: rest_tr_of_rest_tr_subset)

  apply (simp add: rest_tr_Tick_sett)
  apply (elim conjE exE)
  apply (simp)
  apply (rule proc_T2_T3)
  apply (simp)
  apply (simp)
  apply (force)
  apply (force)

(* <= *)
 apply (rule)
 apply (simp add: in_failures_Alpha_parallel)
 apply (rule_tac x="X" in exI)
 apply (rule_tac x="{}" in exI)
 apply (simp)

 apply (simp add: in_failures)
 apply (simp add: rest_tr_empty)
 apply (simp add: in_failures_Rep_parallel)
 apply (elim conjE exE)
 apply (rule_tac x="Yf" in exI)
 apply (simp)
 apply (intro ballI)
 apply (drule_tac x="i" in bspec, simp)

 apply (subgoal_tac " snd (PXf i) <= Union (snd ` PXf ` I)")
 apply (simp add: rest_tr_of_rest_tr_subset)
 apply (force)
done

(************************************
 |        SKIP and [||]:I PXf       |
 ************************************)

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

lemma cspF_SKIP_Rep_parallel_left:
  "finite I ==>
   (SKIP |[{}, Union (snd ` PXf ` I)]| ([||]:I PXf)) =F[M,M]
   ([||]:I PXf)"
apply (subgoal_tac
    "(SKIP |[{}, Union (snd ` PXf ` I)]| ([||]:I PXf)) =F[M,M]
     (([||]:I PXf) |[Union (snd ` PXf ` I), {}]| SKIP)")
apply (rule cspF_trans)
    apply (simp)
(* Isabelle 2017 *)
apply (simp add: cspF_SKIP_Rep_parallel_right[simplified])
apply (simp add: cspF_Alpha_parallel_commut)
done

(*** left and right ***)

lemmas cspF_SKIP_Rep_parallel = cspF_SKIP_Rep_parallel_left
                                  cspF_SKIP_Rep_parallel_right

(************************************
 |          associativity           |
 ************************************)

lemma cspF_Rep_parallel_ass_lm1:
   "Union {(Yf i Int insert Tick (Ev ` snd (PXf i))) |i. i : I} Int
           insert Tick (Ev ` Union (snd ` PXf ` I))
    = Union {(Yf i Int insert Tick (Ev ` snd (PXf i))) |i. i : I}"
by (auto)

lemma cspF_Rep_parallel_ass_lm2:
   "I1 Int I2 = {} ==>
    Union {(Yf1 i Int insert Tick (Ev ` snd (PXf i))) |i. i : I1} Un
    Union {(Yf2 i Int insert Tick (Ev ` snd (PXf i))) |i. i : I2} =
    Union {(if i : I1 then Yf1 i else Yf2 i) Int insert Tick (Ev ` snd (PXf i)) |i.
           i : I1 | i : I2}"
apply (rule)

 apply (rule)
 apply (simp)
 apply (elim disjE conjE exE)

  apply (rule_tac x="Yf1 i Int insert Tick (Ev ` snd (PXf i))" in exI, simp)
  apply (rule_tac x="i" in exI, simp)
  apply (rule_tac x="Yf2 i Int insert Tick (Ev ` snd (PXf i))" in exI, simp)
  apply (rule_tac x="i" in exI, simp)
  apply (force)

 apply (rule)
 apply (simp)
 apply (elim disjE conjE exE)

  apply (rule disjI1)
  apply (rule_tac x="Yf1 i Int insert Tick (Ev ` snd (PXf i))" in exI, simp)
  apply (rule_tac x="i" in exI, simp)
  apply (rule disjI2)
  apply (case_tac "i ~: I1")
  apply (rule_tac x="Yf2 i Int insert Tick (Ev ` snd (PXf i))" in exI, simp)
  apply (rule_tac x="i" in exI, simp)
  apply (force)
done

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

lemma cspF_Rep_parallel_assoc:
 "[| I1 Int I2 = {} ; finite I1 ; finite I2 |] ==>
  [||]:(I1 Un I2) PXf =F[M,M]
  [||]:I1 PXf |[Union (snd ` PXf ` I1), Union (snd ` PXf ` I2)]| [||]:I2 PXf"

apply (case_tac "I1 = {}")
apply (case_tac "I2 = {}")
apply (rule cspF_sym)
apply (simp add: cspF_SKIP_Alpha_parallel)
   apply (rule cspF_sym)
(* Isabellle 2017 *)
apply (simp add: cspF_SKIP_Rep_parallel[simplified])

apply (case_tac "I2 = {}")
   apply (rule cspF_sym)
(* Isabelle2017 *)
apply (simp add: cspF_SKIP_Rep_parallel[simplified])

apply (simp add: cspF_cspT_semantics)
apply (simp add: cspT_Rep_parallel_assoc[simplified])
apply (rule order_antisym)

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

 apply (rule_tac x="Union {(Yf i Int insert Tick (Ev ` snd (PXf i))) |i. i : I1}" in exI)
 apply (rule_tac x="Union {(Yf i Int insert Tick (Ev ` snd (PXf i))) |i. i : I2}" in exI)
 apply (simp add: Union_snd_Un)
 apply (rule conjI)
  apply (simp add: cspF_Rep_parallel_ass_lm1[simplified])
  apply (blast)

 apply (rule conjI)

  (* I1 *)
  apply (rule_tac x="Yf" in exI)
  apply (simp add: cspF_Rep_parallel_ass_lm1[simplified])

  apply (intro ballI)
  apply (drule_tac x="i" in bspec, simp)
  apply (subgoal_tac "snd (PXf i) <= Union (snd ` PXf ` I1)")
  apply (simp add: rest_tr_of_rest_tr_subset)
  apply (force)

  (* I2 *)
  apply (rule_tac x="Yf" in exI)
  apply (simp add: cspF_Rep_parallel_ass_lm1[simplified])

  apply (intro ballI)
  apply (drule_tac x="i" in bspec, simp)
  apply (subgoal_tac "snd (PXf i) <= Union (snd ` PXf ` I2)")
  apply (simp add: rest_tr_of_rest_tr_subset)
  apply (force)

 (* <= *)
 apply (rule)
 apply (simp add: in_failures_Alpha_parallel)
 apply (simp add: in_failures_Rep_parallel)
 apply (elim exE conjE)
 apply (simp add: Union_snd_Un)
 apply (rename_tac s X Y Z Yf1 Yf2)

 apply (rule_tac x="(%i. if i:I1 then Yf1 i else Yf2 i)" in exI)
       (* the necessity of the condition "I1 Int I2 = {}" *)
 apply (simp add: cspF_Rep_parallel_ass_lm2)

 apply (intro ballI)
 apply (simp)
 apply (erule disjE)

  apply (drule_tac x="i" in bspec, simp, simp)
  apply (subgoal_tac "snd (PXf i) <= Union (snd ` PXf ` I1)")
  apply (simp add: rest_tr_of_rest_tr_subset)
  apply (force)

  apply (drule_tac x="i" in bspec, simp)
  apply (case_tac "i ~: I1")
  apply (subgoal_tac "snd (PXf i) <= Union (snd ` PXf ` I2)")
  apply (simp add: rest_tr_of_rest_tr_subset)
  apply (force)
  apply (blast)
done

(************************************
 |             induct               |
 ************************************)

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

lemma cspF_Rep_parallel_induct:
 "[| finite I ; i ~: I |] ==>
  [||]:(insert i I) PXf =F[M,M]
  fst (PXf i) |[snd (PXf i), Union (snd ` PXf ` I)]| [||]:I PXf"
apply (insert cspF_Rep_parallel_assoc[of "{i}" I PXf M])
apply (simp add: Rep_parallel_one)
apply (rule cspF_rw_left)
apply (simp)

apply (insert cspF_Alpha_parallel_assoc
  [of "fst (PXf i)" "snd (PXf i)" "{}" "SKIP" "Union (snd ` PXf ` I)" "[||]:I PXf" M])
apply (rule cspF_trans)
apply (simp)

apply (rule cspF_decompo_Alpha_parallel)
apply (simp_all)
(* Isabelle 2017 *)
apply (simp add: cspF_SKIP_Rep_parallel[simplified])
done

(****************** to add them again ******************)
(*
declare Union_image_eq [simp]
declare Inter_image_eq [simp]
*)
(*
declare Sup_image_eq [simp]
declare Inf_image_eq [simp]
*)
end