theory WTLemma
  imports GenSubEnv WellTypedExp PermEnvMisc AltNormEnv
begin

    (*
      ####################################
        P2. general well-typed lemmas
      ####################################
    *)

lemma well_typed_perm_leq: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> leq_use_env r_s2 r_s1"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
      apply (rule_tac r_sb="diff_use_env r_s1 (comp_use_env (ereq_use_env (owner_name x) tau_x) r_ex)" in trans_leq_use_env)
       apply (rule_tac self_diff_leq_use_env)
      apply (simp)
     apply (rule_tac r_sb="diff_use_env r_s3 r_ex" in trans_leq_use_env)
      apply (rule_tac diff_leq_use_env)
      apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
       apply (auto)
    apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
     apply (auto)
   apply (rule_tac r_sb="diff_use_env r_s1 r_ex" in trans_leq_use_env)
    apply (rule_tac self_diff_leq_use_env)
   apply (simp)
  apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
   apply (auto)
  apply (rule_tac r_sb="r_s3" in trans_leq_use_env)
   apply (auto)
  apply (rule_tac r_sb="diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)" in trans_leq_use_env)
   apply (rule_tac self_diff_leq_use_env)
  apply (simp)
  done

lemma well_typed_perm_leqx: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> leq_use_env rx r_s2"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
       apply (auto)
    (* if case *)
  apply (rule_tac dist_comp_leq_use_env)
   apply (auto)
  done

lemma well_typed_spec_perm_leq: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> leq_perm (r_s2 x) (r_s1 x)"
  apply (cut_tac ?r_s2.0="r_s2" and ?r_s1.0="r_s1" in well_typed_perm_leq)
   apply (auto)
  apply (simp add: leq_use_env_def)
  done

    (*
      ####################################
        P3. well-typed free var lemmas
      ####################################
    *)

lemma well_typed_fv_env_use: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<in> free_vars e \<rbrakk> \<Longrightarrow> env (Var x) \<noteq> None"
  (*apply (simp add: env_gen_use_def)*)
  apply (induction e arbitrary: env tau r_s1 r_s2 rx)
        apply (auto)
   apply (case_tac xa)
    apply (auto)
  apply (case_tac "\<exists> y. add_env env (Var x1a) t1 (Var x) = Some y")
   apply (simp add: add_env_def)
  apply (auto)
  done

lemma well_typed_rv_env_use: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<in> ref_vars e \<rbrakk> \<Longrightarrow> env (Loc x) \<noteq> None"
  (*apply (simp add: env_gen_use_def)*)
  apply (induction e arbitrary: env tau r_s1 r_s2 rx)
        apply (auto)
   apply (case_tac xa)
    apply (auto)
  apply (case_tac "\<exists> y. add_env env (Var x1a) t1 (Loc x) = Some y")
   apply (simp add: add_env_def)
   apply (auto)
  done

lemma well_typed_no_npv_use: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; r_s1 x = NoPerm \<rbrakk> \<Longrightarrow> x \<notin> non_prim_vars env e"
  apply (induction e arbitrary: env r_s1 tau r_s2 rx)
       apply (auto)
    (* const + op case *)
        apply (simp add: non_prim_vars_def)
       apply (simp add: non_prim_vars_def)
    (* var case. *)
      apply (cut_tac r_x="ereq_use_env (owner_name xa) tau_x" and r_s="r_s1" in leq_use_none)
        apply (auto)
      apply (case_tac "x \<noteq> owner_name xa")
       apply (simp add: non_prim_vars_def)
       apply (case_tac xa)
        apply (auto)
      apply (cut_tac x="x" and tau="tau_x" in ereq_use_none)
       apply (auto)
      apply (simp add: non_prim_vars_def)
      apply (simp add: non_prim_entry_def)
    (* pair case 1 *)
     apply (case_tac "x \<notin> res_vars (PairExp e1 e2)")
      apply (simp add: non_prim_vars_def)
     apply (auto)
      apply (simp add: non_prim_vars_def)
    (* pair case 2 *)
     apply (cut_tac r_x="r_s2a" and r_s="r_s1" and x="x" in leq_use_none)
       apply (rule_tac well_typed_perm_leq)
       apply (auto)
     apply (simp add: non_prim_vars_def)
    (* if case 1 *)
    apply (case_tac "x \<notin> res_vars (IfExp e1 e2 e3)")
     apply (simp add: non_prim_vars_def)
    apply (auto)
      apply (case_tac "x \<notin> non_prim_vars env e1")
      apply (simp add: non_prim_vars_def)
      apply (auto)
    (* if case 2 *)
     apply (cut_tac r_x="r_s2a" and r_s="r_s1" and x="x" in leq_use_none)
       apply (rule_tac well_typed_perm_leq)
       apply (auto)
     apply (case_tac "x \<notin> non_prim_vars env e2")
      apply (simp add: non_prim_vars_def)
     apply (auto)
    (* if case 3 *)
     apply (cut_tac r_x="r_s2a" and r_s="r_s1" and x="x" in leq_use_none)
       apply (rule_tac well_typed_perm_leq)
       apply (auto)
    apply (case_tac "x \<notin> non_prim_vars env e3")
     apply (simp add: non_prim_vars_def)
    apply (auto)
    (* lambda case *)
    apply (case_tac "x \<noteq> Var x1a")
     apply (auto)
    apply (cut_tac r_x="rxa" and r_s="r_s1" and x="x" in leq_use_none)
      apply (auto)
    apply (cut_tac r_s="rxa" and y="Var x1a" and r="r" and x="x" in add_use_none_rev)
      apply (auto)
    apply (case_tac "x \<notin> non_prim_vars (add_env env (Var x1a) t1) e")
     apply (simp add: non_prim_vars_def)
    apply (case_tac "\<not> non_prim_entry (add_env env (Var x1a) t1) x")
      apply (simp add: non_prim_entry_def)
      apply (simp add: add_env_def)
      apply (auto)
   apply (simp add: non_prim_vars_def)
    (* app case 1 *)
  apply (case_tac "x \<notin> res_vars (AppExp e1 e2)")
   apply (simp add: non_prim_vars_def)
  apply (auto)
   apply (case_tac "x \<notin> non_prim_vars env e1")
    apply (simp add: non_prim_vars_def)
   apply (auto)
    (* app case 2 *)
  apply (cut_tac r_x="r_s2a" and r_s="r_s1" and x="x" in leq_use_none)
    apply (rule_tac well_typed_perm_leq)
    apply (auto)
  apply (case_tac "x \<notin> non_prim_vars env e2")
   apply (simp add: non_prim_vars_def)
  apply (auto)
  done

lemma well_typed_aff_fv_own: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<in> res_vars e; env x = Some t; req_type t = Aff \<rbrakk> \<Longrightarrow> r_s1 x = OwnPerm"
  apply (induction e arbitrary: env r_s1 tau r_s2 rx)
       apply (auto)
    (* var case *)
       apply (case_tac xa)
        apply (auto)
       apply (case_tac "ereq_use_env x t x \<noteq> OwnPerm")
        apply (simp add: ereq_use_env_def)
        apply (simp add: end_req_perm_def)
        apply (simp add: one_use_env_def)
       apply (cut_tac r_x="ereq_use_env x t" and r_s="r_s1" and x="x" in leq_use_own)
         apply (auto)
    (* pair case 2 *)
      apply (rule_tac r_x="r_s2a" in leq_use_own)
       apply (auto)
      apply (rule_tac well_typed_perm_leq)
      apply (auto)
    (* if case 2 *)
     apply (rule_tac r_x="r_s2a" in leq_use_own)
      apply (auto)
     apply (rule_tac e="e1" in well_typed_perm_leq)
     apply (auto)
    (* if case 3 *)
    apply (rule_tac r_x="r_s2a" in leq_use_own)
     apply (auto)
    apply (rule_tac e="e1" in well_typed_perm_leq)
    apply (auto)
    (* lambda case *)
   apply (rule_tac r_x="rxa" in leq_use_own)
    apply (auto)
   apply (case_tac "\<not> add_use_env rxa (Var x1a) r x = OwnPerm")
    apply (auto)
    apply (case_tac "\<not> add_env env (Var x1a) t1 x = Some t")
     apply (simp add: add_env_def)
    apply (auto)
   apply (simp add: add_use_env_def)
    (* app case *)
  apply (rule_tac r_x = "r_s2a" in leq_use_own)
   apply (auto)
  apply (rule_tac e="e1" in well_typed_perm_leq)
  apply (auto)
  done

    (*
      ####################################
        P4. well-typed manipulation for type environments
      ####################################
    *)

lemma well_typed_add_vars: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<notin> free_vars e \<rbrakk> \<Longrightarrow> well_typed (add_env env (Var x) t) r_s1 e tau r_s2 rx"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* var case *)
        apply (simp add: add_env_def)
        apply (case_tac xa)
         apply (auto)
       apply (simp add: add_env_def)
       apply (case_tac xa)
        apply (auto)
    (* pair case *)
      apply (rule_tac x="r_s2a" in exI)
      apply (rule_tac x="r_s3" in exI)
      apply (rule_tac x="rx1" in exI)
      apply (auto)
      apply (rule_tac x="rx2" in exI)
      apply (auto)
    (* if case *)
     apply (rule_tac x="rx'" in exI)
     apply (rule_tac x="r_s2a" in exI)
     apply (auto)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
    (* lambda case 1 *)
    apply (rule_tac x="rxa" in exI)
    apply (auto)
    apply (rule_tac x="r_end" in exI)
    apply (rule_tac x="r_s'" in exI)
    apply (case_tac "x = x1a")
     apply (cut_tac env="env" and x="Var x" and t="t" and t'="t1" in double_add_env)
     apply (auto)
    apply (cut_tac env="env" and x="Var x1a" and y="Var x" and t="t" and t'="t1" in almost_comm_add_env)
     apply (auto)
    (* lambda case 2 *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_end" in exI)
   apply (rule_tac x="r_s'" in exI)
   apply (cut_tac env="env" and x="Var x" and t="t" and t'="t1" in double_add_env)
   apply (auto)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  done

lemma well_typed_rem_vars: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<notin> free_vars e \<rbrakk> \<Longrightarrow> well_typed (rem_env env (Var x)) r_s1 e tau r_s2 rx"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* var case *)
        apply (simp add: rem_env_def)
        apply (case_tac xa)
         apply (auto)
       apply (simp add: rem_env_def)
       apply (case_tac xa)
        apply (auto)
    (* pair case *)
      apply (rule_tac x="r_s2a" in exI)
      apply (rule_tac x="r_s3" in exI)
      apply (rule_tac x="rx1" in exI)
      apply (auto)
      apply (rule_tac x="rx2" in exI)
      apply (auto)
    (* if case *)
     apply (rule_tac x="rx'" in exI)
     apply (rule_tac x="r_s2a" in exI)
     apply (auto)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
    (* lambda case 1 *)
    apply (rule_tac x="rxa" in exI)
    apply (auto)
    apply (rule_tac x="r_end" in exI)
    apply (rule_tac x="r_s'" in exI)
    apply (case_tac "x = x1a")
     apply (cut_tac env="env" and x="Var x" and t="t1" in partial_add_rem_env)
    apply (auto)
    apply (cut_tac env="env" and x="Var x" and y="Var x1a" and t="t1" in almost_comm_add_rem_env)
     apply (auto)
    (* lambda case 2 *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_end" in exI)
   apply (rule_tac x="r_s'" in exI)
   apply (cut_tac env="env" and x="Var x" and t="t1" in partial_add_rem_env)
   apply (auto)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  done

lemma well_typed_add_vars2: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<notin> ref_vars e \<rbrakk> \<Longrightarrow> well_typed (add_env env (Loc x) t) r_s1 e tau r_s2 rx"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* var case *)
        apply (simp add: add_env_def)
        apply (case_tac xa)
         apply (auto)
       apply (simp add: add_env_def)
       apply (case_tac xa)
        apply (auto)
    (* pair case *)
      apply (rule_tac x="r_s2a" in exI)
      apply (rule_tac x="r_s3" in exI)
      apply (rule_tac x="rx1" in exI)
      apply (auto)
      apply (rule_tac x="rx2" in exI)
      apply (auto)
    (* if case *)
     apply (rule_tac x="rx'" in exI)
     apply (rule_tac x="r_s2a" in exI)
     apply (auto)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
    (* lambda case *)
    apply (rule_tac x="rxa" in exI)
    apply (auto)
    apply (rule_tac x="r_end" in exI)
    apply (rule_tac x="r_s'" in exI)
    apply (cut_tac env="env" and x="Var x1a" and y="Loc x" and t="t" and t'="t1" in almost_comm_add_env)
     apply (auto)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  done

lemma well_typed_add_vars_rev: "\<lbrakk> well_typed (add_env env (Var x) t) r_s1 e tau r_s2 rx; x \<notin> free_vars e \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_s2 rx"
  apply (cut_tac env="add_env env (Var x) t" and ?r_s1.0="r_s1" and e="e" and tau="tau" and ?r_s2.0="r_s2" and rx="rx" and x="x" in well_typed_rem_vars)
    apply (auto)
  apply (case_tac "env (Var x) = None")
   apply (auto)
   apply (cut_tac env="env" and x="Var x" and t="t" in cancel_rem_add_env)
    apply (auto)
  apply (rule_tac t="well_typed env r_s1 e tau r_s2 rx" and s="well_typed (add_env (rem_env env (Var x)) (Var x) y) r_s1 e tau r_s2 rx" in subst)
   apply (cut_tac env="env" and x="Var x" and y="y" in cancel_add_rem_env)
    apply (auto)
  apply (rule_tac well_typed_add_vars)
   apply (cut_tac env="env" and x="Var x" and y="t" in partial_rem_add_env)
   apply (auto)
  done

lemma well_typed_contain_env: "\<lbrakk> contain_env env env'; well_typed env' r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_s2 rx"
  apply (induct e arbitrary: env env' r_s1 tau r_s2 rx)
        apply (auto)
    (* var case *)
       apply (simp add: contain_env_def)
       apply (erule_tac x="res_name x" in allE)
       apply (auto)
      apply (simp add: contain_env_def)
      apply (erule_tac x="owner_name x" in allE)
      apply (auto)
    (* pair case *)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="r_s2a" in exI)
    apply (auto)
    apply (rule_tac x="rx1" in exI)
    apply (auto)
    apply (rule_tac x="rx2" in exI)
    apply (auto)
    (* lam case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_end" in exI)
   apply (rule_tac x="r_s'" in exI)
   apply (cut_tac r_s="env" and r_x="env'" and x="Var x1a" and t="t1" in dist_add_contain_env)
    apply (auto)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  done

    (*
      ####################################
        P5. well-typed manipulation for start permissions
      ####################################
    *)

lemma well_typed_comp_start_perm: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> well_typed env (comp_use_env r_s1 r_ex) e tau r_s2 rx"
  apply (induction e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* const, op, var case 1 *)
         apply (rule_tac comp_leq_use_env1)
         apply (simp)
        apply (rule_tac comp_leq_use_env1)
        apply (simp)
       apply (rule_tac comp_leq_use_env1)
       apply (simp)
    (* var case 2 *)
      apply (rule_tac x="r_exa" in exI)
      apply (auto)
       apply (rule_tac r_sb="diff_use_env r_s1 (comp_use_env (ereq_use_env (owner_name x) tau_x) r_exa)" in trans_leq_use_env)
        apply (rule_tac dist_diff_leq_use_env)
        apply (rule_tac self_comp_leq_use_env1)
       apply (auto)
      apply (rule_tac comp_leq_use_env1)
      apply (simp)
    (* pair case *)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
     apply (rule_tac x="r_exa" in exI)
     apply (auto)
     apply (rule_tac comp_leq_use_env1)
     apply (simp)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="r_s2a" in exI)
    apply (auto)
    (* lambda case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
    apply (rule_tac r_sb="r_s1" in trans_leq_use_env)
     apply (rule_tac comp_leq_use_env1)
     apply (rule_tac id_leq_use_env)
    apply (simp)
   apply (rule_tac x="r_exa" in exI)
   apply (auto)
    apply (rule_tac r_sb="diff_use_env r_s1 r_exa" in trans_leq_use_env)
     apply (rule_tac dist_diff_leq_use_env)
     apply (rule_tac self_comp_leq_use_env1)
    apply (simp)
   apply (rule_tac comp_leq_use_env1)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  apply (rule_tac x="r_exa" in exI)
  apply (auto)
  apply (rule_tac comp_leq_use_env1)
  apply (simp)
  done

lemma well_typed_comp_start_perm2: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> well_typed env (comp_use_env r_ex r_s1) e tau r_s2 rx"
  apply (cut_tac r_s="r_ex" and r_x="r_s1" in comm_comp_use_env)
  apply (auto)
  apply (rule_tac well_typed_comp_start_perm)
  apply (auto)
  done

lemma well_typed_incr_start_perm: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env r_s1 r_c \<rbrakk> \<Longrightarrow> well_typed env r_c e tau r_s2 rx"
  apply (cut_tac r_s="r_c" and r_x="r_s1" in cancel_comp_use_env2)
   apply (auto)
  apply (cut_tac env="env" and ?r_s1.0="r_s1" and r_ex="r_c" and e="e" and tau="tau" and ?r_s2.0="r_s2" and rx="rx" in well_typed_comp_start_perm2)
   apply (auto)
  done

    (*
      ####################################
        P6. well-typed manipulation for sweeping changes
      ####################################
    *)

    (* - diff perm lemmas *)

lemma wtdp_start_perm_req: "\<lbrakk> y \<notin> own_env_vars r_x; leq_use_env (req_use_env y tau) r_s1 \<rbrakk>
       \<Longrightarrow> leq_use_env (req_use_env y tau) (diff_use_env r_s1 r_x)"
  apply (rule_tac r_s="r_s1" in req_leq_use_env)
   apply (simp)
  apply (cut_tac r_s="r_s1" and x="y" and r_x="r_x" in diff_use_eq)
   apply (auto)
  apply (simp add: own_env_vars_def)
  done

lemma weak_diff_req_use_env: "weak_use_env (diff_use_env (req_use_env x tau) (req_use_env x tau))"
  apply (simp add: diff_use_env_def)
  apply (simp add: weak_use_env_def)
  apply (auto)
  apply (case_tac "req_use_env x tau xa")
    apply (auto)
  done

lemma wtdp_disj_req_use_env2: "\<lbrakk> r_x x \<noteq> OwnPerm \<rbrakk> \<Longrightarrow> disj_use_env r_x (diff_use_env (req_use_env x tau) (req_use_env x tau))"
  apply (cut_tac x="x" and tau="tau" in weak_diff_req_use_env)
  apply (simp add: disj_use_env_def)
  apply (auto)
   apply (simp add: mini_disj_use_env_def)
   apply (auto)
   apply (rule_tac r_s="req_use_env x tau" in leq_use_none)
    apply (rule_tac self_diff_leq_use_env)
   apply (rule_tac req_use_none_alt)
   apply (auto)
  apply (simp add: mini_disj_use_env_def)
  apply (auto)
  apply (simp add: weak_use_env_def)
  done

lemma wtdp_end_req: "\<lbrakk> non_prim_vars env e \<inter> own_env_vars r_x = {}; x \<in> res_vars e; env x = Some tau;
  r_x x = OwnPerm \<rbrakk> \<Longrightarrow> end_req_perm tau = NoPerm"
  apply (case_tac "x \<in> non_prim_vars env e")
   apply (simp add: own_env_vars_def)
   apply (auto)
  apply (case_tac "req_type tau \<noteq> Prim")
   apply (simp add: non_prim_vars_def)
   apply (simp add: non_prim_entry_def)
  apply (simp add: end_req_perm_def)
  done

lemma well_typed_diff_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; non_prim_vars env e \<inter> own_env_vars r_x = {} \<rbrakk> \<Longrightarrow>
  well_typed env (diff_use_env r_s1 r_x) e tau (diff_use_env r_s2 r_x) (diff_use_env rx r_x)"
  apply (induction e arbitrary: env r_s1 tau r_s2 rx r_x)
       apply (auto)
    (* const case *)
          apply (rule_tac dist_diff_leq_use_env)
          apply (simp)
         apply (rule_tac dist_diff_leq_use_env)
         apply (simp)
    (* op case *)
        apply (rule_tac dist_diff_leq_use_env)
        apply (simp)
       apply (rule_tac dist_diff_leq_use_env)
       apply (simp)
    (* var case p1. manipulation to show that x1a exists in r_s2 *)
      apply (rule_tac mini_disj_diff_leq_use_env2)
       apply (simp)
      apply (simp add: ereq_use_env_def)
      apply (simp add: mini_disj_use_env_def)
      apply (simp add: one_use_env_def)
      apply (auto)
      apply (rule_tac env="env" and e="VarExp x" and r_x="r_x" and x="owner_name x" in wtdp_end_req)
          apply (auto)
       apply (case_tac x)
        apply (auto)
    (* var case p2 *)
     apply (rule_tac x="diff_use_env r_ex r_x" in exI)
     apply (auto)
        apply (rule_tac rhs_fold_dcl_use_env)
        apply (rule_tac rhs_flip_use_env)
        apply (rule_tac rhs_pull_comp_use_env)
        apply (cut_tac r_ex="r_ex" and r_x="r_x" in sum_comp_diff_use_env)
        apply (auto)
        apply (rule_tac rhs_unroll_dcl_use_env)
        apply (rule_tac rhs_unroll_dcl_use_env)
        apply (rule_tac dist_diff_leq_use_env)
        apply (rule_tac rhs_fold_dcl_use_env)
        apply (simp)
       apply (rule_tac dist_diff_leq_use_env)
       apply (simp)
      apply (rule_tac dist_diff_leq_use_env)
      apply (simp)
    (* - use disjointess of r_x from (req x tau) to remove - r_x *)
     apply (rule_tac disj_diff_leq_use_env)
      apply (simp add: ereq_use_env_def)
      apply (simp add: disj_use_env_def)
      apply (auto)
       apply (rule_tac one_mini_disj_use_env1)
       apply (auto)
       apply (rule_tac env="env" and e="VarExp x" and r_x="r_x" and x="owner_name x" in wtdp_end_req)
           apply (auto)
        apply (case_tac x)
         apply (auto)
      apply (rule_tac one_mini_disj_use_env2)
      apply (auto)
      apply (simp add: comp_use_env_def)
      apply (simp add: one_use_env_def)
    (* - through a slightly more involved process we can also remove it from the left *)
     apply (rule_tac lhs_unroll_dcl_use_env)
     apply (rule_tac r_sb="diff_use_env (diff_use_env (ereq_use_env (owner_name x) tau_x) (ereq_use_env (owner_name x) tau_x)) r_ex" in trans_leq_use_env)
       apply (rule_tac lhs_fold_dcl_use_env)
       apply (simp)
      apply (rule_tac lhs_ddl_use_env)
      apply (rule_tac comm_disj_use_env)
      apply (simp add: ereq_use_env_def)
      apply (simp add: disj_use_env_def)
      apply (auto)
       apply (rule_tac one_mini_disj_use_env1)
       apply (auto)
       apply (rule_tac env="env" and e="VarExp x" and r_x="r_x" and x="owner_name x" in wtdp_end_req)
          apply (auto)
       apply (case_tac x)
        apply (auto)
     apply (rule_tac one_mini_disj_use_env2)
     apply (auto)
      apply (simp add: one_use_env_def)
    (* pair case *)
     apply (rule_tac x="diff_use_env r_s2a r_x" in exI)
     apply (rule_tac x="diff_use_env r_s3 r_x" in exI)
     apply (rule_tac x="diff_use_env rx1 r_x" in exI)
     apply (auto)
      apply (case_tac "\<not> non_prim_vars env e1 \<inter> own_env_vars r_x = {}")
       apply (simp add: non_prim_vars_def)
       apply (auto)
     apply (rule_tac x="diff_use_env rx2 r_x" in exI)
     apply (auto)
           apply (case_tac "\<not> non_prim_vars env e2 \<inter> own_env_vars r_x = {}")
            apply (simp add: non_prim_vars_def)
            apply (auto)
          (*apply (rule_tac aff_diff_use_env)
          apply (simp)*)
          apply (rule_tac t="lift_use_env (diff_use_env rx1 r_x) r" and s="diff_use_env (lift_use_env rx1 r) r_x" in subst)
           apply (rule_tac lift_diff_use_env)
          apply (rule_tac dist_diff_leq_use_env)
          apply (simp)
         apply (rule_tac t="lift_use_env (diff_use_env rx2 r_x) r" and s="diff_use_env (lift_use_env rx2 r) r_x" in subst)
          apply (rule_tac lift_diff_use_env)
         apply (rule_tac dist_diff_leq_use_env)
         apply (simp)
      apply (rule_tac r_s="lift_use_env rx1 r" in disj_leq_use_env1)
       apply (rule_tac r_s="lift_use_env rx2 r" in disj_leq_use_env2)
        apply (simp)
       apply (rule_tac dist_lift_leq_use_env)
       apply (rule_tac self_diff_leq_use_env)
      apply (rule_tac dist_lift_leq_use_env)
      apply (rule_tac self_diff_leq_use_env)
     apply (rule_tac x="diff_use_env r_ex r_x" in exI)
     apply (auto)
        apply (rule_tac t="diff_use_env (diff_use_env r_s3 r_x) (diff_use_env r_ex r_x)" and s="diff_use_env (diff_use_env r_s3 r_ex) r_x" in subst)
         apply (rule_tac dist_sq_diff_use_env)
        apply (rule_tac dist_diff_leq_use_env)
        apply (simp)
       apply (rule_tac dist_diff_leq_use_env)
       apply (simp)
      apply (rule_tac dist_diff_leq_use_env)
      apply (simp)
     apply (case_tac "req_type (PairTy t1 t2 r) = Prim")
      apply (simp add: pair_req_def)
      apply (auto)
      apply (rule_tac leq_empty_use_env)
     apply (simp add: pair_req_def)
     apply (rule_tac t="lift_use_env (diff_use_env rx1 r_x) r" and s="diff_use_env (lift_use_env rx1 r) r_x" in subst)
      apply (rule_tac lift_diff_use_env)
     apply (rule_tac t="lift_use_env (diff_use_env rx2 r_x) r" and s="diff_use_env (lift_use_env rx2 r) r_x" in subst)
      apply (rule_tac lift_diff_use_env)
     apply (simp add: dist_diff_comp_use_env)
     apply (rule_tac t="diff_use_env (diff_use_env (comp_use_env (lift_use_env rx1 r) (lift_use_env rx2 r)) r_x)
        (diff_use_env r_ex r_x)" and s="diff_use_env (diff_use_env (comp_use_env (lift_use_env rx1 r) (lift_use_env rx2 r)) r_ex) r_x" in subst)
      apply (rule_tac dist_sq_diff_use_env)
     apply (rule_tac dist_diff_leq_use_env)
     apply (simp)
    (* if case *)
    apply (rule_tac x="diff_use_env rx' r_x" in exI)
    apply (rule_tac x="diff_use_env r_s2a r_x" in exI)
    apply (auto)
     apply (case_tac "\<not> non_prim_vars env e1 \<inter> own_env_vars r_x = {}")
      apply (simp add: non_prim_vars_def)
      apply (auto)
    apply (rule_tac x="diff_use_env rx1 r_x" in exI)
    apply (auto)
     apply (case_tac "\<not> non_prim_vars env e2 \<inter> own_env_vars r_x = {}")
      apply (simp add: non_prim_vars_def)
      apply (auto)
    apply (rule_tac x="diff_use_env rx2 r_x" in exI)
    apply (auto)
     apply (case_tac "\<not> non_prim_vars env e3 \<inter> own_env_vars r_x = {}")
      apply (simp add: non_prim_vars_def)
      apply (auto)
    apply (simp add: dist_diff_comp_use_env)
    (* lambda case *)
   apply (rule_tac x="diff_use_env rxa r_x" in exI)
   apply (auto)
      apply (rule_tac x="diff_use_env r_end (rem_use_env r_x (Var x1a))" in exI)
      apply (rule_tac x="diff_use_env r_s' (rem_use_env r_x (Var x1a))" in exI)
      apply (cut_tac r_s="rxa" and x="Var x1a" and r="r" and r_x="r_x" in diff_add_rem_use_env)
      apply (auto)
      apply (case_tac "\<not> non_prim_vars (add_env env (Var x1a) t1) e \<inter> own_env_vars (rem_use_env r_x (Var x1a)) = {}")
       apply (auto)
      apply (simp add: rem_use_env_def)
      apply (simp add: own_env_vars_def)
      apply (case_tac "x = Var x1a")
       apply (auto)
      apply (simp add: non_prim_vars_def)
      apply (simp add: non_prim_entry_def)
      apply (simp add: add_env_def)
      apply (auto)
     apply (rule_tac aff_diff_use_env)
     apply (simp)
    apply (rule_tac dist_diff_leq_use_env)
    apply (simp)
   apply (rule_tac x="diff_use_env r_ex r_x" in exI)
   apply (auto)
    (* - proving bounds *)
      apply (rule_tac t="diff_use_env (diff_use_env r_s1 r_x) (diff_use_env r_ex r_x)" and s="diff_use_env (diff_use_env r_s1 r_ex) r_x" in subst)
       apply (cut_tac r_s="r_s1" and r_x="r_ex" and r_ex="r_x" in dist_sq_diff_use_env)
       apply (auto)
      apply (rule_tac dist_diff_leq_use_env)
      apply (simp)
     apply (rule_tac dist_diff_leq_use_env)
     apply (simp)
    apply (rule_tac dist_diff_leq_use_env)
    apply (simp)
   apply (rule_tac t="diff_use_env (diff_use_env rxa r_x) (diff_use_env r_ex r_x)" and s="diff_use_env (diff_use_env rxa r_ex) r_x" in subst)
    apply (cut_tac r_s="rxa" and r_x="r_ex" and r_ex="r_x" in dist_sq_diff_use_env)
    apply (auto)
   apply (rule_tac dist_diff_leq_use_env)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="diff_use_env r_s2a r_x" in exI)
  apply (rule_tac x="diff_use_env rx1 r_x" in exI)
  apply (auto)
   apply (case_tac "\<not> non_prim_vars env e1 \<inter> own_env_vars r_x = {}")
    apply (simp add: non_prim_vars_def)
    apply (auto)
  apply (rule_tac x="diff_use_env rx2 r_x" in exI)
  apply (rule_tac x="diff_use_env r_s3 r_x" in exI)
  apply (auto)
   apply (case_tac "\<not> non_prim_vars env e2 \<inter> own_env_vars r_x = {}")
    apply (simp add: non_prim_vars_def)
    apply (auto)
    (* - reusable substitutions *)
  apply (case_tac "\<not> lift_use_env (diff_use_env rx2 r_x) r = diff_use_env (lift_use_env rx2 r) r_x")
   apply (cut_tac r_s="rx2" and r="r" and r_x="r_x" in lift_diff_use_env)
   apply (simp)
    (* - last instantiation *)
  apply (rule_tac x="diff_use_env r_ex r_x" in exI)
  apply (auto)
    (* - prove the bound for r_s2 *)
        apply (rule_tac rhs_fold_dcl_use_env)
        apply (rule_tac rhs_flip_use_env)
        apply (rule_tac rhs_unroll_dcl_use_env)
        apply (rule_tac rhs_diff_leq_use_env)
        apply (rule_tac r_sb="diff_use_env (diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)) r_x" in trans_leq_use_env)
         apply (rule_tac lhs_fold_dcl_use_env)
         apply (rule_tac lhs_flip_use_env)
         apply (rule_tac lhs_unroll_dcl_use_env)
         apply (rule_tac unroll_dcl_use_env)
         apply (rule_tac dist_diff_leq_use_env_gen)
          apply (rule_tac dist_diff_leq_use_env_gen)
           apply (rule_tac self_diff_leq_use_env)
          apply (rule_tac dist_comp_leq_use_env)
           apply (rule_tac comp_leq_use_env1)
           apply (rule_tac self_diff_leq_use_env)
          apply (rule_tac comp_leq_use_env2)
          apply (rule_tac self_diff_leq_use_env)
         apply (rule_tac self_diff_leq_use_env)
        apply (rule_tac dist_diff_leq_use_env)
        apply (simp)
    (* - prove lift safety *)
    (* - prove rx1 + rx2 is subtractable *)
      apply (rule_tac r_sb="diff_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_x" in trans_leq_use_env)
       apply (rule_tac dist_diff_leq_use_env)
       apply (simp)
      apply (rule_tac dist_comp_leq_use_env)
       apply (rule_tac dist_diff_leq_use_env)
       apply (rule_tac self_comp_leq_use_env1)
      apply (rule_tac dist_diff_leq_use_env)
      apply (rule_tac self_comp_leq_use_env2)
    (* - prove disjointedness *)
     apply (rule_tac r_s="rx1" in disj_leq_use_env1)
      apply (rule_tac r_s="lift_use_env rx2 r" in disj_leq_use_env2)
       apply (simp)
      apply (rule_tac self_diff_leq_use_env)
     apply (rule_tac self_diff_leq_use_env)
    apply (rule_tac dist_diff_leq_use_env)
    apply (simp)
    (* - prove r_ex bound *)
   apply (rule_tac dist_diff_leq_use_env)
   apply (simp)
    (* - prove the bound for rx *)
  apply (simp add: app_req_def)
  apply (auto)
   apply (rule_tac leq_empty_use_env)
  apply (rule_tac t="comp_use_env (diff_use_env rx1 r_x) (diff_use_env rx2 r_x)" and s="diff_use_env (comp_use_env rx1 rx2) r_x" in subst)
   apply (simp add: dist_diff_comp_use_env)
  apply (rule_tac t="comp_use_env (diff_use_env rx1 r_x) (diff_use_env (lift_use_env rx2 r) r_x)" and
      s="diff_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_x" in subst)
   apply (simp add: dist_diff_comp_use_env)
  apply (rule_tac t="comp_use_env (diff_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_x) (diff_use_env r_ex r_x)" and
      s="diff_use_env (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex) r_x" in subst)
   apply (simp add: dist_diff_comp_use_env)
  apply (rule_tac t="diff_use_env (diff_use_env (comp_use_env rx1 rx2) r_x) (diff_use_env (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex) r_x)" and
      s="diff_use_env (diff_use_env (comp_use_env rx1 rx2) (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)) r_x" in subst)
   apply (rule_tac dist_sq_diff_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (simp)
  done

lemma well_typed_disj_diff_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; mini_disj_use_env r_ex r_s1 \<rbrakk> \<Longrightarrow>
  well_typed env (diff_use_env r_s1 r_ex) e tau (diff_use_env r_s2 r_ex) (diff_use_env rx r_ex)"
  apply (rule_tac well_typed_diff_perms)
   apply (simp)
  apply (auto)
  apply (case_tac "r_s1 x = NoPerm")
   apply (cut_tac env="env" and ?r_s1.0="r_s1" and x="x" in well_typed_no_npv_use)
     apply (auto)
  apply (simp add: own_env_vars_def)
  apply (simp add: mini_disj_use_env_def)
  done

lemma well_typed_rem_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<notin> non_prim_vars env e \<rbrakk> \<Longrightarrow>
  well_typed env (rem_use_env r_s1 x) e tau (rem_use_env r_s2 x) (rem_use_env rx x)"
  apply (cut_tac r_s="r_s1" and x="x" in diff_rem_use_env)
  apply (cut_tac r_s="r_s2" and x="x" in diff_rem_use_env)
  apply (cut_tac r_s="rx" and x="x" in diff_rem_use_env)
  apply (auto)
  apply (rule_tac well_typed_diff_perms)
   apply (auto)
  apply (simp add: one_use_env_def)
  apply (simp add: own_env_vars_def)
  apply (case_tac "x = xa")
   apply (auto)
  done

lemma well_typed_add_perms_rev: "\<lbrakk> well_typed env (add_use_env r_s1 x r) e tau (add_use_env r_s2 x r') (add_use_env rx x r3);
  r_s1 x = NoPerm; r_s2 x = NoPerm; rx x = NoPerm; x \<notin> non_prim_vars env e \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_s2 rx"
  apply (cut_tac r_s="r_s1" and x="x" and r="r" in cancel_rem_add_use_env)
   apply (auto)
  apply (cut_tac r_s="r_s2" and x="x" and r="r'" in cancel_rem_add_use_env)
   apply (auto)
  apply (cut_tac r_s="rx" and x="x" and r="r3" in cancel_rem_add_use_env)
   apply (auto)
  apply (cut_tac env="env" and ?r_s1.0="add_use_env r_s1 x r" and e="e" and tau="tau" and ?r_s2.0="add_use_env r_s2 x r'" and rx="add_use_env rx x r3" and x="x" in well_typed_rem_perms)
    apply (auto)
  done

lemma wtapr_ex: "\<lbrakk>leq_use_env rxa (add_use_env r_s1 x r);
     leq_use_env r_s2 (diff_use_env (add_use_env r_s1 x r) r_ex); leq_use_env rx r_s2; leq_use_env r_ex (add_use_env r_s1 x r);
     leq_use_env (diff_use_env rxa r_ex) rx\<rbrakk>
    \<Longrightarrow> \<exists>r_ex. leq_use_env (rem_use_env r_s2 x) (diff_use_env r_s1 r_ex) \<and>
               leq_use_env (rem_use_env rx x) (rem_use_env r_s2 x) \<and>
               leq_use_env r_ex r_s1 \<and> leq_use_env (diff_use_env (rem_use_env rxa x) r_ex) (rem_use_env rx x)"
  apply (rule_tac x="rem_use_env r_ex x" in exI)
  apply (auto)
     apply (rule_tac r="r" in rem_add_leq_use_env)
     apply (rule_tac r_sb="add_use_env (diff_use_env r_s1 r_ex) x r" in trans_leq_use_env)
      apply (rule_tac dist_add_leq_use_env)
      apply (rule_tac dist_diff_leq_use_env_gen)
       apply (rule_tac id_leq_use_env)
      apply (rule_tac self_rem_leq_use_env)
     apply (rule_tac r_sb="diff_use_env (add_use_env r_s1 x r) r_ex" in trans_leq_use_env)
      apply (rule_tac add_diff_leq_use_env)
     apply (simp)
    apply (rule_tac dist_rem_leq_use_env)
    apply (simp)
   apply (rule_tac r="r" in rem_add_leq_use_env)
   apply (simp)
  apply (rule_tac t="diff_use_env (rem_use_env rxa x) (rem_use_env r_ex x)" and s="rem_use_env (diff_use_env rxa r_ex) x" in subst)
   apply (rule_tac dist_diff_rem_use_env)
  apply (rule_tac dist_rem_leq_use_env)
  apply (simp)
  done

lemma wtapr_helper: "\<lbrakk>\<And>env r_s1 tau r_s2 rx.
           \<lbrakk>well_typed env (add_use_env r_s1 (Var x1a) r) e tau r_s2 rx; Var x1a \<notin> res_vars e\<rbrakk>
           \<Longrightarrow> well_typed env r_s1 e tau (rem_use_env r_s2 (Var x1a)) (rem_use_env rx (Var x1a));
        well_typed (add_env env (Var x1a) t1) (add_use_env rxa (Var x1a) ra) e t2 r_s' r_end; aff_use_env rxa a;
        leq_use_env rxa (add_use_env r_s1 (Var x1a) r); leq_use_env r_s2 (diff_use_env (add_use_env r_s1 (Var x1a) r) r_ex); leq_use_env rx r_s2;
        leq_use_env r_ex (add_use_env r_s1 (Var x1a) r); leq_use_env (diff_use_env rxa r_ex) rx; x = Var x1a\<rbrakk>
       \<Longrightarrow> \<exists>rxa. (\<exists>r_end r_s'. well_typed (add_env env (Var x1a) t1) (add_use_env rxa (Var x1a) ra) e t2 r_s' r_end) \<and>
                 aff_use_env rxa a \<and>
                 leq_use_env rxa r_s1 \<and>
                 (\<exists>r_ex. leq_use_env (rem_use_env r_s2 (Var x1a)) (diff_use_env r_s1 r_ex) \<and>
                         leq_use_env (rem_use_env rx (Var x1a)) (rem_use_env r_s2 (Var x1a)) \<and>
                         leq_use_env r_ex r_s1 \<and> leq_use_env (diff_use_env rxa r_ex) (rem_use_env rx (Var x1a)))"
  apply (rule_tac x="rem_use_env rxa x" in exI)
  apply (auto)
     apply (rule_tac t="add_use_env (rem_use_env rxa (Var x1a)) (Var x1a) ra" and s="add_use_env rxa (Var x1a) ra" in subst)
      apply (rule_tac partial_add_rem_use_env)
     apply (auto)
    apply (rule_tac aff_rem_use_env)
    apply (simp)
   apply (rule_tac r="r" in rem_add_leq_use_env)
   apply (simp)
  apply (rule_tac wtapr_ex)
  apply (auto)
  done

lemma well_typed_add_perms_rev2: "\<lbrakk> well_typed env (add_use_env r_s1 x r) e tau r_s2 rx; x \<notin> res_vars e \<rbrakk> \<Longrightarrow>
  well_typed env r_s1 e tau (rem_use_env r_s2 x) (rem_use_env rx x)"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* const + op cases *)
            apply (rule_tac r="r" in rem_add_leq_use_env)
            apply (auto)
           apply (rule_tac dist_rem_leq_use_env)
           apply (auto)
          apply (rule_tac r="r" in rem_add_leq_use_env)
          apply (auto)
         apply (rule_tac dist_rem_leq_use_env)
         apply (auto)
    (* var cases *)
        apply (rule_tac r_sb="rem_use_env (ereq_use_env (owner_name xa) tau_x) x" in trans_leq_use_env)
         apply (rule_tac r="r" in rem_add_leq_use_env)
         apply (auto)
        apply (rule_tac rhs_rem_leq_use_env)
         apply (simp add: ereq_use_env_def)
         apply (simp add: one_use_env_def)
         apply (case_tac xa)
          apply (auto)
        apply (rule_tac id_leq_use_env)
       apply (rule_tac x="rem_use_env r_ex x" in exI)
       apply (auto)
          apply (rule_tac r="r" in rem_add_leq_use_env)
          apply (rule_tac r_sb="add_use_env (diff_use_env r_s1 (comp_use_env (ereq_use_env (owner_name xa) tau_x) r_ex)) x r" in trans_leq_use_env)
           apply (rule_tac dist_add_leq_use_env)
           apply (rule_tac dist_diff_leq_use_env_gen)
            apply (rule_tac id_leq_use_env)
           apply (rule_tac dist_comp_leq_use_env)
            apply (rule_tac self_comp_leq_use_env1)
           apply (rule_tac comp_leq_use_env2)
           apply (rule_tac self_rem_leq_use_env)
          apply (rule_tac r_sb="diff_use_env (add_use_env r_s1 x r) (comp_use_env (ereq_use_env (owner_name xa) tau_x) r_ex)" in trans_leq_use_env)
           apply (rule_tac add_diff_leq_use_env)
          apply (simp)
         apply (rule_tac dist_rem_leq_use_env)
         apply (simp)
        apply (rule_tac r="r" in rem_add_leq_use_env)
        apply (auto)
       apply (rule_tac r_sb="rem_use_env (diff_use_env (ereq_use_env (owner_name xa) tau_x) (comp_use_env (ereq_use_env (owner_name xa) tau_x) r_ex)) x" in trans_leq_use_env)
        apply (rule_tac dist_rem_leq_use_env)
        apply (simp)
       apply (simp add: dist_diff_rem_use_env)
       apply (rule_tac dist_diff_leq_use_env_gen)
        apply (rule_tac rhs_rem_leq_use_env)
         apply (simp add: ereq_use_env_def)
         apply (simp add: one_use_env_def)
         apply (case_tac xa)
          apply (auto)
        apply (rule_tac id_leq_use_env)
       apply (simp add: dist_rem_comp_use_env)
       apply (rule_tac dist_comp_leq_use_env)
        apply (rule_tac comp_leq_use_env1)
        apply (rule_tac self_rem_leq_use_env)
       apply (rule_tac self_comp_leq_use_env2)
    (* pair case *)
      apply (rule_tac x="rem_use_env r_s2a x" in exI)
      apply (rule_tac x="rem_use_env r_s3 x" in exI)
      apply (rule_tac x="rem_use_env rx1 x" in exI)
      apply (auto)
      apply (rule_tac x="rem_use_env rx2 x" in exI)
      apply (auto)
            apply (rule_tac well_typed_rem_perms)
             apply (simp_all)
            apply (simp add: non_prim_vars_def)
           apply (simp add: lift_rem_use_env)
           apply (rule_tac dist_rem_leq_use_env)
           apply (simp)
          apply (simp add: lift_rem_use_env)
          apply (rule_tac dist_rem_leq_use_env)
          apply (simp)(*
         apply (rule_tac safe_lift_rem_use_env)
         apply (simp)
        apply (rule_tac safe_lift_rem_use_env)
        apply (simp)*)
       apply (simp add: lift_rem_use_env)
       apply (rule_tac r_s="lift_use_env rx1 ra" in disj_leq_use_env1)
        apply (rule_tac r_s="lift_use_env rx2 ra" in disj_leq_use_env2)
         apply (simp)
        apply (rule_tac self_rem_leq_use_env)
       apply (rule_tac self_rem_leq_use_env)
      apply (rule_tac x="rem_use_env r_ex x" in exI)
      apply (auto)
         apply (rule_tac t="diff_use_env (rem_use_env r_s3 x) (rem_use_env r_ex x)" and s="rem_use_env (diff_use_env r_s3 r_ex) x" in subst)
          apply (rule_tac dist_diff_rem_use_env)
         apply (rule_tac dist_rem_leq_use_env)
         apply (simp)
        apply (rule_tac dist_rem_leq_use_env)
        apply (simp)
       apply (rule_tac r="r" in rem_add_leq_use_env)
       apply (auto)
      apply (case_tac "req_type (PairTy t1 t2 ra) = Prim")
       apply (simp add: pair_req_def)
       apply (rule_tac leq_empty_use_env)
      apply (simp add: pair_req_def)
      apply (rule_tac r_sb="rem_use_env (diff_use_env (comp_use_env (lift_use_env rx1 ra) (lift_use_env rx2 ra)) r_ex) x" in trans_leq_use_env)
       apply (rule_tac dist_rem_leq_use_env)
       apply (simp)
      apply (simp add: dist_diff_rem_use_env)
      apply (rule_tac dist_diff_leq_use_env)
      apply (simp add: dist_rem_comp_use_env)
      apply (simp add: lift_rem_use_env)
      apply (rule_tac id_leq_use_env)
    (* if case *)
     apply (rule_tac x="rem_use_env rx' x" in exI)
     apply (rule_tac x="rem_use_env r_s2a x" in exI)
     apply (auto)
     apply (rule_tac x="rem_use_env rx1 x" in exI)
     apply (auto)
      apply (rule_tac well_typed_rem_perms)
       apply (simp)
      apply (simp add: non_prim_vars_def)
     apply (rule_tac x="rem_use_env rx2 x" in exI)
     apply (auto)
      apply (rule_tac well_typed_rem_perms)
       apply (simp)
      apply (simp add: non_prim_vars_def)
     apply (simp add: dist_rem_comp_use_env)
    (* lam case 1. x \<noteq> x1a *)
    apply (case_tac "x \<noteq> Var x1a")
     apply (auto)
     apply (rule_tac x="rem_use_env rxa x" in exI)
     apply (auto)
        apply (rule_tac t="add_use_env (rem_use_env rxa x) (Var x1a) ra" and s="rem_use_env (add_use_env rxa (Var x1a) ra) x" in subst)
         apply (rule_tac almost_comm_rem_add_use_env)
         apply (auto)
        apply (rule_tac x="rem_use_env r_end x" in exI)
        apply (rule_tac x="rem_use_env r_s' x" in exI)
        apply (rule_tac well_typed_rem_perms)
         apply (auto)
        apply (simp add: non_prim_vars_def)
       apply (rule_tac aff_rem_use_env)
       apply (simp)
      apply (rule_tac r="r" in rem_add_leq_use_env)
      apply (simp)
     apply (rule_tac wtapr_ex)
         apply (auto)
    (* lam case 1b / 2. x = x1a *)
    apply (rule_tac wtapr_helper)
           apply (auto)
   apply (rule_tac wtapr_helper)
          apply (auto)
    (* app case. *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="ra" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="rem_use_env r_s2a x" in exI)
  apply (rule_tac x="rem_use_env rx1 x" in exI)
  apply (auto)
  apply (rule_tac x="rem_use_env rx2 x" in exI)
  apply (rule_tac x="rem_use_env r_s3 x" in exI)
  apply (auto)
   apply (rule_tac well_typed_rem_perms)
    apply (auto)
   apply (simp add: non_prim_vars_def)
  apply (rule_tac x="rem_use_env r_ex x" in exI)
  apply (auto)
        apply (rule_tac r_sb="rem_use_env (diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 ra)) r_ex)) x" in trans_leq_use_env)
         apply (simp add: dist_diff_rem_use_env)
         apply (rule_tac dist_diff_leq_use_env_gen)
          apply (rule_tac id_leq_use_env)
         apply (simp add: dist_rem_comp_use_env)
         apply (simp add: lift_rem_use_env)
         apply (rule_tac id_leq_use_env)
        apply (rule_tac dist_rem_leq_use_env)
        apply (simp)(*
       apply (rule_tac safe_lift_rem_use_env)
       apply (simp)*)
      apply (simp add: lift_rem_use_env)
      apply (rule_tac r_sb="rem_use_env (comp_use_env rx1 (lift_use_env rx2 ra)) x" in trans_leq_use_env)
       apply (rule_tac dist_rem_leq_use_env)
       apply (simp)
      apply (simp add: dist_rem_comp_use_env)
      apply (rule_tac id_leq_use_env)
     apply (simp add: lift_rem_use_env)
     apply (rule_tac r_s="rx1" in disj_leq_use_env1)
      apply (rule_tac r_s="lift_use_env rx2 ra" in disj_leq_use_env2)
       apply (simp)
      apply (rule_tac self_rem_leq_use_env)
     apply (rule_tac self_rem_leq_use_env)
    apply (rule_tac dist_rem_leq_use_env)
    apply (simp)
   apply (rule_tac r="r" in rem_add_leq_use_env)
   apply (simp)
  apply (simp add: app_req_def)
  apply (auto)
   apply (rule_tac leq_empty_use_env)
  apply (rule_tac r_sb="rem_use_env (diff_use_env (comp_use_env rx1 rx2) (comp_use_env (comp_use_env rx1 (lift_use_env rx2 ra)) r_ex)) x" in trans_leq_use_env)
   apply (rule_tac dist_rem_leq_use_env)
   apply (simp)
  apply (simp add: dist_diff_rem_use_env)
  apply (simp add: lift_rem_use_env)
  apply (simp add: dist_rem_comp_use_env)
  apply (rule_tac id_leq_use_env)
  done

    (*
      ####################################
        P7. well-typed manipulation for permission changes
      ####################################
    *)

lemma well_typed_comp_perms_gen: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; mini_disj_use_env r_s1 r_ex \<rbrakk> \<Longrightarrow>
  well_typed env (comp_use_env r_s1 r_ex) e tau (comp_use_env r_s2 r_ex) rx"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
       apply (auto)
    (* const case *)
           apply (rule_tac dist_comp_leq_use_env)
            apply (rule_tac comp_leq_use_env1)
            apply (simp)
           apply (rule_tac comp_leq_use_env2)
           apply (rule_tac id_leq_use_env)
          apply (rule_tac comp_leq_use_env1)
          apply (simp)
    (* op case *)
         apply (rule_tac dist_comp_leq_use_env)
          apply (rule_tac comp_leq_use_env1)
          apply (simp)
         apply (rule_tac comp_leq_use_env2)
         apply (rule_tac id_leq_use_env)
        apply (rule_tac comp_leq_use_env1)
        apply (simp)
    (* var case *)
       apply (rule_tac comp_leq_use_env1)
       apply (simp)
      apply (rule_tac x="r_exa" in exI)
      apply (auto)
    (* - first half of end permission bounds check *)
        apply (rule_tac dist_comp_leq_use_env)
         apply (rule_tac r_sb="diff_use_env r_s1 (comp_use_env (ereq_use_env (owner_name x) tau_x) r_exa)" in trans_leq_use_env)
          apply (rule_tac dist_diff_leq_use_env)
          apply (rule_tac self_comp_leq_use_env1)
         apply (simp)
    (* - second half of end permission bounds check *)
        apply (rule_tac rhs_dist_dcl_use_env)
        apply (rule_tac comp_leq_use_env2)
        apply (rule_tac mini_disj_diff_leq_use_env)
         apply (rule_tac id_leq_use_env)
        apply (rule_tac r_s="r_s1" in mini_disj_leq_use_env1)
         apply (simp)
        apply (rule_tac dist_comp_leq_use_env)
         apply (auto)
    (* - various bounds checks *)
       apply (rule_tac comp_leq_use_env1)
       apply (simp)
      apply (rule_tac comp_leq_use_env1)
      apply (simp)
    (* pair case *)
     apply (rule_tac x="comp_use_env r_s2a r_ex" in exI)
     apply (rule_tac x="comp_use_env r_s3 r_ex" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
        apply (cut_tac r_x="r_s2a" and r_s="r_s1" and r_ex="r_ex" in mini_disj_leq_use_env1)
          apply (simp)
         apply (rule_tac well_typed_perm_leq)
         apply (auto)
       apply (rule_tac comp_leq_use_env1)
       apply (simp)
      apply (rule_tac comp_leq_use_env1)
      apply (simp)
     apply (rule_tac x="r_exa" in exI)
     apply (auto)
       apply (rule_tac rhs_dist_dcl_use_env)
       apply (rule_tac dist_comp_leq_use_env)
        apply (rule_tac comp_leq_use_env1)
        apply (simp)
       apply (rule_tac comp_leq_use_env2)
       apply (rule_tac mini_disj_diff_leq_use_env)
        apply (rule_tac id_leq_use_env)
       apply (rule_tac r_s="r_s1" in mini_disj_leq_use_env1)
        apply (simp_all)
      apply (rule_tac comp_leq_use_env1)
      apply (simp)
     apply (rule_tac comp_leq_use_env1)
     apply (simp)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="comp_use_env r_s2a r_ex" in exI)
    apply (auto)
    apply (cut_tac r_s="r_s1" and r_x="r_s2a" and r_ex="r_ex" in mini_disj_leq_use_env1)
      apply (simp)
     apply (rule_tac well_typed_perm_leq)
     apply (auto)
    apply (rule_tac x="rx1" in exI)
    apply (auto)
    apply (rule_tac x="rx2" in exI)
    apply (auto)
    (* lambda case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
    apply (rule_tac comp_leq_use_env1)
    apply (simp)
   apply (rule_tac x="r_exa" in exI)
   apply (auto)
     apply (rule_tac rhs_dist_dcl_use_env)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac comp_leq_use_env1)
      apply (simp)
     apply (rule_tac comp_leq_use_env2)
     apply (rule_tac mini_disj_diff_leq_use_env)
      apply (rule_tac id_leq_use_env)
     apply (rule_tac r_s="r_s1" in mini_disj_leq_use_env1)
      apply (auto)
    apply (rule_tac comp_leq_use_env1)
    apply (simp)
   apply (rule_tac comp_leq_use_env1)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="comp_use_env r_s2a r_ex" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="comp_use_env r_s3 r_ex" in exI)
  apply (auto)
   apply (cut_tac r_s="r_s1" and r_x="r_s2a" and r_ex="r_ex" in mini_disj_leq_use_env1)
     apply (simp)
    apply (rule_tac well_typed_perm_leq)
    apply (auto)
  apply (cut_tac r_sa="r_s1" and r_sb="r_s2a" and r_sc="r_s3" in trans_leq_use_env)
    apply (rule_tac well_typed_perm_leq)
    apply (auto)
   apply (rule_tac well_typed_perm_leq)
   apply (auto)
  apply (rule_tac x="r_exa" in exI)
  apply (auto)
    (* - first half of end permissions bounds check *)
     apply (rule_tac rhs_dist_dcl_use_env)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac comp_leq_use_env1)
      apply (simp)
    (* - second half of end permissions bounds check *)
     apply (rule_tac comp_leq_use_env2)
     apply (rule_tac mini_disj_diff_leq_use_env)
      apply (rule_tac id_leq_use_env)
     apply (rule_tac r_s="r_s1" in mini_disj_leq_use_env1)
      apply (simp)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac r_sb="r_s3" in trans_leq_use_env)
       apply (auto)
    (* - final bounds checks *)
    apply (rule_tac comp_leq_use_env1)
    apply (simp)
   apply (rule_tac comp_leq_use_env1)
   apply (simp)
  apply (rule_tac comp_leq_use_env1)
  apply (simp)
  done

lemma well_typed_comp_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; disj_use_env r_s1 r_ex \<rbrakk> \<Longrightarrow>
  well_typed env (comp_use_env r_s1 r_ex) e tau (comp_use_env r_s2 r_ex) rx"
  apply (rule_tac well_typed_comp_perms_gen)
   apply (simp)
  apply (simp add: disj_use_env_def)
  done

lemma well_typed_comp_perms2: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; disj_use_env r_s1 r_ex \<rbrakk> \<Longrightarrow>
  well_typed env (comp_use_env r_ex r_s1) e tau (comp_use_env r_ex r_s2) rx"
  apply (cut_tac r_s="r_ex" and r_x="r_s1" in comm_comp_use_env)
  apply (cut_tac r_s="r_ex" and r_x="r_s2" in comm_comp_use_env)
  apply (auto)
  apply (rule_tac well_typed_comp_perms)
   apply (auto)
  done

lemma well_typed_add_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<notin> non_prim_vars env e; r = OwnPerm; rx x = NoPerm \<rbrakk> \<Longrightarrow>
  well_typed env (add_use_env r_s1 x r) e tau (add_use_env r_s2 x r) rx"
  apply (cut_tac r_s="r_s1" and x="x" and r="r" in partial_add_rem_use_env)
  apply (cut_tac r_s="r_s2" and x="x" and r="r" in partial_add_rem_use_env)
  apply (cut_tac r_s="rx" and x="x" in ignore_rem_use_env)
   apply (simp)
  apply (cut_tac r_s="rem_use_env r_s1 x" and x="x" and r="r" in add_comp_use_env)
   apply (auto)
  apply (cut_tac r_s="rem_use_env r_s2 x" and x="x" and r="r" in add_comp_use_env)
    apply (auto)
  apply (rule_tac well_typed_comp_perms)
   apply (cut_tac env="env" and ?r_s1.0="r_s1" and e="e" and tau="tau" and ?r_s2.0="r_s2" and rx="rx" and x="x" in well_typed_rem_perms)
     apply (auto)
  apply (rule_tac disj_one_use_env)
  apply (simp add: rem_use_env_def)
  done

lemma well_typed_incr_simul_perm: "\<lbrakk> leq_use_env r_s r_c; well_typed env r_s e tau r_s rx \<rbrakk> \<Longrightarrow> well_typed env r_c e tau r_c rx"
  apply (rule_tac t="r_c" and s="comp_use_env r_s (diff_use_env r_c r_s)" in subst)
   apply (rule_tac msum_diff_comp_use_env)
   apply (simp)
  apply (rule_tac well_typed_comp_perms_gen)
   apply (simp)
  apply (rule_tac mini_disj_diff_use_env)
  done

lemma well_typed_lift_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> well_typed env (lift_use_env r_s1 r) e tau (lift_use_env r_s2 r) rx"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* const + op cases *)
           apply (rule_tac dist_lift_leq_use_env)
           apply (simp)
          apply (rule_tac lift_leq_use_env)
          apply (simp)
         apply (rule_tac dist_lift_leq_use_env)
         apply (simp)
        apply (rule_tac lift_leq_use_env)
        apply (simp)
    (* var cases *)
       apply (rule_tac lift_leq_use_env)
       apply (simp)
      apply (rule_tac x="r_ex" in exI)
      apply (auto)
        apply (cut_tac r_s="r_s1" and r_x="comp_use_env (ereq_use_env (owner_name x) tau_x) r_ex" and r="r" in lift_diff_use_env)
        apply (auto)
        apply (rule_tac dist_lift_leq_use_env)
        apply (simp)
       apply (rule_tac lift_leq_use_env)
       apply (simp)
      apply (rule_tac lift_leq_use_env)
      apply (simp)
    (* pair case *)
     apply (rule_tac x="lift_use_env r_s2a r" in exI)
     apply (rule_tac x="lift_use_env r_s3 r" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
       apply (rule_tac lift_leq_use_env)
       apply (simp)
      apply (rule_tac lift_leq_use_env)
      apply (simp)
     apply (rule_tac x="r_ex" in exI)
     apply (auto)
       apply (cut_tac r_s="r_s3" and r_x="r_ex" and r="r" in lift_diff_use_env)
       apply (simp)
       apply (rule_tac dist_lift_leq_use_env)
       apply (simp)
      apply (rule_tac lift_leq_use_env)
      apply (simp)
     apply (rule_tac lift_leq_use_env)
     apply (simp)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="lift_use_env r_s2a r" in exI)
    apply (auto)
    apply (rule_tac x="rx1" in exI)
    apply (auto)
    apply (rule_tac x="rx2" in exI)
    apply (auto)
    (* lam case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
    apply (rule_tac lift_leq_use_env)
    apply (simp)
   apply (rule_tac x="r_ex" in exI)
   apply (auto)
     apply (cut_tac r_s="r_s1" and r_x="r_ex" and r="r" in lift_diff_use_env)
     apply (auto)
     apply (rule_tac dist_lift_leq_use_env)
     apply (simp)
    apply (rule_tac lift_leq_use_env)
    apply (simp)
   apply (rule_tac lift_leq_use_env)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="ra" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="lift_use_env r_s2a r" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="lift_use_env r_s3 r" in exI)
  apply (auto)
  apply (rule_tac x="r_ex" in exI)
  apply (auto)
     apply (cut_tac r_s="r_s3" and r_x="comp_use_env (comp_use_env rx1 (lift_use_env rx2 ra)) r_ex" and r="r" in lift_diff_use_env)
     apply (auto)
     apply (rule_tac dist_lift_leq_use_env)
     apply (simp)
    apply (rule_tac lift_leq_use_env)
    apply (simp)
   apply (rule_tac lift_leq_use_env)
   apply (simp)
  apply (rule_tac lift_leq_use_env)
  apply (simp)
  done

    (*
      ####################################
        P8. well-typed manipulation for end permissions
      ####################################
    *)

lemma wtdep_diff_use_env: "\<lbrakk> leq_use_env r_x (diff_use_env r_s r_xa) \<rbrakk> \<Longrightarrow> diff_use_env r_x r_ex = diff_use_env r_x (comp_use_env (diff_use_env r_ex r_xa) r_xa)"
  apply (case_tac "\<forall> x. diff_use_env r_x r_ex x = diff_use_env r_x (comp_use_env (diff_use_env r_ex r_xa) r_xa) x")
   apply (auto)
  apply (simp add: diff_use_env_def)
  apply (simp add: leq_use_env_def)
  apply (simp add: comp_use_env_def)
  apply (erule_tac x="x" in allE)
  apply (case_tac "r_xa x")
    apply (auto)
    apply (case_tac "r_ex x")
      apply (auto)
   apply (case_tac "r_ex x")
     apply (auto)
  apply (case_tac "r_x x")
    apply (auto)
  apply (case_tac "r_ex x")
    apply (auto)
  done

lemma wtdep_strong_use_vars: "\<lbrakk> well_typed env (diff_use_env r_s1 r_x) e tau r_s2 rx; strong_use_env r_x \<rbrakk> \<Longrightarrow> non_prim_vars env e \<inter> own_env_vars r_x = {}"
  apply (auto)
  apply (case_tac "r_x x \<noteq> NoPerm")
   apply (case_tac "r_x x")
     apply (auto)
    apply (simp add: strong_use_env_def)
   apply (cut_tac r_s="r_s1" and r_ex="r_x" and x="x" in diff_use_none_ex)
    apply (auto)
   apply (cut_tac x="x" and e="e" and env="env" and ?r_s1.0="diff_use_env r_s1 r_x" in well_typed_no_npv_use)
     apply (auto)
  apply (simp add: own_env_vars_def)
  done

lemma well_typed_break: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau (norm_use_env r_s1 r_s2) rx"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* const case *)
          apply (rule_tac self_norm_leq_use_env)
         apply (rule_tac rhs_norm_leq_use_env)
          apply (auto)
    (* op case *)
        apply (rule_tac self_norm_leq_use_env)
       apply (rule_tac rhs_norm_leq_use_env)
        apply (auto)
    (* var case *)
      apply (rule_tac x="r_ex" in exI)
      apply (auto)
       apply (rule_tac diff_norm_leq_use_env)
       apply (simp)
      apply (rule_tac rhs_norm_leq_use_env)
       apply (simp)
      apply (rule_tac r_sb="diff_use_env r_s1 (comp_use_env (ereq_use_env (owner_name x) tau_x) r_ex)" in trans_leq_use_env)
       apply (rule_tac self_diff_leq_use_env)
      apply (auto)
    (* pair case *)
     apply (cut_tac r_sc="r_s3" and r_sb="r_s2a" and r_sa="r_s1" in trans_leq_use_env)
       apply (rule_tac well_typed_perm_leq)
       apply (auto)
      apply (rule_tac well_typed_perm_leq)
      apply (auto)
     apply (rule_tac x="norm_use_env r_s1 r_s2a" in exI)
     apply (rule_tac x="norm_use_env r_s1 r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
        apply (rule_tac t="norm_use_env r_s1 r_s3" and s="norm_use_env (norm_use_env r_s1 r_s2a) r_s3" in subst)
         apply (rule_tac sub_norm_use_env)
         apply (rule_tac well_typed_perm_leq)
         apply (auto)
        apply (cut_tac env="env" and ?r_s1.0="r_s2a" and r_c="norm_use_env r_s1 r_s2a" and e="e2" and ?r_s2.0="r_s3" and rx="rx2" in well_typed_incr_start_perm)
          apply (auto)
        apply (rule_tac rhs_self_norm_leq_use_env)
        apply (rule_tac well_typed_perm_leq)
        apply (auto)
       apply (rule_tac rhs_norm_leq_use_env)
        apply (auto)
      apply (rule_tac rhs_norm_leq_use_env)
       apply (auto)
     apply (rule_tac x="r_ex" in exI)
     apply (auto)
      apply (rule_tac spec_norm_leq_use_env)
      apply (simp)
     apply (rule_tac rhs_norm_leq_use_env)
      apply (simp)
     apply (rule_tac r_sb="diff_use_env r_s3 r_ex" in trans_leq_use_env)
      apply (rule_tac diff_leq_use_env)
     apply (auto)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="norm_use_env r_s1 r_s2a" in exI)
    apply (auto)
    (* - common substitution *)
    apply (cut_tac ?r_s1.0="r_s2a" and ?r_s2.0="r_s2" in well_typed_perm_leq)
     apply (auto)
    apply (rule_tac t="norm_use_env r_s1 r_s2" and s="norm_use_env (norm_use_env r_s1 r_s2a) r_s2" in subst)
     apply (rule_tac sub_norm_use_env)
     apply (simp)
    (* - rx1 *)
    apply (rule_tac x="rx1" in exI)
    apply (auto)
     apply (cut_tac env="env" and ?r_s1.0="r_s2a" and r_c="norm_use_env r_s1 r_s2a" and e="e2" and ?r_s2.0="r_s2" and rx="rx1" in well_typed_incr_start_perm)
       apply (auto)
     apply (rule_tac rhs_self_norm_leq_use_env)
     apply (rule_tac well_typed_perm_leq)
     apply (auto)
    (* - rx2 *)
    apply (rule_tac x="rx2" in exI)
    apply (auto)
    apply (cut_tac env="env" and ?r_s1.0="r_s2a" and r_c="norm_use_env r_s1 r_s2a" and e="e3" and ?r_s2.0="r_s2" and rx="rx2" in well_typed_incr_start_perm)
      apply (auto)
    apply (rule_tac rhs_self_norm_leq_use_env)
    apply (rule_tac well_typed_perm_leq)
    apply (auto)
    (* lam case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_ex" in exI)
   apply (auto)
    apply (rule_tac diff_norm_leq_use_env)
    apply (simp)
   apply (rule_tac rhs_norm_leq_use_env)
    apply (auto)
   apply (rule_tac r_sb="diff_use_env r_s1 r_ex" in trans_leq_use_env)
    apply (rule_tac self_diff_leq_use_env)
   apply (auto)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="norm_use_env r_s1 r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="norm_use_env r_s1 r_s3" in exI)
  apply (cut_tac ?r_s1.0="r_s2a" and ?r_s2.0="r_s3" in well_typed_perm_leq)
   apply (auto)
   apply (rule_tac t="norm_use_env r_s1 r_s3" and s="norm_use_env (norm_use_env r_s1 r_s2a) r_s3" in subst)
    apply (rule_tac sub_norm_use_env)
    apply (simp)
   apply (cut_tac env="env" and ?r_s1.0="r_s2a" and r_c="norm_use_env r_s1 r_s2a" and e="e2" and ?r_s2.0="r_s3" and rx="rx2" in well_typed_incr_start_perm)
     apply (auto)
   apply (rule_tac rhs_self_norm_leq_use_env)
   apply (rule_tac well_typed_perm_leq)
   apply (auto)
  apply (cut_tac r_sc="r_s3" and r_sb="r_s2a" and r_sa="r_s1" in trans_leq_use_env)
    apply (rule_tac well_typed_perm_leq)
    apply (auto)
  apply (rule_tac x="r_ex" in exI)
  apply (auto)
    apply (rule_tac spec_norm_leq_use_env)
    apply (simp)
   apply (rule_tac r_sb="r_s3" in trans_leq_use_env)
    apply (rule_tac rhs_self_norm_leq_use_env)
    apply (auto)
  apply (rule_tac r_sb="r_s2" in trans_leq_use_env)
   apply (rule_tac rhs_self_norm_leq_use_env)
   apply (rule_tac r_sb="r_s3" in trans_leq_use_env)
    apply (auto)
  apply (rule_tac r_sb="diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)" in trans_leq_use_env)
   apply (rule_tac self_diff_leq_use_env)
  apply (simp)
  done

    (* when we perform substitution, we need to be able to stop "requiring" permissions. the
    intuition behind this lemma is that we no longer need a permission if we simply remove it from
    the list of permissions in the environment. *)

lemma well_typed_diff_end_perm: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env r_ex r_s1 \<rbrakk> \<Longrightarrow>
  well_typed env r_s1 e tau (diff_use_env r_s2 r_ex) (diff_use_env rx r_ex)"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx r_ex)
        apply (auto)
    (* const case + op case are trivial since they never require permissions *)
          apply (rule_tac diff_leq_use_env)
          apply (simp)
         apply (rule_tac dist_diff_leq_use_env)
         apply (simp)
        apply (rule_tac diff_leq_use_env)
        apply (simp)
       apply (rule_tac dist_diff_leq_use_env)
       apply (simp)
    (* var case *)
      apply (rule_tac x="comp_use_env r_exa r_ex" in exI)
      apply (auto)
         apply (rule_tac rhs_unroll_dcl_use_env)
         apply (rule_tac rhs_unroll_dcl_use_env)
         apply (rule_tac dist_diff_leq_use_env)
         apply (rule_tac rhs_fold_dcl_use_env)
         apply (simp)
        apply (rule_tac dist_diff_leq_use_env)
        apply (simp)
       apply (rule_tac dist_comp_leq_use_env)
        apply (auto)
      apply (rule_tac lhs_unroll_dcl_use_env)
      apply (rule_tac lhs_unroll_dcl_use_env)
      apply (rule_tac dist_diff_leq_use_env)
      apply (rule_tac lhs_fold_dcl_use_env)
      apply (simp)
    (* pair case *)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
     apply (rule_tac x="comp_use_env r_exa r_ex" in exI)
     apply (auto)
        apply (rule_tac rhs_unroll_dcl_use_env)
        apply (rule_tac dist_diff_leq_use_env)
        apply (simp)
       apply (rule_tac dist_diff_leq_use_env)
       apply (simp)
      apply (rule_tac dist_comp_leq_use_env)
       apply (simp_all)
     apply (case_tac "req_type (PairTy t1 t2 r) = Prim")
      apply (simp add: pair_req_def)
      apply (rule_tac leq_empty_use_env)
     apply (simp add: pair_req_def)
     apply (rule_tac lhs_unroll_dcl_use_env)
     apply (rule_tac dist_diff_leq_use_env)
     apply (simp)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (cut_tac env="env" and ?r_s1.0="r_s1" and e="e1" and ?r_s2.0="r_s2a" in well_typed_break)
     apply (auto)
    apply (cut_tac r_x="r_s2a" and r_s="r_s1" in ex_norm_use_env)
     apply (rule_tac well_typed_perm_leq)
     apply (auto)
    (* - setup r_s2 \<le> r_s1 - r_exa *)
    apply (cut_tac r_sc="r_s2" and r_sb="r_s2a" and r_sa="norm_use_env r_s1 r_s2a" in trans_leq_use_env)
      apply (rule_tac rhs_self_norm_leq_use_env)
      apply (rule_tac well_typed_perm_leq)
      apply (auto)
     apply (rule_tac well_typed_perm_leq)
     apply (auto)
    (* - prelim for both inductions *)
    apply (case_tac "diff_use_env r_s2 (comp_use_env (diff_use_env r_ex r_exa) r_exa) \<noteq> diff_use_env (diff_use_env r_s2 (diff_use_env r_ex r_exa)) r_exa")
     apply (cut_tac r_s="r_s2" and r_x="diff_use_env r_ex r_exa" and r_ex="r_exa" in diff_comp_use_env)
     apply (auto)
    apply (cut_tac r_sc="diff_use_env r_ex r_exa" and r_sb="r_ex" and r_sa="r_s1" in trans_leq_use_env)
      apply (simp)
     apply (rule_tac self_diff_leq_use_env)
    (* - first induction *)
    apply (rule_tac x="diff_use_env r_s1 r_exa" in exI)
    apply (auto)
    apply (rule_tac x="diff_use_env rx1 r_ex" in exI)
    apply (auto)
    apply (cut_tac r_x="r_s2" and r_s="r_s1" and r_xa="r_exa" and r_ex="r_ex" in wtdep_diff_use_env)
     apply (auto)
    apply (cut_tac r_x="rx1" and r_s="r_s1" and r_xa="r_exa" and r_ex="r_ex" in wtdep_diff_use_env)
      apply (auto)
      apply (rule_tac r_sb="r_s2" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac well_typed_perm_leqx)
      apply (auto)
     apply (rule_tac t="diff_use_env rx1 (comp_use_env (diff_use_env r_ex r_exa) r_exa)" and s="diff_use_env (diff_use_env rx1 (diff_use_env r_ex r_exa)) r_exa" in subst)
      apply (rule_tac diff_comp_use_env)
     apply (rule_tac well_typed_diff_perms)
      apply (auto)
      apply (cut_tac env="env" and ?r_s1.0="r_s2a" and r_c="r_s1" and e="e2" and tau="tau" and ?r_s2.0="r_s2" and rx="rx1" in well_typed_incr_start_perm)
        apply (auto)
      apply (rule_tac well_typed_perm_leq)
      apply (auto)
    (* - lemma to prove non-prim x is not in e2 *)
     apply (cut_tac env="env" and ?r_s1.0="r_s1" and tau="tau" and ?r_s2.0="r_s2" and rx="rx1" and e="e2" and r_x="r_exa" in wtdep_strong_use_vars)
       apply (rule_tac ?r_s1.0="r_s2a" in well_typed_incr_start_perm)
        apply (auto)
     apply (rule_tac r_sb="norm_use_env r_s1 r_s2a" in trans_leq_use_env)
      apply (simp)
      apply (rule_tac id_leq_use_env)
     apply (rule_tac rhs_self_norm_leq_use_env)
     apply (rule_tac well_typed_perm_leq)
     apply (auto)
    (* - second induction *)
    apply (rule_tac x="diff_use_env rx2 r_ex" in exI)
    apply (auto)
     apply (cut_tac r_x="r_s2" and r_s="r_s1" and r_xa="r_exa" and r_ex="r_ex" in wtdep_diff_use_env)
      apply (auto)
     apply (cut_tac r_x="rx2" and r_s="r_s1" and r_xa="r_exa" and r_ex="r_ex" in wtdep_diff_use_env)
      apply (auto)
      apply (rule_tac r_sb="r_s2" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac well_typed_perm_leqx)
      apply (auto)
     apply (rule_tac t="diff_use_env rx2 (comp_use_env (diff_use_env r_ex r_exa) r_exa)" and s="diff_use_env (diff_use_env rx2 (diff_use_env r_ex r_exa)) r_exa" in subst)
      apply (rule_tac diff_comp_use_env)
     apply (rule_tac well_typed_diff_perms)
      apply (auto)
      apply (cut_tac env="env" and ?r_s1.0="r_s2a" and r_c="r_s1" and e="e3" and tau="tau" and ?r_s2.0="r_s2" and rx="rx2" in well_typed_incr_start_perm)
        apply (auto)
      apply (rule_tac well_typed_perm_leq)
      apply (auto)
    (* - lemma to prove non-prim x is not in e3 *)
     apply (cut_tac env="env" and ?r_s1.0="r_s1" and tau="tau" and ?r_s2.0="r_s2" and rx="rx2" and e="e3" and r_x="r_exa" in wtdep_strong_use_vars)
       apply (rule_tac ?r_s1.0="r_s2a" in well_typed_incr_start_perm)
        apply (auto)
     apply (rule_tac r_sb="norm_use_env r_s1 r_s2a" in trans_leq_use_env)
      apply (simp)
      apply (rule_tac id_leq_use_env)
     apply (rule_tac rhs_self_norm_leq_use_env)
     apply (rule_tac well_typed_perm_leq)
     apply (auto)
    (* - final equality *)
    apply (simp add: dist_diff_comp_use_env)
    (* the lambda case allows us to select any r_s2 + rx as long as they match. *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="comp_use_env r_exa r_ex" in exI)
   apply (auto)
      apply (rule_tac r_sb="diff_use_env (diff_use_env r_s1 r_exa) r_ex" in trans_leq_use_env)
       apply (rule_tac diff_comp_leq_use_env1)
      apply (rule_tac dist_diff_leq_use_env)
      apply (simp)
     apply (rule_tac dist_diff_leq_use_env)
     apply (simp)
    apply (rule_tac dist_comp_leq_use_env)
     apply (simp_all)
   apply (rule_tac lhs_unroll_dcl_use_env)
   apply (rule_tac dist_diff_leq_use_env)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  apply (rule_tac x="comp_use_env r_exa r_ex" in exI)
  apply (auto)
     apply (rule_tac rhs_unroll_dcl_use_env)
     apply (rule_tac rhs_unroll_dcl_use_env)
     apply (rule_tac dist_diff_leq_use_env)
     apply (rule_tac rhs_fold_dcl_use_env)
     apply (simp)
    apply (rule_tac dist_diff_leq_use_env)
    apply (simp)
   apply (rule_tac dist_comp_leq_use_env)
    apply (simp_all)
  apply (simp add: app_req_def)
  apply (auto)
   apply (rule_tac leq_empty_use_env)
  apply (rule_tac lhs_unroll_dcl_use_env)
  apply (rule_tac lhs_unroll_dcl_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (rule_tac lhs_fold_dcl_use_env)
  apply (simp)
  done

lemma well_typed_rem_end_perm: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; r_s1 x = OwnPerm \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau (rem_use_env r_s2 x) (rem_use_env rx x)"
  apply (cut_tac r_s="r_s2" and x="x" in diff_rem_use_env)
  apply (cut_tac r_s="rx" and x="x" in diff_rem_use_env)
  apply (auto)
  apply (rule_tac well_typed_diff_end_perm)
   apply (auto)
  apply (simp add: leq_use_env_def)
  apply (simp add: one_use_env_def)
  done

lemma well_typed_decr_end_perm: "\<lbrakk> well_typed env r_s1 e tau r_c rx; leq_use_env r_s2 r_c; leq_use_env rx r_s2 \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_s2 rx"
  apply (induction e arbitrary: env r_s1 tau rx)
        apply (auto)
        apply (rule_tac r_sb="r_c" in trans_leq_use_env)
         apply (auto)
       apply (rule_tac r_sb="r_c" in trans_leq_use_env)
        apply (auto)
      apply (rule_tac x="r_ex" in exI)
      apply (auto)
      apply (rule_tac r_sb="r_c" in trans_leq_use_env)
       apply (auto)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
     apply (rule_tac x="r_ex" in exI)
     apply (auto)
     apply (rule_tac r_sb="r_c" in trans_leq_use_env)
      apply (simp_all)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="r_s2a" in exI)
    apply (auto)
    apply (rule_tac x="rx1" in exI)
    apply (auto)
     apply (cut_tac r_sa="r_s2" and r_sb="comp_use_env rx1 rx2" and r_sc="rx1" in trans_leq_use_env)
       apply (auto)
     apply (rule_tac comp_leq_use_env1)
     apply (rule_tac id_leq_use_env)
    apply (rule_tac x="rx2" in exI)
    apply (auto)
    apply (cut_tac r_sa="r_s2" and r_sb="comp_use_env rx1 rx2" and r_sc="rx2" in trans_leq_use_env)
      apply (auto)
    apply (rule_tac comp_leq_use_env2)
    apply (rule_tac id_leq_use_env)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_ex" in exI)
   apply (auto)
   apply (rule_tac r_sb="r_c" in trans_leq_use_env)
    apply (auto)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  apply (rule_tac x="r_ex" in exI)
  apply (auto)
  apply (rule_tac r_sb="r_c" in trans_leq_use_env)
   apply (auto)
  done

lemma well_typed_diff_decr_end_perm: "\<lbrakk> well_typed env r_s1 e tau (diff_use_env r_s2 r_ex) (diff_use_env rx r_ex');
    leq_use_env r_ex' r_ex; leq_use_env r_ex r_s1 \<rbrakk> \<Longrightarrow>
    well_typed env r_s1 e tau (diff_use_env r_s2 r_ex) (diff_use_env rx r_ex)"
  apply (case_tac "well_typed env r_s1 e tau (diff_use_env r_s2 r_ex) (diff_use_env rx r_ex) =
    well_typed env r_s1 e tau (diff_use_env (diff_use_env r_s2 r_ex) r_ex) (diff_use_env (diff_use_env rx r_ex') r_ex)")
   apply (simp)
   apply (rule_tac well_typed_diff_end_perm)
    apply (auto)
  apply (cut_tac r_s="r_s2" and r_x="r_ex" in double_diff_use_env)
  apply (cut_tac r_s="rx" and r_x="r_ex'" and r_c="r_ex" in cancel_diff_use_env)
   apply (auto)
  done

lemma well_typed_diff_decr_end_perm_gen: "\<lbrakk> well_typed env r_s1 e tau (diff_use_env r_s2 r_exb) (diff_use_env rx r_exb);
  leq_use_env r_exb r_exa; leq_use_env r_exa r_s1 \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau (diff_use_env r_s2 r_exa) (diff_use_env rx r_exa)"
  apply (cut_tac r_s="r_s2" and r_x="r_exb" and r_c="r_exa" in cancel_diff_use_env)
   apply (auto)
  apply (cut_tac r_s="rx" and r_x="r_exb" and r_c="r_exa" in cancel_diff_use_env)
   apply (auto)
  apply (rule_tac well_typed_diff_end_perm)
   apply (auto)
  done

    (*
      ####################################
        P9. well-typed manipulation for requirements
      ####################################
    *)

lemma well_typed_comp_req1: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env r_ex r_s2 \<rbrakk> \<Longrightarrow>
  well_typed env r_s1 e tau r_s2 (comp_use_env r_ex rx)"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx r_ex)
        apply (auto)
    (* const + op case *)
        apply (rule_tac dist_comp_leq_use_env)
         apply (auto)
       apply (rule_tac dist_comp_leq_use_env)
        apply (auto)
    (* var cases *)
      apply (rule_tac x="r_exa" in exI)
      apply (auto)
       apply (rule_tac dist_comp_leq_use_env)
        apply (auto)
      apply (rule_tac comp_leq_use_env2)
      apply (simp)
    (* pair case *)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
     apply (rule_tac x="r_exa" in exI)
     apply (auto)
      apply (rule_tac dist_comp_leq_use_env)
       apply (simp_all)
     apply (rule_tac comp_leq_use_env2)
     apply (simp)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="r_s2a" in exI)
    apply (auto)
    apply (rule_tac x="comp_use_env r_ex rx1" in exI)
    apply (auto)
    apply (rule_tac x="rx2" in exI)
    apply (auto)
    apply (rule_tac assoc_comp_use_env)
    (* lambda case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_exa" in exI)
   apply (auto)
    apply (rule_tac dist_comp_leq_use_env)
     apply (auto)
   apply (rule_tac comp_leq_use_env2)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  apply (rule_tac x="r_exa" in exI)
  apply (auto)
   apply (rule_tac dist_comp_leq_use_env)
    apply (auto)
  apply (rule_tac comp_leq_use_env2)
  apply (simp)
  done

lemma well_typed_comp_req2: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env r_ex r_s2 \<rbrakk> \<Longrightarrow>
  well_typed env r_s1 e tau r_s2 (comp_use_env rx r_ex)"
  apply (cut_tac r_s="rx" and r_x="r_ex" in comm_comp_use_env)
  apply (auto)
  apply (rule_tac well_typed_comp_req1)
   apply (auto)
  done

lemma well_typed_incr_req: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env rx rc; leq_use_env rc r_s2 \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_s2 rc"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* var case *)
      apply (rule_tac x="r_ex" in exI)
      apply (auto)
      apply (rule_tac r_sb="rx" in trans_leq_use_env)
       apply (auto)
    (* pair case *)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
     apply (rule_tac x="r_ex" in exI)
     apply (auto)
     apply (rule_tac r_sb="rx" in trans_leq_use_env)
      apply (auto)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="r_s2a" in exI)
    apply (auto)
    apply (rule_tac x="rc" in exI)
    apply (auto)
     apply (cut_tac r_sc="rx1" and r_sb="comp_use_env rx1 rx2" and r_sa="rc" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac self_comp_leq_use_env1)
     apply (simp)
    apply (rule_tac x="rc" in exI)
    apply (auto)
     apply (cut_tac r_sc="rx2" and r_sb="comp_use_env rx1 rx2" and r_sa="rc" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac self_comp_leq_use_env2)
     apply (simp)
    apply (case_tac "\<forall> x. rc x = comp_use_env rc rc x")
     apply (auto)
    apply (simp add: comp_use_env_def)
    apply (case_tac "rc x")
      apply (auto)
    (* lam case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_ex" in exI)
   apply (auto)
   apply (rule_tac r_sb="rx" in trans_leq_use_env)
    apply (auto)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="r" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  apply (rule_tac x="r_ex" in exI)
  apply (auto)
  apply (rule_tac r_sb="rx" in trans_leq_use_env)
   apply (auto)
  done

lemma well_typed_simul_end_perm: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env r_c r_s2;
  leq_use_env rc r_c; leq_use_env rx rc \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_c rc"
  apply (rule_tac rx="rx" in well_typed_incr_req)
    apply (rule_tac r_c="r_s2" in well_typed_decr_end_perm)
      apply (auto)
  apply (rule_tac r_sb="rc" in trans_leq_use_env)
   apply (auto)
  done

lemma well_typed_add_permsx: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; x \<notin> non_prim_vars env e \<rbrakk> \<Longrightarrow>
  well_typed env (add_use_env r_s1 x r) e tau (add_use_env r_s2 x r) (add_use_env rx x r)"
  apply (cut_tac r_s="r_s1" and x="x" and r="r" in partial_add_rem_use_env)
  apply (cut_tac r_s="r_s2" and x="x" and r="r" in partial_add_rem_use_env)
  apply (cut_tac r_s="rx" and x="x" and r="r" in partial_add_rem_use_env)
  apply (simp)
  apply (cut_tac r_s="rem_use_env r_s1 x" and x="x" and r="r" in add_comp_use_env)
   apply (auto)
   apply (simp add: rem_use_env_def)
  apply (cut_tac r_s="rem_use_env r_s2 x" and x="x" and r="r" in add_comp_use_env)
   apply (auto)
   apply (simp add: rem_use_env_def)
  apply (cut_tac r_s="rem_use_env rx x" and x="x" and r="r" in add_comp_use_env)
   apply (auto)
   apply (simp add: rem_use_env_def)
  apply (rule_tac well_typed_comp_req2)
   apply (rule_tac well_typed_comp_perms)
    apply (rule_tac well_typed_rem_perms)
     apply (auto)
   apply (simp add: disj_use_env_def)
   apply (simp add: mini_disj_use_env_def)
   apply (simp add: one_use_env_def)
   apply (simp add: rem_use_env_def)
  apply (rule_tac self_comp_leq_use_env2)
  done

    (*
      ####################################
        P10. well-typed manipulation involving lifts
      ####################################
    *)

lemma well_typed_lift_req: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx; leq_use_env (lift_use_env rx r) r_s2 \<rbrakk> \<Longrightarrow> well_typed env r_s1 e tau r_s2 (lift_use_env rx r)"
  apply (induct e arbitrary: env r_s1 tau r_s2 rx)
        apply (auto)
    (* var case *)
      apply (rule_tac x="r_ex" in exI)
      apply (auto)
      apply (rule_tac lift_leq_use_env)
      apply (simp)
    (* pair case *)
     apply (rule_tac x="r_s2a" in exI)
     apply (rule_tac x="r_s3" in exI)
     apply (rule_tac x="rx1" in exI)
     apply (auto)
     apply (rule_tac x="rx2" in exI)
     apply (auto)
     apply (rule_tac x="r_ex" in exI)
     apply (auto)
     apply (rule_tac lift_leq_use_env)
     apply (simp)
    (* if case *)
    apply (rule_tac x="rx'" in exI)
    apply (rule_tac x="r_s2a" in exI)
    apply (auto)
    apply (rule_tac x="lift_use_env rx1 r" in exI)
    apply (auto)
     apply (cut_tac r_sc="lift_use_env rx1 r" and r_sb="lift_use_env (comp_use_env rx1 rx2) r" and r_sa="r_s2" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac dist_lift_leq_use_env)
      apply (rule_tac self_comp_leq_use_env1)
     apply (auto)
    apply (rule_tac x="lift_use_env rx2 r" in exI)
    apply (auto)
     apply (cut_tac r_sc="lift_use_env rx2 r" and r_sb="lift_use_env (comp_use_env rx1 rx2) r" and r_sa="r_s2" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac dist_lift_leq_use_env)
      apply (rule_tac self_comp_leq_use_env2)
     apply (auto)
    apply (rule_tac lift_comp_use_env)
    (* lam case *)
   apply (rule_tac x="rxa" in exI)
   apply (auto)
   apply (rule_tac x="r_ex" in exI)
   apply (auto)
   apply (rule_tac lift_leq_use_env)
   apply (simp)
    (* app case *)
  apply (rule_tac x="t1" in exI)
  apply (rule_tac x="ra" in exI)
  apply (rule_tac x="a" in exI)
  apply (rule_tac x="r_s2a" in exI)
  apply (rule_tac x="rx1" in exI)
  apply (auto)
  apply (rule_tac x="rx2" in exI)
  apply (auto)
  apply (rule_tac x="r_s3" in exI)
  apply (auto)
  apply (rule_tac x="r_ex" in exI)
  apply (auto)
  apply (rule_tac lift_leq_use_env)
  apply (auto)
  done

lemma well_typed_lift_all_perms: "\<lbrakk> well_typed env r_s1 e tau r_s2 rx \<rbrakk> \<Longrightarrow> well_typed env (lift_use_env r_s1 r) e tau (lift_use_env r_s2 r) (lift_use_env rx r)"
  apply (rule_tac well_typed_lift_req)
   apply (rule_tac well_typed_lift_perms)
   apply (simp)
  apply (rule_tac dist_lift_leq_use_env)
  apply (rule_tac well_typed_perm_leqx)
  apply (auto)
  done

end


(*  Title:      HOL/Auth/n_germanSymIndex.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_germanSymIndex Protocol Case Study*}

theory n_germanSymIndex imports n_germanSymIndex_lemma_invs_on_rules n_germanSymIndex_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