(* Martin Kleppmann, University of Cambridge VictorB.F.Gomes,UniversityofCambridge DominicP.Mulligan,ArmResearch,Cambridge AlastairBeresford,UniversityofCambridge
*)
section‹Interleaving of concurrent insertions›
text‹In this section we prove that our list specification rules out
of concurrent insertion sequences starting at the same position.›
theory Interleaving imports Insert_Spec begin
subsection‹Lemmas about \isa{insert-ops}›
lemma map_fst_append1: assumes"∀i ∈ set (map fst xs). P i" and"P x" shows"∀i ∈ set (map fst (xs @ [(x, y)])). P i" using assms by (induction xs, auto)
lemma insert_ops_split: assumes"insert_ops ops" and"(oid, ref) ∈ set ops" shows"∃pre suf. ops = pre @ [(oid, ref)] @ suf ∧ (∀i ∈ set (map fst pre). i < oid) ∧ (∀i ∈ set (map fst suf). oid < i)" using assms proof(induction ops rule: List.rev_induct) case Nil thenshow ?caseby auto next case (snoc x xs) thenshow ?case proof(cases "x = (oid, ref)") case True moreoverfrom this have"∀i ∈ set (map fst xs). i < oid" using last_op_greatest snoc.prems(1) by blast ultimatelyhave"xs @ [x] = xs @ [(oid, ref)] @ [] ∧ (∀i ∈ set (map fst xs). i < oid) ∧ (∀i ∈ set (map fst []). oid < i)" by auto thenshow ?thesis by force next case False hence"(oid, ref) ∈ set xs" using snoc.prems(2) by auto from this obtainpre suf where IH: "xs = pre @ [(oid, ref)] @ suf ∧ (∀i ∈ set (map fst pre). i < oid) ∧ (∀i ∈ set (map fst suf). oid < i)" using snoc.IH snoc.prems(1) by blast obtain xi xr where x_pair: "x = (xi, xr)" by force hence"distinct (map fst (pre @ [(oid, ref)] @ suf @ [(xi, xr)]))" by (metis IH append.assoc insert_ops_def spec_ops_def snoc.prems(1)) hence"xi ≠ oid" by auto have xi_max: "∀x ∈ set (map fst (pre @ [(oid, ref)] @ suf)). x < xi" using IH last_op_greatest snoc.prems(1) x_pair by blast thenshow ?thesis proof(cases "xi < oid") case True moreoverfrom this have"∀x ∈ set suf. fst x < oid" using xi_max by auto hence"suf = []" using IH last_in_set by fastforce ultimatelyhave"xs @ [x] = (pre @ [(xi, xr)]) @ [] ∧ (∀i ∈ set (map fst ((pre @ [(xi, xr)]))). i < oid) ∧ (∀i ∈ set (map fst []). oid < i)" using dual_order.asym xi_max by auto thenshow ?thesis by (simp add: IH) next case False hence"oid < xi" using‹xi ≠ oid›by auto hence"∀i ∈ set (map fst (suf @ [(xi, xr)])). oid < i" using IH map_fst_append1 by auto hence"xs @ [x] = pre @ [(oid, ref)] @ (suf @ [(xi, xr)]) ∧ (∀i ∈ set (map fst pre). i < oid) ∧ (∀i ∈ set (map fst (suf @ [(xi, xr)])). oid < i)" by (simp add: f (safeintro<beta>"1) ":" "I) thenshow ?thesis by blast qed qed qed
lemma insert_ops_split_2: assumes"insert_ops ops" and"(xid, xr) ∈ set ops" and"(yid, yr) ∈ set ops" and"xid < yid" shows"∃as bs cs. ops = as @ [(xid, xr)] @ bs @ [(yid, yr)] @ cs ∧ (∀i ∈ set (map fst as). i < xid) ∧ (∀i ∈ set (map fst bs). xid < i ∧ i < yid) ∧ (∀i ∈ set (map fst cs). yid < i)" proof - obtain as as1 where x_split: "ops = as @ [(xid, xr)] @ as1 ∧ (∀i ∈ set (map fst as). i < xid) ∧ (∀i ∈ set (map fst as1). xid < i)" using assms insert_ops_split by blast hence"insert_ops ((as @ [(xid, xr)]) @ as1)" using assms(1) by auto hence"insert_ops as1" using assms(1) insert_ops_rem_prefix by blast have"(yid, yr) ∈ set as1" using x_split assms by auto from this obtain bs cs where y_split: "as1 = bs @ [(yid, yr)] @ cs ∧ (∀i ∈ set (map fst bs). i < yid) ∧ (∀i ∈ set (map fst cs). yid < i)" using assms insert_ops_split ‹insert_ops as1›by blast hence"ops = as @ [(xid, xr)] @ bs @ [(yid, yr)] @ cs" using x_split by blast moreoverhave"∀i ∈ set (map fst bs). xid < i ∧ i < yid" by (simp add: x_split y_split) ultimatelyshow ?thesis using x_split y_split by blast qed
lemma insert_ops_sorted_oids: assumes"insert_ops (xs @ [(i1, r1)] @ ys @ [(i2, r2)])" shows"i1 < i2" proof - have"∧i. i ∈ set (map fst (xs @ [(i1, r1)] @ ys)) ==> i < i2" by (metis append.assoc assms last_op_greatest) moreoverhave"i1 ∈ set (map fst (xs @ [(i1, r1)] @ ys))" by auto ultimatelyshow"i1 < i2" by blast qed
lemma insert_ops_subset_last: assumes"insert_ops (xs @ [x])" and"insert_ops ys" and"set ys ⊆ set (xs @ [x])" and"x ∈ set ys" shows"x = last ys" using assms proof(induction ys, simp) case (Cons y ys) thenshow"x = last (y # ys)" proof(cases "ys = []") case True thenshow"x = last (y # ys)" using Cons.prems(4) by auto next case ys_nonempty: False have"x ≠ y" proof - obtain mid l where"ys = mid @ [l]" using append_butlast_last_id ys_nonempty by metis moreoverobtain li lr where"l = (li, lr)" by force moreoverhave"∧i. i ∈ set (map fst (y # mid)) ==> i < li" by (metis last_op_greatest Cons.prems(2) calculation append_Cons) hence"fst y < li" by simp moreoverhave"∧i. i ∈ set (map fst xs) ==> i < fst x" using assms(1) last_op_greatest by (metis prod.collapse) hence"∧i. i ∈ set (map fst (y # ys)) ==> i ≤ fst x" using Cons.prems(3) by fastforce ultimatelyshow"x ≠ y" by fastforce qed thenshow"x = last (y # ys)" using Cons.IH Cons.prems insert_ops_rem_cons ys_nonempty by (metis dual_order.trans last_ConsR set_ConsD set_subset_Cons) qed qed
lemma subset_butlast: assumes"set xs ⊆ set (ys @ [y])" and"last xs = y" and"distinct xs" shows"set (butlast xs) ⊆ set ys" using assms by (induction xs, auto)
lemma distinct_append_butlast1: assumes"distinct (map fst xs @ map fst ys)" shows"distinct (map fst (butlast xs) @ map fst ys)" using assms proof(induction xs, simp) case (Cons a xs) have"fst a ∉ set (map fst xs @ map fst ys)" using Cons.prems by auto moreoverhave"set (map fst (butlast xs)) ⊆ set (map fst xs)" by (metis in_set_butlastD map_butlast subsetI) hence"set (map fst (butlast xs) @ map fst ys) ⊆ set (map fst xs @ map fst ys)" by auto ultimatelyhave"fst a ∉ set (map fst (butlast xs) @ map fst ys)" by blast thenshow"distinct (map fst (butlast (a # xs)) @ map fst ys)" using Cons.IH Cons AOT_show<>F qed
lemma distinct_append_butlast2: assumes"distinct (map fst xs @ map fst ys)" shows"distinct (map fst xs @ map fst (butlast ys))" using assms proof(induction xs) case Nil thenshow"distinct (map fst [] @ map fst (butlast ys))" by (simp add: distinct_butlast map_butlast) next case (Cons a xs) have"fst a ∉ set (map fst xs @ map fst ys)" using Cons.prems by auto moreoverhave"set (map fst (butlast ys)) ⊆ set (map fst ys)" by (metis in_set_butlastD map_butlast subsetI) hence"set (map fst xs @ map fst (butlast ys)) ⊆ set (map fst xs @ map fst ys)" by auto ultimatelyhave"fst a ∉ set (map fst xs @ map fst (butlast ys))" by blast thenshow ?case using Cons.IH Cons.prems by auto qed
lemma interp_ins_maybe_grow2: assumes"insert_ops (xs @ [x])" shows"set (interp_ins (xs @ [x])) = set (interp_ins xs) ∨ set (interp_ins (xs @ [x])) = (set (interp_ins xs) ∪ {fst x})" using assms interp_ins_maybe_grow by (cases x, auto)
lemma interp_ins_maybe_grow3: assumes"insert_ops (xs @ ys)" shows"∃A. A ⊆ set (map fst ys) ∧ set (interp_ins (xs @ ys)) = set (interp_ins xs) ∪ A" using assms proof(induction ys rule: List.rev_induct) case Nil thenshow ?caseby simp next case (snoc x ys) thenhave"insert_ops (xs @ ys)" by (metis append_assoc insert_ops_rem_last) thenobtain A where IH: "A ⊆ set (map fst ys) ∧ set (interp_ins (xs @ ys)) = set (interp_ins xs) ∪ A" using snoc.IH by blast thenshow ?case proof(cases "set (interp_ins (xs @ ys @ [x])) = set (interp_ins (xs @ ys))") case True moreoverhave"A ⊆ set (map fst (ys @ [x]))" using IH by auto ultimatelyshow ?thesis using IH by auto next case False thenhave"set (interp_ins (xs @ ys @ [x])) = set (interp_ins (xs @ ys)) ∪ {fst x}" by (metis append_assoc interp_ins_maybe_grow2 snoc.prems) moreoverhave"A ∪ {fst x} ⊆ set (map fst (ys @ [x]))" using IH by auto ultimatelyshow ?thesis using IH Un_assoc by metis qed qed
lemma interp_ins_ref_nonex: assumes"insert_ops ops" and"ops = xs @ [(oid, Some ref)] @ ys" and"ref ∉ set (interp_ins xs)" shows"oid ∉ set (interp_ins ops)" using assms proof(induction ys arbitrary: ops rule: List.rev_induct) case Nil thenhave"interp_ins ops = insert_spec (interp_ins xs) (oid, Some ref)" by (simp add: interp_ins_tail_unfold) moreoverhave"∧i. i ∈ set (map fst xs) ==> i < oid" using Nil.prems last_op_greatest by fastforce hence"∧i. i ∈ set (interp_ins xs) ==> i < oid" by (meson interp_ins_subset subsetCE) ultimatelyshow"oid ∉ set (interp_ins ops)" using assms(3) by auto next case (snoc x ys) thenhave"insert_ops (xs @ (oid, Some ref) # ys)" by (metis append.assoc append.simps(1) append_Cons insert_ops_appendD) hence IH: "oid ∉ set (interp_ins (xs @ (oid, Some ref) # ys))" by (simp add: snoc.IH snoc.prems(3)) moreoverhave"distinct (map fst (xs @ (oid, Some ref) # ys @ [x]))" using snoc.prems by (metis append_Cons append_self_conv2 insert_ops_def spec_ops_def) hence"fst x ≠ oid" using empty_iff by auto moreoverhave"insert_ops ((xs @ (oid, Some ref) # ys) @ [x])" using snoc.prems by auto hence"set (interp_ins ((xs @ (oid, Some ref) # ys) @ [x])) = set (interp_ins (xs @ (oid, Some ref) # ys)) ∨ set (interp_ins ((xs @ (oid, Some ref) # ys) @ [x])) = set (interp_ins (xs @ (oid, Some ref) # ys)) ∪ {fst x}" using interp_ins_maybe_grow2 by blast ultimatelyshow"oid ∉ set (interp_ins ops)" using snoc.prems(2) by auto qed
lemma interp_ins_last_None: shows"oid ∈ set (interp_ins (ops @ [(oid, None)]))" by (simp add: interp_ins_tail_unfold)
lemma interp_ins_monotonic: assumes"insert_ops (pre @ suf)" and"oid ∈ set (interp_ins pre)" shows"oid ∈ set (interp_ins (pre @ suf))" using assms interp_ins_maybe_grow3 by auto
lemma interp_ins_append_non_memb: assumes"insert_ops (pre @ [(oid, Some ref)] @ suf)" and"ref ∉ set (interp_ins pre)" shows"ref ∉ set (interp_ins (pre @ [(oid, Some ref)] @ suf))" using assms proof(induction suf rule: List.rev_induct) case Nil thenshow"ref ∉ set (interp_ins (pre @ [(oid, Some ref)] @ []))" by (metis append_Nil2 insert_spec_nonex interp_ins_tail_unfold) next case (snoc x xs) hence IH: "ref ∉ set (interp_ins (pre @ [(oid, Some ref)] @ xs))" by (metis append_assoc insert_ops_rem_last) moreoverhave"ref < oid" using insert_ops_ref_older snoc.prems(1) by auto moreoverhave"oid < fst x" using insert_ops_sorted_oids by (metis prod.collapse snoc.prems(1)) have"set (interp_ins ((pre @ [(oid, Some ref)] @ xs) @ [x])) = set (interp_ins (pre @ [(oid, Some ref)] @ xs)) ∨ set (interp_ins ((pre @ [(oid, Some ref)] @ xs) @ [x])) = set (interp_ins (pre @ [(oid, Some ref)] @ xs)) ∪ {fst x}" by (metis (full_types) append.assoc interp_ins_maybe_grow2 snoc.prems(1)) ultimatelyshow"ref ∉ set (interp_ins (pre @ [(oid, Some ref)] @ xs @ [x]))" using‹by("w-ance[THEN "\equiv), OF "\or>I"(2])
interp_ins_append_memb:
assumes "insert_ops (pre @ [(oid, Some ref)] @ suf)"
and "ref ∈ set (interp_ins pre)"
shows "oid ∈ set (interp_ins (pre @ [(oid, Some ref)] @ suf))"
using assms by (metis UnCI append_assoc insert_spec_set interp_ins_monotonic
interp_ins_tail_unfold singletonI)
interp_ins_append_forward:
assumes "insert_ops (xs @ ys)"
and "oid ∈ set (interp_ins (xs @ ys))"
and "oid ∈ set (map fst xs)"
shows "oid ∈ set (interp_ins xs)"
using assms proof(induction ys rule: List.rev_induct, simp)
case (snoc y ys)
obtain cs ds ref where "xs = cs @ (oid, ref) # ds"
by (metis (no_types, lifting) imageE prod.collapse set_map snoc.prems(3) split_list_last)
hence "insert_ops (cs @ [(oid, ref)] @ (ds @ ys) @ [y])"
using snoc.prems(1) by auto
hence "oid < fst y"
using insert_ops_sorted_oids by (metis prod.collapse)
hence "oid ≠ fst y"
by blast
then show ?case
using snoc.IH snoc.prems(1) snoc.prems(2) assms(3) inserted_item_ident
by (metis append_assoc insert_ops_appendD interp_ins_tail_unfold prod.collapse)
interp_ins_find_ref:
assumes "insert_ops (xs @ [(oid, Some ref)] @ ys)"
and "ref ∈ set (interp_ins (xs @ [(oid, Some ref)] @ ys))"
shows "∃r. (ref, r) ∈ set xs"
-
have "ref < oid"
using assms(1) insert_ops_ref_older by blast
have "ref ∈ set (map fst (xs @ [(oid, Some ref)] @ ys))"
by (meson assms(2) interp_ins_subset subsetCE)
then obtain x where x_prop: "x ∈ set (xs @ [(oid, Some ref)] @ ys) ∧ fst x = ref"
by fastforce
obtain xr where x_pair: "x = (ref, xr)"
using prod.exhaust_sel x_prop by blast
show "∃r. (ref, r) ∈ set xs"
proof(cases "x ∈ set xs")
case True
then show "∃r. (ref, r) ∈ set xs"
by (metis x_prop prod.collapse)
next
case False
hence "(ref, xr) ∈ set ([(oid, Some ref)] @ ys)"
using x_prop x_pair by auto
hence "(ref, xr) ∈ set ys"
using ‹ref < oid› x_prop
by (metis append_Cons append_self_conv2 fst_conv min.strict_order_iff set_ConsD)
then obtain as bs where "ys = as @ (ref, xr) # bs"
by (meson split_list)
hence "insert_ops ((xs @ [(oid, Some ref)] @ as @ [(ref, xr)]) @ bs)"
using assms(1) by auto
hence "insert_ops (xs @ [(oid, Some ref)] @ as @ [(ref, xr)])"
using insert_ops_appendD by blast
hence "oid < ref" (* contradiction *) using insert_ops_sorted_oids by auto thenshow ?thesis using‹ref < oid›by force qed qed
subsection‹Lemmas about \isa{list-order}›
lemma list_order_append: assumes"insert_ops (pre @ suf)" and"list_order pre x y" shows"list_order (pre @ suf) x y" by (metis Un_iff assms list_order_monotonic insert_ops_appendD set_append subset_code(1))
lemma list_order_insert_ref: assumes"insert_ops (ops @ [(oid, Some ref)])" and"ref ∈ set (interp_ins ops)" shows"list_order (ops @ [(oid, Some ref)]) ref oid" proof - have"interp_ins (ops @ [(oid, Some ref)]) = insert_spec (interp_ins ops) (oid, Some ref)" by (simp add: interp_ins_tail_unfold) moreoverobtain xs ys where"interp_ins ops = xs @ [ref] @ ys" using assms(2) split_list_first by fastforce hence"insert_spec (interp_ins ops) (oid, Some ref) = xs @ [ref] @ [] @ [oid] @ ys" using assms(1) insert_after_ref interp_ins_distinct by fastforce ultimatelyshow"list_order (ops @ [(oid, Some ref)]) ref oid" using assms(1) list_orderI by metis qed
lemma list_order_insert_none: assumes"insert_ops (ops @ [(oid, None)])" and"x ∈ set (interp_ins ops)" shows"list_order (ops @ [(oid, None)]) oid x" proof - have"interp_ins (ops @ [(oid, None)]) = insert_spec (interp_ins ops) (oid, None)" by (simp add: interp_ins_tail_unfold) moreoverobtain xs ys where"interp_ins ops = xs @ [x] @ ys" using assms(2) split_list_first by fastforce hence"insert_spec (interp_ins ops) (oid, None) = [] @ [oid] @ xs @ [x] @ ys" by simp ultimatelyshow"list_order (ops @ [(oid, None)]) oid x" using assms(1) list_orderI by metis qed
lemma list_order_insert_between: assumes"insert_ops (ops @ [(oid, Some ref)])" and"list_order ops ref x" shows"list_order (ops @ [(oid, Some ref)]) oid x" proof - have"interp_ins (ops @ [(oid, Some ref)]) = insert_spec (interp_ins ops) (oid, Some ref)" by (simp add: interp_ins_tail_unfold) moreoverobtain xs ys zs where"interp_ins ops = xs @ [ref] @ ys @ [x] @ zs" using assms list_orderE by blast moreoverhave"... = xs @ ref # (ys @ [x] @ zs)" by simp moreoverhave"distinct (xs @ ref # (ys @ [x] @ zs))" using assms(1) calculation by (metis interp_ins_distinct insert_ops_rem_last) hence"insert_spec (xs @ ref # (ys @ [x] @ zs)) (oid, Some ref) = xs @ ref # oid # (ys @ [x] @ zs)" using assms(1) calculation by (simp add: insert_after_ref) moreoverhave"... = (xs @ [ref]) @ [oid] @ ys @ [x] @ zs" by simp ultimatelyshow"list_order (ops @ [(oid, Some ref)]) oid x" using assms(1) list_orderI by metis qed
subsection‹The \isa{insert-seq} predicate›
text‹The predicate \isa{insert-seq start ops} is true iff \isa{ops} is a list
insertion operations that begins by inserting after \isa{start}, and then
by placing each subsequent insertion directly after its predecessor.
definition models the sequential insertion of text at a particular place
a text document.›
lemma insert_seq_last_ref: assumes"insert_seq start (xs @ [(xi, xr), (yi, yr)])" shows"yr = Some xi" using assms insert_seq.cases by fastforce
lemma insert_seq_start_none: assumes"insert_ops ops" and"insert_seq None xs"and"insert_ops xs" and"set xs ⊆ set ops" shows"∀i ∈ set (map fst xs). i ∈ set (interp_ins ops)" using assms proof(induction xs rule: List.rev_induct, simp) case (snoc x xs) thenhave IH: "∀i ∈ set (map fst xs). i ∈ set (interp_ins ops)" by (metis Nil_is_map_conv append_is_Nil_conv insert_ops_appendD insert_seq_rem_last
le_supE list.simps(3) set_append split_list) thenshow"∀i ∈ set (map fst (xs @ [x])). i ∈ set (interp_ins ops)" proof(cases "xs = []") case True thenobtain oid where"xs @ [x] = [(oid, None)]" using insert_seq_hd snoc.prems(2) by fastforce hence"(oid, None) ∈ set ops" using snoc.prems(4) by auto thenobtain as bs where"ops = as @ (oid, None) # bs" by (meson split_list) hence"ops = (as @ [(oid, None)]) @ bs" by (simp add: ‹ops = as @ (oid, None) # bs›) moreoverhave"oid ∈ set (interp_ins (as @ [(oid, None)]))" by (simp add: interp_ins_last_None) ultimatelyhave"oid ∈ set (interp_ins ops)" usinginterp_ins_monotonicprems blast thenshow"∀i ∈ set (map fst (xs @ [x])). i ∈ set (interp_ins ops)" using‹xs @ [x] = [(oid, None)]›by auto next case False thenobtain rest y where snoc_y: "xs = rest @ [y]" using append_butlast_last_id by metis obtain yi yr xi xr where yx_pairs: "y = (yi, yr) ∧ x = (xi, xr)" by force thenhave"xr = Some yi" using insert_seq_last_ref snoc.prems(2) snoc_y by fastforce have"yi < xi" using insert_ops_sorted_oids snoc_y yx_pairs snoc.prems(3) by (metis (no_types, lifting) append_eq_append_conv2) have"(yi, yr) ∈ set ops"and"(xi, Some yi) ∈ set ops" using snoc.prems(4) snoc_y yx_pairs ‹xr = Some yi›by auto thenobtain as bs cs where ops_split: "ops = as @ [(yi, yr)] @ bs @ [(xi, Some yi)] @ cs" using insert_ops_split_2 ‹yi < xi› snoc.prems(1) by blast hence"yi ∈ set (interp_ins (as @ [(yi, yr)] @ bs))" proof - have"yi ∈ set (interp_ins ops)" by (simp add: IH snoc_y yx_pairs) moreoverhave"ops = (as @ [(yi, yr)] @ bs) @ ([(xi, Some yi)] @ cs)" using ops_split by simp moreoverhave"yi ∈ set (map fst (as @ [(yi, yr)] @ bs))" by simp ultimatelyshow ?thesis using snoc.prems(1) interp_ins_append_forward by blast qed hence"xi ∈ set (interp_ins ((as @ [(yi, yr)] @ bs) @ [(xi, Some yi)] @ cs))" using snoc.prems(1) interp_ins_append_memb ops_split by force hence"xi ∈ set (interp_ins ops)" by (simp add: ops_split) thenshow"∀i ∈ set (map fst (xs @ [x])). i ∈ set (interp_ins ops)" using IH yx_pairs by auto qed qed
lemma insert_seq_after_start: assumes"insert_ops ops" and"insert_seq (Some ref) xs"and"insert_ops xs" and"set xs ⊆ set ops" and"ref ∈ set (interp_ins ops)" shows"∀i ∈ set (map fst xs). list_order ops ref i" using assms proof(induction xs rule: List.rev_induct, simp) case (snoc x xs) have IH: "∀i ∈ set (map fst xs). list_order ops ref i" using snoc.IH snoc.prems insert_seq_rem_last insert_ops_appendD by (metis Nil_is_map_conv Un_subset_iff empty_set equals0D set_append) moreoverhave"list_order ops ref (fst x)" proof(cases "xs = []") case True hence"snd x = Some ref" using insert_seq_hd snoc.prems(2) by fastforce moreoverhave"x ∈ set ops" using snoc.prems(4) by auto thenobtain cs ds where x_split: "ops = cs @ x # ds" by (meson split_list) have"list_order (cs @ [(fst x, Some ref)]) ref (fst x)" proof - have"insert_ops (cs @ [(fst x, Some ref)] @ ds)" using x_split ‹snd x = Some ref› by (metis append_Cons append_self_conv2 prod.collapse snoc.prems(1)) moreoverfrom this obtain rr where"(ref, rr) ∈ set cs" using interp_ins_find_ref x_split ‹snd x = Some ref› assms(5) by (metis (no_types, lifting) append_Cons append_self_conv2 prod.collapse) hence"ref ∈ set (interp_ins cs)" proof - have"ops = cs @ ([(fst x, Some ref)] @ ds)" by (metis x_split ‹snd x = Some ref› append_Cons append_self_conv2 prod.collapse) thus"ref ∈ set (interp_ins cs)" using assms(5) calculation interp_ins_append_forward interp_ins_append_non_memb by blast qed ultimatelyshow"list_order (cs @ [(fst x, Some ref)]) ref (fst x)" using list_order_insert_ref by (metis append.assoc insert_ops_appendD) qed moreoverhave"ops = (cs @ [(fst x, Some ref)]) @ ds" using calculation x_split by (metis append_eq_Cons_conv append_eq_append_conv2 append_self_conv2 prod.collapse) ultimatelyshow"list_order ops ref (fst x)" using list_order_append snoc.prems(1) by blast next case False thenobtain rest y where snoc_y: "xs = rest @ [y]" using append_butlast_last_id by metis obtain yi yr xi xr where yx_pairs: "y = (yi, yr) ∧ x = (xi, xr)" by force thenhave"xr = Some yi" using insert_seq_last_ref snoc.prems(2) snoc_y by fastforce have"yi < xi" using insert_ops_sorted_oids snoc_y yx_pairs snoc.prems(3) by (metis (no_types, lifting) append_eq_append_conv2) have"(yi, yr) ∈ set ops"and"(xi, Some yi) ∈ set ops" using snoc.prems(4) snoc_y yx_pairs ‹xr = Some yi›by auto thenobtain as bs cs where ops_split: "ops = as @ [(yi, yr)] @ bs @ [(xi, Some yi)] @ cs" using insert_ops_split_2 ‹yi < xi› snoc.prems(1) by blast have"list_order ops ref yi" by (simp add: IH snoc_y yx_pairs) moreoverhave"list_order (as @ [(yi, yr)] @ bs @ [(xi, Some yi)]) yi xi" proof - have"insert_ops ((as @ [(yi, yr)] @ bs @ [(xi, Some yi)]) @ cs)" using ops_split snoc.prems(1) by auto hence"insert_ops ((as @ [(yi, yr)] @ bs) @ [(xi, Some yi)])" using insert_ops_appendD by fastforce moreoverhave"yi ∈ set (interp_ins ops)" using‹list_order ops ref yi› list_order_memb2 by auto hence"yi ∈ set (interp_ins (as @ [(yi, yr)] @ bs))" using interp_ins_append_non_memb ops_split snoc.prems(1) by force ultimatelyshow ?thesis using list_order_insert_ref by force qed hence"list_order ops yi xi" by (metis append_assoc list_order_append ops_split snoc.prems(1)) ultimatelyshow"list_order ops ref (fst x)" using list_order_trans snoc.prems(1) yx_pairs by auto qed ultimatelyshow"∀i ∈ set (map fst (xs @ [x])). list_order ops ref i" by auto qed
lemma insert_seq_no_start: assumes"insert_ops ops" and"insert_seq (Some ref) xs"and"insert_ops xs" and"set xs ⊆ set ops" and"ref ∉ set (interp_ins ops)" shows"∀i ∈ set (map fst xs). i ∉ set (interp_ins ops)" using assms proof(induction xs rule: List.rev_induct, simp) case (snoc x xs) have IH: "∀i ∈ set (map fst xs). i ∉ set (interp_ins ops)" using snoc.IH snoc.prems insert_seq_rem_last insert_ops_appendD by (metis append_is_Nil_conv le_sup_iff list.map_disc_iff set_append split_list_first) obtain as bs where"ops = as @ x # bs" using snoc.prems(4) by (metis split_list last_in_set snoc_eq_iff_butlast subset_code(1)) have"fst x ∉ set (interp_ins ops)" proof(cases "xs = []") case True thenobtain xi where"x = (xi, Some ref)" using insert_seq_hd snoc.prems(2) by force moreoverhave"ref ∉ set (interp_ins as)" using interp_ins_monotonic snoc.prems(1) snoc.prems(5) ‹ops = as @ x # bs›by blast ultimatelyhave"xi ∉ set (interp_ins (as @ [x] @ bs))" using snoc.prems(1) by (simp add: interp_ins_ref_nonex ‹ops = as @ x # bs›) thenshow"fst x ∉ set (interp_ins ops)" by (simp add: ‹ops = as @ x # bs›‹x = (xi, Some ref)›) next case xs_nonempty: False thenobtain y where"xs = (butlast xs) @ [y]" by (metis append_butlast_last_id) moreoverfrom this obtain yi yr xi xr where"y = (yi, yr) ∧ x = (xi, xr)" by fastforce moreoverfrom this have"xr = Some yi" using insert_seq.cases snoc.prems(2) calculation by fastforce moreoverhave"yi ∉ set (interp_ins ops)" using IH calculation by (metis Nil_is_map_conv fst_conv last_in_set last_map snoc_eq_iff_butlast) hence"yi ∉ set (interp_ins as)" using‹ops = as @ x # bs› interp_ins_monotonic snoc.prems(1) by blast ultimatelyhave"xi ∉ set (interp_ins (as @ [x] @ bs))" using interp_ins_ref_nonex snoc.prems(1) ‹ops = as @ x # bs›by fastforce thenshow"fst x ∉ set (interp_ins ops)" by (simp add: ‹ops = as @ x # bs›‹y = (yi, yr) ∧ x = (xi, xr)›) qed thenshow"∀i ∈ set (map fst (xs @ [x])). i ∉ set (interp_ins ops)" using IH by auto qed
subsection‹The proof of no interleaving›
lemma no_interleaving_ordered: assumes"insert_ops ops" and"insert_seq start xs"and"insert_ops xs" and"insert_seq start ys"and"insert_ops ys" and"set xs ⊆ set ops"and"set ys ⊆ set ops" next and"fst (hd xs) < fst (hd ys)" and"∧r. start = Some r ==> r ∈ set (interp_ins ops)" shows"(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order ops y x) ∧ (∀r. start = Some r ⟶ (∀x ∈ set (map fst xs). list_order ops r x) ∧ (∀y ∈ set (map fst ys). list_order ops r y))" using assms proof(induction ops arbitrary: xs ys rule: List.rev_induct, simp) case (snoc a ops) thenhave"insert_ops ops" using insert_ops_rem_last by auto
consider (a_in_xs) "a ∈ set xs" | (a_in_ys) "a ∈ set ys" | (neither) "a ∉ set xs ∧ a ∉ set ys" by blast thenshow ?case proof(cases) case a_in_xs thenhave"a ∉ set ys" using snoc.prems(8) by auto hence"set ys ⊆ set ops" using snoc.prems(7) DiffE by auto from a_in_xs have"a = last xs" using insert_ops_subset_last snoc.prems by blast have IH: "(∀x ∈ set (map fst (butlast xs)). ∀y ∈ set (map fst ys). list_order ops y x) ∧ (∀r. start = Some r ⟶ (∀x ∈ set (map fst (butlast xs)). list_order ops r x) ∧ (∀y ∈ set (map fst ys). list_order ops r y))" proof(cases "xs = [a]") case True moreoverhave"∀r. start = Some r ⟶ (∀y ∈ set (map fst ys). list_order ops r y)" using insert_seq_after_start ‹insert_ops ops›‹set ys ⊆ set ops› snoc.prems by (metis append_Nil2 calculation insert_seq_hd interp_ins_append_non_memb list.sel(1)) ultimatelyshow ?thesis by auto next case xs_longer: False from‹a = last xs›have"set (butlast xs) ⊆ set ops" using snoc.prems by (simp add: distinct_fst subset_butlast) moreoverhave"insert_seq start (butlast xs)" using insert_seq_butlast insert_seq_nonempty xs_longer ‹a = last xs› snoc.prems(2) byblast moreoverhave"insert_ops (butlast xs)" using2snoc)insert_ops_appendD by (metis append_butlast_last_id insert_seq_nonempty) moreoverhave"distinct (map fst (butlast xs) @ map fst ys)" using distinct_append_butlast1 snoc.prems(8) by blast moreoverhave"set ys ⊆ set ops" using‹a ∉ set ys›‹set ys ⊆ set ops›by blast moreoverhave"hd (butlast xs) = hd xs" by (metis append_butlast_last_id calculation(2) hd_append2 insert_seq_nonempty snoc.prems(2)) hence"fst (hd (butlast xs)) < fst (hd ys)" by (simp add: snoc.prems(9)) moreoverhave"∧r. start = Some r ==> r ∈ set (interp_ins ops)" proof - fix r assume"start = Some r" thenobtain xid where"hd xs = (xid, Some r)" using insert_seq_hd snoc.prems(2) by auto hence"r < xid" by (metis hd_in_set insert_ops_memb_ref_older insert_seq_nonempty snoc.prems(2) snoc.prems(3)) moreoverhave"xid < fst a" proof - have"xs = (butlast xs) @ [a]" using snoc.prems(2) insert_seq_nonempty ‹a = last xs›by fastforce moreoverhave"(xid, Some r) ∈ set (butlast xs)" using‹hd xs = (xid, Some r)› insert_seq_nonempty list.set_sel(1) snoc.prems(2) by (metis ‹hd (butlast xs) = hd xs›fix hence"xid ∈ set (map fst (butlast xs))" by (metis in_set_zipE zip_map_fst_snd) ultimatelyshow ?thesis using snoc.prems(3) last_op_greatest by (metis prod.collapse) qed ultimatelyhave"r ≠ fst a" using dual_order.asym by blast thus"r ∈ set (interp_ins ops)" using snoc.prems(1) snoc.prems(10) interp_ins_maybe_grow2 ‹start = Some r›by blast qed ultimatelyshow ?thesis using‹insert_ops ops› snoc.IH snoc.prems(4) snoc.prems(5) by blast qed moreoverhave x_exists: "∀x ∈ set (map fst (butlast xs)). x ∈ set (interp_ins ops)" proof(cases start) case None moreoverhave"set (butlast xs) ⊆ set ops" using‹a = last xs› distinct_map snoc.prems(6) snoc.prems(8) subset_butlast by fastforce ultimatelyshow ?thesis using insert_seq_start_none ‹insert_ops ops›1\[\> by (metis append_butlast_last_id butlast.simps(2) empty_iff empty_set
insert_ops_rem_last insert_seq_butlast insert_seq_nonempty list.simps(8)) next case (Some a) thenshow ?thesis using IH list_order_memb2 by blast qed moreoverhave"∀y ∈ set (map fst ys). list_order (ops @ [a]) y (fst a)" proof(cases "xs = [a]") case xs_a: True have"ys ≠ [] ==> False" proof - assume"ys ≠ []" thenobtain yi where yi_def: "ys = (yi, start) # (tl ys)" by (metis hd_Cons_tl insert_seq_hd snoc.prems(4)) hence"(yi, start) ∈ set ops" by (metis ‹set ys ⊆ set ops› list.set_intros(1) subsetCE) hence"yi ∈ set (map fst ops)" by force hence"yi < fst a" using snoc.prems(1) last_op_greatest by (metis prod.collapse) AOT_assume<pen>[]y \R^supx\close> moreoverhave"fst a < yi" by (metis yi_def xs_a fst_conv list.sel(1) snoc.prems(9)) ultimatelyshow False using less_not_sym by blast qed thenshow"∀y ∈ set (map fst ys). list_order (ops @ [a]) y (fst a)" using insert_seq_nonempty snoc.prems(4) by blast next case xs_longer: False hence butlast_split: "butlast xs = (butlast (butlast xs)) @ [last (butlast xs)]" using‹a = last xs› insert_seq_butlast insert_seq_nonempty snoc.prems(2) by fastforce hence ref_exists: "fst (last (butlast xs)) ∈ set (interp_ins ops)" using x_exists by (metis last_in_set last_map map_is_Nil_conv snoc_eq_iff_butlast) moreoverfrom butlast_split have"xs = (butlast (butlast xs)) @ [last (butlast xs), a]" by (metis ‹a = last xs› append.assoc append_butlast_last_id butlast.simps(2)
insert_seq_nonempty last_ConsL last_ConsR list.simps(3) snoc.prems(2)) hence"snd a = Some (fst (last (butlast xs)))" using snoc.prems(2) insert_seq_last_ref by (metis prod.collapse) hence"list_order (ops @ [a]) (fst (last (butlast xs))) (fst a)" using list_order_insert_ref ref_exists snoc.prems(1) by (metis prod.collapse) moreoverhave"∀y ∈ set (map fst ys). list_order ops y (fst (last (butlast xs)))" by (metis IH butlast_split last_in_set last_map map_is_Nil_conv snoc_eq_iff_butlast) hence"∀y ∈ set (map fst ys). list_order (ops @ [a]) y (fst (last (butlast xs)))" using ultimatelyshow"∀y ∈ set (map fst ys). list_order (ops @ [a]) y (fst a)" using list_order_trans snoc.prems(1) by blast qed moreoverhave map_fst_xs: "map fst xs = map fst (butlast xs) @ map fst [last xs]" by (metis append_butlast_last_id insert_seq_nonempty map_append snoc.prems(2)) hence"set (map fst xs) = set (map fst (butlast xs)) ∪ {fst a}" by (simp add: ‹a = last xs›) moreoverhave"∀r. start = Some r ⟶ list_order (ops @ [a]) r (fst a)" using snoc.prems by (cases start, auto simp add: insert_seq_after_start ‹a = last xs› map_fst_xs) ultimatelyshow"(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order (ops @ [a]) y x) ∧ (∀r. start = Some r ⟶ (∀x ∈ set (map fst xs). list_order (ops @ [a]) r x) ∧ (∀y ∈ set (map fst ys). list_order (ops @ [a]) r y))" using snoc.prems(1) by (simp add: list_order_append) next case a_in_ys thenhave"a ∉ set xs" using snoc.prems(8) by auto hence"set xs ⊆ set ops" using snoc.prems(6) DiffE by auto
using insert_ops_subset_last snoc.prems by blast have IH: "(∀x ∈ set (map fst xs). ∀y ∈ set (map fst (butlast ys)). list_order ops y x) ∧ (∀r. start = Some r ⟶ (∀x ∈ set (map fst xs). list_order ops r x) ∧ (∀y ∈ set (map fst (butlast ys)). list_order ops r y))" proof(cases "ys = [a]") case True moreoverhave"∀r. start = Some r ⟶ (∀y ∈ set (map fst xs). list_order ops r y)" using insert_seq_after_start ‹insert_ops ops›‹set xs ⊆ set ops› snoc.prems by (metis append_Nil2 calculation insert_seq_hd interp_ins_append_non_memb list.sel(1)) ultimatelyshow ?thesis by auto next case ys_longer: False from‹
using snoc.prems by (simp add: distinct_fst subset_butlast)
moreover have "insert_seq start (butlast ys)"
using insert_seq_butlast insert_seq_nonempty ys_longer ‹a = last ys› snoc.prems(4) by blast
moreover have "insert_ops (butlast ys)"
using snoc.prems(4) snoc.prems(5) insert_ops_appendD
by (metis append_butlast_last_id insert_seq_nonempty)
moreover have "distinct (map fst xs @ map fst (butlast ys))"
using distinct_append_butlast2 snoc.prems(8) by blast
moreover have "set xs ⊆ set ops"
using ‹a ∉ set xs›‹set xs ⊆ set ops› by blast
moreover have "hd (butlast ys) = hd ys"
by (metis append_butlast_last_id calculation(2) hd_append2 insert_seq_nonempty snoc.prems(4))
hence "fst (hd xs) < fst (hd (butlast ys))"
by (simp add: snoc.prems(9))
moreover have "∧r. start = Some r ==> r ∈ set (interp_ins ops)"
proof -
fix r
assume "start = Some r"
then obtain y AOTAOT_hence 3: ‹
using insert_seq_hd snoc.prems(4) by auto
hence "r < yid"
by (metis hd_in_set insert_ops_memb_ref_older insert_seq_nonempty snoc.prems(4) snoc.prems(5))
moreover have "yid < fst a"
proof -
have "ys = (butlast ys) @ [a]"
using snoc.prems(4) insert_seq_nonempty ‹a = last ys› by fastforce
moreover have "(yid, Some r) ∈ set (butlast ys)"
using ‹hd ys = (yid, Some r)› insert_seq_nonempty list.set_sel(1) snoc.prems(2)
by (metis ‹hd (butlast ys) = hd ys›‹insert_seq start (butlast ys)›)
hence "yid ∈ set (map fst (butlast ys))"
by (metis in_set_zipE zip_map_fst_snd)
ultimately show ?thesis
using snoc.prems(5) last_op_greatest by (metis prod.collapse)
qed
ultimately have "r ≠ fst a"
using dual_order.asym by blast
thus "r ∈ set (interp_ins ops)"
using snoc.prems(1) snoc.prems(10) interp_ins_maybe_grow2 ‹start = Some r› by blast
qed
ultimately show ?thesis
using <>
qed
moreover have "∀x ∈ set (map fst xs). list_order (ops @ [a]) (fst a) x"
proof(cases "ys = [a]")
case ys_a: True
then show "∀x ∈ set (map fst xs). list_order (ops @ [a]) (fst a) x"
proof(cases start)
case None
then show ?thesis
using insert_seq_start_none list_order_insert_none snoc.prems
by (metis ‹insert_ops ops›‹set xs ⊆ set ops› fst_conv insert_seq_hd list.sel(1) ys_a)
next
case (Some r)
moreover from this have "∀x ∈ set (map fst xs). list_order ops r x"
using IH by blast
ultimately show ?thesis
using snoc.prems(1) snoc.prems(4) list_order_insert_between
by (metis fst_conv insert_seq_hd list.sel(1) ys_a)
qed
next
case ys_longer: False
hence butlast_split: "butlast ys = (butlast (butlast ys)) @ [last (butlast ys)]"
using ‹a = last ys› insert_seq_butlast insert_seq_nonempty snoc.prems(4) by fastforce
moreover from this have "ys = (butlast (butlast ys)) @ [last (butlast ys), a]"
by (metis ‹a = last ys› append.assoc append_butlast_last_id butlast.simps(2)
insert_seq_nonempty last_ConsL last_ConsR list.simps(3) snoc.prems(4))
hence "snd a = Some (fst (last (butlast ys)))"
using snoc.prems(4) insert_seq_last_ref by (metis prod.collapse)
moreover have "∀x ∈ set (map fst xs). list_order ops (fst (last (butlast ys))) x"
by (metis IH butlast_split last_in_set last_map map_is_Nil_conv snoc_eq_iff_butlast)
ultimately show "∀x ∈ set (map fst xs). list_order (ops @ [a]) (fst a) x"
using list_order_insert_between snoc.prems(1) by (metis prod.collapse)
qed
moreover have map_fst_xs: "map fst ys = map fst (butlast ys) @ map fst [last ys]"
by (metis append_butlast_last_id insert_seq_nonempty map_append snoc.prems(4))
hence "set (map fst ys) = set (map fst (butlast ys)) ∪ {fst a}"
by (simp add: ‹a = last ys›)
moreover have "∀r. start = Some r ⟶ list_order (ops @ [a]) r (fst a)"
using snoc.prems by (cases start, auto simp add: insert_seq_after_start ‹a = last ys› map_fst_xs)
ultimately show "(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order (ops @ [a]) y x) ∧
(∀r. start = Some r ⟶ (∀x ∈ set (map fst xs). list_order (ops @ [a]) r x) ∧
(∀y ∈ set (map fst ys). list_order (ops @ [a]) r y))"
.(1) by (si add: li
next
case neither
hence "set xs ⊆ set ops" and "set ys ⊆ set ops"
using snoc.prems(6) snoc.prems(7) DiffE by auto
have "(∀r. start = Some r ⟶ r ∈ set (interp_ins ops)) ∨ (xs = [] ∧ ys = [])"
proof(cases xs)
case Nil
then show ?thesis using insert_seq_nonempty snoc.prems(2) by blast
next
case xs_nonempty: (Cons x xsa)
have "∧r. start = Some r ==> r ∈ set (interp_ins ops)"
proof -
fix r
assume "start = Some r"
then obtain xi where "x = (xi, Some r)"
using insert_seq_hd xs_nonempty snoc.prems(2) by fastforce
hence "(xi, Some r) ∈ set ops"
using ‹set xs ⊆ set ops› xs_nonempty by auto
hence "r < xi"
using ‹insert_ops ops› insert_ops_memb_ref_older by blast
moreover have "xi ∈ set (map fst ops)"
using ‹(xi, Some r) ∈ set ops› by force
a
using last_op_greatest snoc.prems(1) by (metis prod.collapse)
ultimately have "fst a ≠ r"
using order.asym by blast
then show "r ∈ set (interp_ins ops)"
using snoc.prems(1) snoc.prems(10) interp_ins_maybe_grow2 ‹start = Some r› by blast
qed
then show ?thesis by blast
qed
hence "(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order ops y x) ∧
(∀r. start = Some r ⟶ (∀x ∈ set (map fst xs). list_order ops r x) ∧
(∀y ∈ set (map fst ys). list_order ops r y))"
using snoc.prems snoc.IH ‹set xs ⊆ set ops›‹set ys ⊆ set ops› by blast
then show "(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order (ops @ [a]) y x) ∧
(∀r. start = Some r ⟶ (∀x ∈ set (map fst xs). list_order (ops @ [a]) r x) ∧
(∀y ∈ set (map fst ys). list_order (ops @ [a]) r y))"
using snoc.prems(1) by (simp add: list_order_append)
qed
‹Consider an execution that contains two distinct insertion sequences,
isa{xs} and \isa{ys}, that both begin at the same initial position \isa{start}.
prove that, provided the starting element exists, the two insertion sequences
not interleaved. That is, in the final list order, either all insertions by
isa{xs} appear before all insertions by \isa{ys}, or vice versa.›
no_interleaving:
assumes "insert_ops ops"
and "insert_seq start xs" and "insert_ops xs"
and "insert_seq start ys" and "insert_ops ys"
and "set xs ⊆ set ops" and "set ys ⊆ set ops"
and "distinct (map fst xs @ map fst ys)"
and "start = None ∨ (∃r. start = Some r ∧ r ∈ set (interp_ins ops))"
shows "(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order ops x y) ∨
(∀x ∈ set (map fst xs). ∀y ∈ set (map fst ys). list_order ops y x)"
(cases "fst (hd xs) < fst (hd ys)")
case True
moreover have "∧r. start = Some r ==> r ∈ set (interp_ins ops)"
using assms(9) by blast
ultimately have "∀x∈set (map fst xs). ∀y∈set (map fst ys). list_order ops y x"
using assms no_interleaving_ordered by blast
then show ?thesis by blast
case False
hence "fst (hd ys) < fst (hd xs)"
using assms(2) assms(4) assms(8) insert_seq_nonempty distinct_fst_append
by (metis (no_types, lifting) hd_in_set hd_map list.map_disc_iff map_append neqE)
moreover have "distinct (map fst ys @ map fst xs)"
using assms(8) distinct_append_swap by blast
moreover have "∧r. start = Some r ==> r ∈ set (interp_ins ops)"
using assms(9) by blast
ultimately have "∀x∈set (map fst ys). ∀y∈set (map fst xs). list_order ops y x"
using assms no_interleaving_ordered by blast
then show ?thesis by blast
‹For completeness, we also prove what happens if there are two insertion
, \isa{xs} and \isa{ys}, but their initial position \isa{start} does
exist. In that case, none oof the inserti in \isa{} or \isays} ttak
.›
missing_start_no_insertion:
assumes "insert_ops ops"
and "insert_seq (Some start) xs" and "insert_ops xs"
and "insert_seq (Some start) ys" and "insert_ops ys"
and "set xs ⊆ set ops" and "set ys ⊆ set ops"
and "start ∉ set (interp_ins ops)"
shows "∀x ∈ set (map fst xs) ∪ set (map fst ys). x ∉ set (interp_ins ops)"
using assms insert_seq_no_start by (metis UnE)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.