2014-07-14 19:32:44 +00:00
|
|
|
(*
|
|
|
|
* Copyright 2014, NICTA
|
|
|
|
*
|
|
|
|
* This software may be distributed and modified according to the terms of
|
|
|
|
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
|
|
|
|
* See "LICENSE_GPLv2.txt" for details.
|
|
|
|
*
|
|
|
|
* @TAG(NICTA_GPL)
|
|
|
|
*)
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Proofs regarding the State Translation.
|
|
|
|
*)
|
|
|
|
|
|
|
|
theory StateTranslationProofs_DR
|
|
|
|
imports StateTranslation_D
|
|
|
|
begin
|
|
|
|
|
2016-05-01 00:09:19 +00:00
|
|
|
context begin interpretation Arch . (*FIXME: arch_split*)
|
|
|
|
|
2014-07-14 19:32:44 +00:00
|
|
|
declare transform_current_domain_def [simp]
|
|
|
|
|
|
|
|
lemma asid_high_bits [simp]:
|
|
|
|
"Types_D.asid_high_bits = asid_high_bits"
|
|
|
|
by (simp add:Types_D.asid_high_bits_def asid_high_bits_def)
|
|
|
|
|
|
|
|
lemma asid_low_bits [simp]:
|
|
|
|
"Types_D.asid_low_bits = asid_low_bits"
|
|
|
|
by (simp add:Types_D.asid_low_bits_def asid_low_bits_def)
|
|
|
|
|
|
|
|
lemma asid_bits [simp]:
|
|
|
|
"Types_D.asid_bits = asid_bits"
|
|
|
|
by (simp add:Types_D.asid_bits_def asid_bits_def)
|
|
|
|
|
|
|
|
lemma get_obj_simps [simp]:
|
|
|
|
"get_obj (s\<lparr>cur_thread := a\<rparr>) = get_obj s"
|
|
|
|
apply (rule ext)
|
|
|
|
apply (clarsimp simp: get_obj_def)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma transform_objects_simps [simp]:
|
|
|
|
"transform_objects (s\<lparr>cur_thread := a\<rparr>) = transform_objects s"
|
|
|
|
apply (rule ext)
|
|
|
|
apply (clarsimp simp: transform_objects_def transform_object_def)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma transform_cdt_simps [simp]:
|
|
|
|
"transform_cdt (s\<lparr>cur_thread := a\<rparr>) = transform_cdt s"
|
|
|
|
apply (rule ext)+
|
|
|
|
apply (clarsimp simp: transform_cdt_def split_def)
|
|
|
|
done
|
|
|
|
|
|
|
|
(* Aggressive simp rules, using explictly *)
|
|
|
|
abbreviation
|
|
|
|
"update_machine ms s \<equiv> machine_state_update (\<lambda>_. ms) s"
|
|
|
|
|
|
|
|
abbreviation
|
|
|
|
"update_kheap kh s \<equiv> kheap_update (\<lambda>_. kh) s"
|
|
|
|
|
|
|
|
abbreviation
|
|
|
|
"tcb_set_mi tcb msg \<equiv> tcb \<lparr>tcb_context := (tcb_context tcb)(msg_info_register := msg)\<rparr>"
|
|
|
|
|
|
|
|
abbreviation
|
|
|
|
"update_tcb_cxt_badge msg tcb\<equiv> tcb \<lparr>tcb_context := (tcb_context tcb)(badge_register := msg)\<rparr>"
|
|
|
|
|
|
|
|
abbreviation
|
|
|
|
"update_tcb_state state tcb \<equiv> tcb \<lparr>tcb_state := state\<rparr>"
|
|
|
|
|
2015-09-02 05:43:39 +00:00
|
|
|
abbreviation
|
2015-11-02 00:00:32 +00:00
|
|
|
"update_tcb_boundntfn ntfn_opt tcb \<equiv> tcb \<lparr>tcb_bound_notification := ntfn_opt\<rparr>"
|
2015-09-02 05:43:39 +00:00
|
|
|
|
2014-07-14 19:32:44 +00:00
|
|
|
abbreviation
|
|
|
|
"dupdate_cdl_object ptr obj s \<equiv> cdl_objects_update (\<lambda>_. cdl_objects s(ptr \<mapsto> obj)) s"
|
|
|
|
|
|
|
|
abbreviation
|
|
|
|
"dupdate_tcb_intent intent tcb\<equiv> tcb \<lparr>cdl_tcb_intent := intent\<rparr>"
|
|
|
|
|
2014-07-17 16:22:50 +00:00
|
|
|
lemma update_kheap_triv[simp]:
|
2014-07-14 19:32:44 +00:00
|
|
|
"kheap s y = Some obj\<Longrightarrow> update_kheap ((kheap s)(y \<mapsto> obj)) s = s"
|
|
|
|
apply (case_tac s,clarsimp)
|
|
|
|
apply (rule ext,clarsimp)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma msg_registers_lt_msg_max_length [simp]:
|
|
|
|
"length msg_registers < msg_max_length"
|
2018-10-13 01:28:22 +00:00
|
|
|
by (simp add: msg_registers_def msgRegisters_def upto_enum_def
|
|
|
|
fromEnum_def enum_register msg_max_length_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma get_tcb_mrs_update_state :
|
|
|
|
"get_tcb_mrs ms (tcb_state_update f tcb) = get_tcb_mrs ms tcb"
|
|
|
|
by (clarsimp simp:get_tcb_mrs_def Suc_le_eq get_tcb_message_info_def get_ipc_buffer_words_def)
|
|
|
|
|
|
|
|
lemma msg_info_badge_register_no_overlap:
|
|
|
|
"badge_register \<noteq> msg_info_register"
|
|
|
|
by (clarsimp simp:badge_register_def msg_info_register_def
|
2016-05-04 03:28:20 +00:00
|
|
|
ARM.badgeRegister_def
|
|
|
|
ARM.msgInfoRegister_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma badge_cap_register_overlap:
|
|
|
|
"badge_register = cap_register"
|
|
|
|
by (clarsimp simp:badge_register_def cap_register_def
|
2016-05-04 03:28:20 +00:00
|
|
|
ARM.badgeRegister_def
|
|
|
|
ARM.capRegister_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma cap_msg_info_register_no_overlap:
|
|
|
|
"cap_register \<noteq> msg_info_register"
|
|
|
|
by (clarsimp simp:msg_info_register_def cap_register_def
|
2016-05-04 03:28:20 +00:00
|
|
|
ARM.msgInfoRegister_def
|
|
|
|
ARM.capRegister_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemmas register_overlap_check = msg_info_badge_register_no_overlap
|
|
|
|
cap_msg_info_register_no_overlap
|
|
|
|
badge_cap_register_overlap
|
|
|
|
|
|
|
|
lemma transform_full_intent_cong:
|
2016-11-10 05:12:16 +00:00
|
|
|
"\<lbrakk>ms = ms'; ptr = ptr';
|
|
|
|
arch_tcb_context_get (tcb_arch tcb) = arch_tcb_context_get (tcb_arch tcb');
|
|
|
|
tcb_ipc_buffer tcb = tcb_ipc_buffer tcb'; tcb_ipcframe tcb = tcb_ipcframe tcb'\<rbrakk>
|
2014-07-14 19:32:44 +00:00
|
|
|
\<Longrightarrow> transform_full_intent ms ptr tcb = transform_full_intent ms' ptr' tcb'"
|
|
|
|
by (simp add: transform_full_intent_def get_tcb_message_info_def get_tcb_mrs_def Suc_le_eq get_ipc_buffer_words_def)
|
|
|
|
|
|
|
|
lemma caps_of_state_eq_lift:
|
2018-06-24 07:47:21 +00:00
|
|
|
"\<forall>cap. cte_wp_at ((=) cap) p s = cte_wp_at ((=) cap) p s' \<Longrightarrow> caps_of_state s p = caps_of_state s' p"
|
2014-07-14 19:32:44 +00:00
|
|
|
apply (simp add:cte_wp_at_def caps_of_state_def)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma caps_of_state_irrelavent_simp:
|
|
|
|
"ref \<noteq> epptr \<Longrightarrow> caps_of_state (update_kheap (kh(epptr \<mapsto> obj)) s) (ref, cref) = caps_of_state (update_kheap kh s) (ref, cref)"
|
|
|
|
apply (rule caps_of_state_eq_lift)
|
|
|
|
apply (clarsimp simp: cte_wp_at_cases)
|
|
|
|
done
|
|
|
|
|
|
|
|
(* This doesn't satisfy the obvious transformation into capDL because of
|
|
|
|
pagetables etc. *)
|
|
|
|
fun
|
|
|
|
caps_of_object :: "kernel_object \<Rightarrow> (bool list \<rightharpoonup> cap)"
|
|
|
|
where
|
2018-06-24 07:47:21 +00:00
|
|
|
"caps_of_object (Structures_A.CNode sz c) = (if well_formed_cnode_n sz c then c else Map.empty)"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "caps_of_object (Structures_A.TCB t) = (\<lambda>n. option_map (\<lambda>(f, _). f t) (tcb_cap_cases n))"
|
2018-06-24 07:47:21 +00:00
|
|
|
| "caps_of_object _ = Map.empty"
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma caps_of_state_def2:
|
|
|
|
"caps_of_state s = (\<lambda>ptr. case (option_map caps_of_object (kheap s (fst ptr))) of
|
|
|
|
None \<Rightarrow> None
|
|
|
|
| Some f \<Rightarrow> f (snd ptr))"
|
|
|
|
unfolding caps_of_state_def get_cap_def tcb_cnode_map_def
|
|
|
|
apply (rule ext)
|
|
|
|
apply (clarsimp simp add: split_def get_object_def bind_def gets_def get_def return_def assert_def fail_def)
|
|
|
|
apply (case_tac y, simp_all add: bind_def assert_def return_def assert_opt_def fail_def tcb_cap_cases_def
|
|
|
|
split: option.splits)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma caps_of_state_update_same_caps:
|
|
|
|
assumes kh: "kh ptr = Some ko"
|
|
|
|
and coo: "caps_of_object ko' = caps_of_object ko"
|
|
|
|
shows "caps_of_state (update_kheap (kh(ptr \<mapsto> ko')) s) = caps_of_state (update_kheap kh s)"
|
|
|
|
using kh coo
|
|
|
|
apply -
|
|
|
|
apply (rule ext)
|
|
|
|
apply (clarsimp simp add: caps_of_state_def2)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma caps_of_state_update_tcb:
|
|
|
|
"\<lbrakk> kh thread = Some (TCB tcb);
|
|
|
|
(tcb_ctable tcb) = (tcb_ctable (f tcb));
|
|
|
|
(tcb_vtable tcb) = (tcb_vtable (f tcb));
|
|
|
|
(tcb_reply tcb) = (tcb_reply (f tcb));
|
|
|
|
(tcb_caller tcb) = (tcb_caller (f tcb));
|
|
|
|
(tcb_ipcframe tcb) = (tcb_ipcframe (f tcb)) \<rbrakk>
|
|
|
|
\<Longrightarrow>
|
|
|
|
caps_of_state (update_kheap (kh(thread \<mapsto> (TCB (f tcb)))) s) =
|
|
|
|
caps_of_state (update_kheap kh s)"
|
|
|
|
apply (erule caps_of_state_update_same_caps)
|
|
|
|
apply (rule ext)
|
2016-10-25 06:01:30 +00:00
|
|
|
apply (simp add: tcb_cap_cases_def split: if_split)
|
2014-07-14 19:32:44 +00:00
|
|
|
done
|
|
|
|
|
|
|
|
lemmas caps_of_state_upds = caps_of_state_update_tcb caps_of_state_update_same_caps
|
|
|
|
|
|
|
|
lemma transform_cdt_kheap_update [simp]:
|
|
|
|
"transform_cdt (kheap_update f s) = transform_cdt s"
|
2015-05-13 07:52:32 +00:00
|
|
|
by (clarsimp simp: transform_cdt_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma transform_cdt_update_machine [simp]:
|
|
|
|
"transform_cdt (update_machine ms s) = transform_cdt s "
|
2015-05-13 07:52:32 +00:00
|
|
|
by (clarsimp simp: transform_cdt_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma transform_cdt_update_original_cap [simp]:
|
|
|
|
"transform_cdt (b\<lparr>is_original_cap := x\<rparr>) = transform_cdt b"
|
2015-05-13 07:52:32 +00:00
|
|
|
by (clarsimp simp: transform_cdt_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma transform_asid_table_kheap_update [simp]:
|
|
|
|
"transform_asid_table (kheap_update f s) = transform_asid_table s"
|
2015-05-13 07:52:32 +00:00
|
|
|
by (clarsimp simp: transform_asid_table_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma transform_asid_table_update_machine [simp]:
|
|
|
|
"transform_asid_table (update_machine ms s) = transform_asid_table s "
|
2015-05-13 07:52:32 +00:00
|
|
|
by (clarsimp simp: transform_asid_table_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma transform_asid_table_update_original_cap [simp]:
|
|
|
|
"transform_asid_table (b\<lparr>is_original_cap := x\<rparr>) = transform_asid_table b"
|
2015-05-13 07:52:32 +00:00
|
|
|
by (clarsimp simp: transform_asid_table_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma transform_objects_update_kheap_same_caps:
|
|
|
|
"\<lbrakk> kh ptr = Some ko; caps_of_object ko' = caps_of_object ko; a_type ko' = a_type ko\<rbrakk> \<Longrightarrow>
|
|
|
|
transform_objects (update_kheap (kh(ptr \<mapsto> ko')) s) =
|
|
|
|
(if ptr = idle_thread s then
|
|
|
|
transform_objects (update_kheap kh s)
|
|
|
|
else
|
|
|
|
(transform_objects (update_kheap kh s))(ptr \<mapsto> transform_object (machine_state s) ptr (ekheap s ptr) ko'))"
|
|
|
|
unfolding transform_objects_def
|
|
|
|
apply (rule ext)
|
2014-08-09 11:09:37 +00:00
|
|
|
apply (simp add: map_option_case restrict_map_def map_add_def )
|
2014-07-14 19:32:44 +00:00
|
|
|
done
|
|
|
|
|
2014-07-17 16:22:50 +00:00
|
|
|
lemma transform_objects_update_same:
|
|
|
|
"\<lbrakk> kheap s ptr = Some ko; transform_object (machine_state s) ptr (ekheap s ptr) ko = ko'; ptr \<noteq> idle_thread s \<rbrakk>
|
|
|
|
\<Longrightarrow> (transform_objects s)(ptr \<mapsto> ko') = transform_objects s"
|
|
|
|
unfolding transform_objects_def
|
|
|
|
by (rule ext) (simp)
|
|
|
|
|
2014-07-14 19:32:44 +00:00
|
|
|
text {* Facts about map_lift_over *}
|
|
|
|
|
|
|
|
lemma map_lift_over_eq_Some:
|
|
|
|
"(map_lift_over f m x = Some y)
|
|
|
|
= (\<exists>x' y'. x = f x' \<and> y = f y' \<and> inj_on f (dom m \<union> ran m)
|
|
|
|
\<and> m x' = Some y')"
|
|
|
|
proof -
|
|
|
|
have P: "inj_on f (dom m \<union> ran m) \<longrightarrow> inj_on f (dom m)"
|
|
|
|
by (auto elim: subset_inj_on)
|
|
|
|
have Q: "\<And>x y. \<lbrakk> m x = Some y; inj_on f (dom m \<union> ran m) \<rbrakk>
|
|
|
|
\<Longrightarrow> inv_into (dom m) f (f x) = x"
|
|
|
|
using P
|
|
|
|
by (blast intro: inv_into_f_f)
|
|
|
|
show ?thesis
|
|
|
|
by (auto simp add: map_lift_over_def Q)
|
|
|
|
qed
|
|
|
|
|
|
|
|
lemma map_lift_over_eq_None:
|
|
|
|
"(map_lift_over f m x = None)
|
|
|
|
= (inj_on f (dom m \<union> ran m) \<longrightarrow>
|
|
|
|
(\<forall>x'. x = f x' \<longrightarrow> m x' = None))"
|
|
|
|
proof -
|
|
|
|
have P: "inj_on f (dom m \<union> ran m) \<Longrightarrow> inj_on f (dom m)"
|
|
|
|
by (auto elim: subset_inj_on)
|
|
|
|
show ?thesis
|
|
|
|
by (auto simp add: map_lift_over_def P[THEN inv_into_f_f] domI
|
2016-01-28 03:07:42 +00:00
|
|
|
inj_on_eq_iff[where f=f]
|
2014-08-11 08:51:04 +00:00
|
|
|
| rule ccontr[where P="v = None" for v])+
|
2014-07-14 19:32:44 +00:00
|
|
|
qed
|
|
|
|
|
|
|
|
lemma map_lift_over_f_eq:
|
|
|
|
"inj_on f ({x} \<union> dom m \<union> ran m) \<Longrightarrow>
|
2014-08-09 05:16:17 +00:00
|
|
|
(map_lift_over f m (f x) = v) = (v = map_option f (m x))"
|
2014-07-14 19:32:44 +00:00
|
|
|
apply (cases v, simp_all add: map_lift_over_eq_None map_lift_over_eq_Some)
|
2014-08-13 06:45:40 +00:00
|
|
|
apply (auto simp: option_map_def split: option.split)
|
2014-07-14 19:32:44 +00:00
|
|
|
done
|
|
|
|
|
|
|
|
lemma map_lift_over_eq_cases[unfolded map_lift_over_eq_None map_lift_over_eq_Some]:
|
|
|
|
"(map_lift_over f m x = v)
|
|
|
|
= (case v of None \<Rightarrow> map_lift_over f m x = None
|
|
|
|
| Some z \<Rightarrow> map_lift_over f m x = Some z)"
|
|
|
|
by (simp split: option.split)
|
|
|
|
|
|
|
|
lemma map_lift_over_upd:
|
2014-08-09 05:16:17 +00:00
|
|
|
assumes inj_f: "inj_on f ({x} \<union> set_option y \<union> dom m \<union> ran m)"
|
2014-07-14 19:32:44 +00:00
|
|
|
shows "(map_lift_over f (m(x := y)))
|
2014-08-09 05:16:17 +00:00
|
|
|
= ((map_lift_over f m) (f x := map_option f y))"
|
2014-07-14 19:32:44 +00:00
|
|
|
proof -
|
|
|
|
have Q: "inj_on f (dom m \<union> ran m)"
|
|
|
|
"inj_on f (insert x (dom m \<union> ran (m(x := y))))"
|
|
|
|
"inj_on f (dom m)"
|
|
|
|
"inj_on f (insert x (dom m))"
|
|
|
|
"inj_on f (dom m - {x} \<union> ran (m(x := None)))"
|
|
|
|
"inj_on f (dom m - {x})"
|
|
|
|
apply (safe intro!: subset_inj_on[OF inj_f])
|
2016-10-25 06:01:30 +00:00
|
|
|
apply (auto simp: ran_def split: if_split_asm)
|
2014-07-14 19:32:44 +00:00
|
|
|
done
|
|
|
|
show ?thesis
|
|
|
|
apply (simp add: map_lift_over_def Q del: inj_on_insert)
|
2018-10-13 01:28:22 +00:00
|
|
|
apply (safe; rule ext; simp add: Q[THEN inv_into_f_f] domI cong del: imp_cong)
|
|
|
|
apply (auto simp add: Q[THEN inv_into_f_f] domI inj_on_eq_iff[OF inj_f] ranI
|
|
|
|
simp del: inj_on_insert)
|
2014-07-14 19:32:44 +00:00
|
|
|
done
|
|
|
|
qed
|
|
|
|
|
|
|
|
lemma map_lift_over_if_eq_twice:
|
2014-08-09 05:16:17 +00:00
|
|
|
assumes inj_f: "inj_on f (dom m \<union> ran m \<union> {y, y'} \<union> set_option z \<union> set_option z')"
|
2014-07-14 19:32:44 +00:00
|
|
|
shows
|
|
|
|
"map_lift_over f (\<lambda>x. if m x = Some y then z else if m x = Some y' then z' else m x)
|
2014-08-09 05:16:17 +00:00
|
|
|
= (\<lambda>x. if map_lift_over f m x = Some (f y) then map_option f z
|
|
|
|
else if map_lift_over f m x = Some (f y') then map_option f z'
|
2014-07-14 19:32:44 +00:00
|
|
|
else map_lift_over f m x)"
|
|
|
|
(is "map_lift_over f ?ifeq = ?rhs")
|
|
|
|
proof -
|
|
|
|
from inj_f
|
|
|
|
have 1: "inj_on f (dom m \<union> ran m)" "inj_on f (dom m)"
|
|
|
|
by (auto simp: inj_on_Un)
|
|
|
|
have "dom ?ifeq \<subseteq> dom m"
|
2016-10-25 06:01:30 +00:00
|
|
|
by (auto split: if_split_asm)
|
2014-07-14 19:32:44 +00:00
|
|
|
with inj_f
|
|
|
|
have 2: "inj_on f (dom ?ifeq)"
|
|
|
|
by (auto elim!: subset_inj_on)
|
2014-08-09 05:16:17 +00:00
|
|
|
have "dom ?ifeq \<union> ran ?ifeq \<subseteq> dom m \<union> ran m \<union> set_option z \<union> set_option z'"
|
2014-07-14 19:32:44 +00:00
|
|
|
by (auto simp: ran_def)
|
|
|
|
with inj_f
|
|
|
|
have "inj_on f (dom ?ifeq \<union> ran ?ifeq)"
|
|
|
|
by (auto elim!: subset_inj_on)
|
|
|
|
note Q = 1 2 this
|
2016-10-25 06:01:30 +00:00
|
|
|
note if_split[split del]
|
2014-07-14 19:32:44 +00:00
|
|
|
show ?thesis
|
|
|
|
apply (simp add: map_lift_over_def Q)
|
|
|
|
apply (rule ext)
|
|
|
|
apply (case_tac "x \<in> f ` dom ?ifeq")
|
|
|
|
apply clarsimp
|
2016-10-25 06:01:30 +00:00
|
|
|
apply (subst if_P, fastforce split: if_split_asm)+
|
2016-01-28 03:07:42 +00:00
|
|
|
apply (simp add: Q[THEN inv_into_f_f] domI ranI inj_on_eq_iff[OF inj_f]
|
2016-10-25 06:01:30 +00:00
|
|
|
split: if_split_asm)
|
2014-07-14 19:32:44 +00:00
|
|
|
apply (subst if_not_P, simp, rule allI, fastforce)+
|
2014-08-13 06:45:40 +00:00
|
|
|
apply (auto simp: option_map_def Q[THEN inv_into_f_f] domI ranI
|
2016-01-28 03:07:42 +00:00
|
|
|
inj_on_eq_iff[OF inj_f]
|
2016-10-25 06:01:30 +00:00
|
|
|
split: if_split option.split)
|
2014-07-14 19:32:44 +00:00
|
|
|
done
|
|
|
|
qed
|
|
|
|
|
|
|
|
lemma map_lift_over_if_eq:
|
2014-08-09 05:16:17 +00:00
|
|
|
assumes inj_f: "inj_on f (dom m \<union> ran m \<union> {y} \<union> set_option z)"
|
2014-07-14 19:32:44 +00:00
|
|
|
shows
|
|
|
|
"map_lift_over f (\<lambda>x. if m x = Some y then z else m x)
|
2014-08-09 05:16:17 +00:00
|
|
|
= (\<lambda>x. if map_lift_over f m x = Some (f y) then map_option f z
|
2014-07-14 19:32:44 +00:00
|
|
|
else map_lift_over f m x)"
|
|
|
|
using inj_f map_lift_over_if_eq_twice[where f=f and m=m and y=y and z=z and y'=y and z'=z]
|
|
|
|
apply (simp del: inj_on_insert)
|
|
|
|
done
|
|
|
|
|
|
|
|
end
|
2016-05-01 00:09:19 +00:00
|
|
|
|
|
|
|
end
|