Theory Take_While_Update
theory Take_While_Update imports Tools
begin
section ‹Extending @{text "Take_While"} with an additional, mutable parameter›
text‹This theory defines takeW, holds and extract similarly to the other @{text "Take_While"} theory, but removes
the predecessor parameter and adds a parameter to P and an update function that is applied to this parameter.
In our formalization, the additional parameter is the uinfo field and the update function is the update
on uinfo fields.›
locale TWu =
fixes P :: "('b ⇒ 'a ⇒ 'a option ⇒ bool)"
fixes upd :: "('b ⇒ 'a ⇒ 'b)"
begin
subsection‹Definitions›
text‹Apply @{text "upds"} on a sequence›
abbreviation upds :: "'b ⇒ 'a list ⇒ 'b" where
"upds ≡ foldl upd"
fun upd_opt :: "('b ⇒ 'a option ⇒ 'b)" where
"upd_opt info (Some hf) = upd info hf"
| "upd_opt info None = info"
text‹holds returns true iff every element of a list, together with its context, satisfies P.›
fun holds :: "'b ⇒ 'a list ⇒ 'a option ⇒ bool"
where
"holds info (x # y # ys) nxt ⟷ P info x (Some y) ∧ holds (upd info y) (y # ys) nxt"
| "holds info [x] nxt ⟷ P info x nxt"
| "holds info [] nxt ⟷ True"
text‹holds returns the longest prefix of a list for every element, together with its context, satisfies P.›
function takeW :: "'b ⇒ 'a list ⇒ 'a option ⇒ 'a list" where
"takeW _ [] _ = []"
| "P info x xo ⟹ takeW info [x] xo = [x]"
| "¬ P info x xo ⟹ takeW info [x] xo = []"
| "P info x (Some y) ⟹ takeW info (x # y # xs) xo = x # takeW (upd info y) (y # xs) xo"
| "¬ P info x (Some y) ⟹ takeW info (x # y # xs) xo = []"
apply auto
by (metis remdups_adj.cases)
termination
by lexicographic_order
text‹extract returns the last element of a list, or nxt if the list is empty.›
"" :: "'b ⇒ 'a list ⇒ 'a option ⇒ 'a option"
where
"extract info (x # y # ys) nxt = (if P info x (Some y) then extract (upd info y) (y # ys) nxt else Some x)"
| "extract info [x] nxt = (if P info x nxt then nxt else (Some x))"
| "extract info [] nxt = nxt"
subsection‹Lemmas›
text ‹Lemmas packing singleton and at least two element cases into a single equation.›
lemma takeW_singleton:
"takeW info [x] xo = (if P info x xo then [x] else [])"
by (simp)
lemma takeW_two_or_more:
"takeW info (x # y # zs) xo = (if P info x (Some y) then x # takeW (upd info y) (y # zs) xo else [])"
by (simp)
text ‹Some lemmas for splitting the tail of the list argument.›
text ‹Splitting lemma formulated with if-then-else rather than case.›
lemma takeW_split_tail:
"takeW info (x # xs) nxt =
(if xs = []
then (if P info x nxt then [x] else [])
else (if P info x (Some (hd xs)) then x # takeW (upd info (hd xs)) xs nxt else []))"
by (cases xs, auto)
lemma :
"extract info (x # xs) nxt =
(case xs of
[] ⇒ (if P info x nxt then nxt else (Some x))
| (y # ys) ⇒ (if P info x (Some y) then extract (upd info y) (y # ys) nxt else Some x))"
by (cases xs, auto)
lemma holds_split_tail:
"holds info (x # xs) nxt ⟷
(case xs of
[] ⇒ P info x nxt
| (y # ys) ⇒ P info x (Some y) ∧ holds (upd info y) (y # ys) nxt)"
by (cases xs, auto)
lemma holds_Cons_P:
"holds info (x # xs) nxt ⟹ ∃y . P info x y"
by (cases xs, auto)
lemma holds_Cons_holds:
"holds info (x # xs) nxt ⟹ holds (upd_opt info (head xs)) xs nxt"
by (cases xs, auto)
lemmas tail_splitting_lemmas =
extract_split_tail holds_split_tail
text ‹Interaction between @{term holds}, @{term takeWhile}, and @{term extract}.›
declare if_split_asm [split]
lemma : "holds info (takeW info xs nxt) (extract info xs nxt)"
apply(induction info xs nxt rule: takeW.induct)
apply auto
subgoal for info x y ys
apply(cases "ys")
apply(simp_all)
done
done
text ‹Interaction of @{term holds}, @{term takeWhile}, and @{term extract}
with @{term append}.›
lemma holds_append:
"holds info (xs @ ys) nxt =
(case ys of [] ⇒ holds info xs nxt | x # _ ⇒
holds info xs (Some x) ∧
(case xs of [] ⇒ holds info ys nxt
| _ ⇒ holds (upds info (tl xs@[x])) ys nxt))"
by(induction info xs nxt rule: takeW.induct)
(auto split: list.split)
lemma upds_snoc: "upds uinfo (xs@[x]) = upd (upds uinfo xs) x"
by simp
lemma takeW_prefix:
"prefix (takeW info l nxt) l"
by (induction info l nxt rule: takeW.induct) auto
lemma takeW_set: "t ∈ set (TWu.takeW P upd info l nxt) ⟹ t ∈ set l"
by(auto intro: takeW_prefix elim: set_prefix)
lemma holds_implies_takeW_is_identity:
"holds info l nxt ⟹ takeW info l nxt = l"
by (induction info l nxt rule: takeW.induct) auto
lemma holds_takeW_is_identity[simp]:
"takeW info l nxt = l ⟷ holds info l nxt"
by (induction info l nxt rule: takeW.induct) auto
lemma :
"takeW info (takeW info l nxt) (extract info l nxt)
= takeW info l nxt"
using holds_takeW_extract holds_implies_takeW_is_identity
by blast
subsubsection ‹Holds unfolding›
text ‹This section contains various lemmas that show how one can deduce P info' x' nxt' for some of
info' x' nxt' out of a list l, for which we know that holds info l nxt is true.›
lemma holds_set_list: "⟦holds info l nxt; x ∈ set l⟧ ⟹ ∃ p y . P p x y"
apply(induction info l nxt rule: TWu.takeW.induct[where ?Pa="P"]) by auto
lemma holds_set_list_no_update: "⟦holds info l nxt; x ∈ set l; ⋀a b. upd a b = a⟧ ⟹ ∃ y . P info x y"
apply(induction info l nxt rule: TWu.takeW.induct[where ?Pa="P"]) by auto
lemma holds_unfold: "holds info l None ⟹
l = [] ∨
(∃ x . l = [x] ∧ P info x None) ∨
(∃ x y ys . l = (x#y#ys) ∧ P info x (Some y) ∧ holds (upd info y) (y#ys) None)"
by auto (meson holds.elims(2))
lemma holds_unfold_prexnxt':
"⟦holds info l nxt; l = (zs@(x1#x2#xs)); zs ≠ []⟧
⟹ P (upds info ((tl zs)@[x1])) x1 (Some x2)"
apply(cases zs) apply simp
apply(simp only: TWu.holds_append)
by auto
lemma holds_suffix:
"⟦holds info l nxt; suffix l' l⟧ ⟹ ∃ info'. holds info' l' nxt"
apply(cases l')
by(auto simp add: suffix_def TWu.holds_append list.case_eq_if)
lemma holds_unfold_prelnil:
"⟦holds info l nxt; l = (zs@(x1#[])); zs ≠ []⟧
⟹ P (upds info ((tl zs)@[x1])) x1 nxt"
apply(cases zs)
subgoal by simp
by(simp only: TWu.holds_append) auto
subsubsection ‹Update shifted›
text‹Usually, the update has already been applied to the head of the list. Hence, when given a list
to apply updates to (and a successor, i.e., the first element that comes after the list), we remove
the first element of the list and add the successor. We apply the updates on the resulting list.›
fun upd_shifted :: "('b ⇒ 'a list ⇒ 'a ⇒ 'b)" where
"upd_shifted uinfo (x#xs) nxt = upds uinfo (xs@[nxt])"
| "upd_shifted uinfo [] nxt = uinfo"
text‹This lemma is useful when there is an intermediate hop field hf of interest.›
lemma holds_intermediate:
assumes "holds uinfo p nxt" "p = pre @ hf # post"
shows "holds (upd_shifted uinfo pre hf) (hf # post) nxt"
using assms proof(induction pre arbitrary: p uinfo hf)
case Nil
then show ?case using assms by auto
next
case induct_asm: (Cons a prev)
show ?case
proof(cases prev)
case Nil
then have "holds (upd uinfo hf) (hf # post) nxt"
using induct_asm by simp
then show ?thesis
using induct_asm Nil by auto
next
case cons_asm: (Cons b list)
then have "holds (upd uinfo b) (b # list @ hf # post) nxt"
using induct_asm(2-3) by auto
then show ?thesis
using induct_asm(1)
by (simp add: cons_asm)
qed
qed
lemma holds_intermediate_ex:
assumes "holds uinfo hfs nxt" "hf ∈ set hfs"
shows "∃pre post . holds (upd_shifted uinfo pre hf) (hf # post) nxt ∧ hfs = pre @ hf # post"
using assms holds_intermediate
by (meson split_list)
end
end