Theory Imperative_Loops
section ‹Looping Constructs for Imperative HOL›
theory Imperative_Loops
imports "HOL-Imperative_HOL.Imperative_HOL"
begin
subsection ‹While Loops›
text ‹
We would have liked to restrict to read-only loop conditions using a condition of
type @{typ "heap ⇒ bool"} together with @{const tap}. However, this does not allow
for code generation due to breaking the heap-abstraction.
›
partial_function (heap) while :: "bool Heap ⇒ 'b Heap ⇒ unit Heap"
where
[code]: "while p f = do {
b ← p;
if b then f ⪢ while p f
else return ()
}"
definition "cond p h ⟷ fst (the (execute p h))"
text ‹A locale that restricts to read-only loop conditions.›
locale ro_cond =
fixes p :: "bool Heap"
assumes read_only: "success p h ⟹ snd (the (execute p h)) = h"
begin
lemma ro_cond: "ro_cond p"
using read_only by (simp add: ro_cond_def)
lemma cond_cases [execute_simps]:
"success p h ⟹ cond p h ⟹ execute p h = Some (True, h)"
"success p h ⟹ ¬ cond p h ⟹ execute p h = Some (False, h)"
using read_only [of h] by (auto simp: cond_def success_def)
lemma execute_while_unfolds [execute_simps]:
"success p h ⟹ cond p h ⟹ execute (while p f) h = execute (f ⪢ while p f) h"
"success p h ⟹ ¬ cond p h ⟹ execute (while p f) h = execute (return ()) h"
by (auto simp: while.simps execute_simps)
lemma
success_while_cond: "success p h ⟹ cond p h ⟹ effect f h h' r ⟹ success (while p f) h' ⟹
success (while p f) h" and
success_while_not_cond: "success p h ⟹ ¬ cond p h ⟹ success (while p f) h"
by (auto simp: while.simps effect_def execute_simps intro!: success_intros)
lemma success_cond_effect:
"success p h ⟹ cond p h ⟹ effect p h h True"
using read_only [of h] by (auto simp: effect_def execute_simps)
lemma success_not_cond_effect:
"success p h ⟹ ¬ cond p h ⟹ effect p h h False"
using read_only [of h] by (auto simp: effect_def execute_simps)
end
text ‹The loop-condition does no longer hold after the loop is finished.›
lemma ro_cond_effect_while_post:
assumes "ro_cond p"
and "effect (while p f) h h' r"
shows "success p h' ∧ ¬ cond p h'"
using assms(1)
apply (induct rule: while.raw_induct [OF _ assms(2)])
apply (auto elim!: effect_elims effect_ifE simp: cond_def)
apply (metis effectE ro_cond.read_only)+
done
text ‹A rule for proving partial correctness of while loops.›
lemma ro_cond_effect_while_induct:
assumes "ro_cond p"
assumes "effect (while p f) h h' u"
and "I h"
and "⋀h h' u. I h ⟹ success p h ⟹ cond p h ⟹ effect f h h' u ⟹ I h'"
shows "I h'"
using assms(1, 3-)
proof (induction p f h h' u rule: while.raw_induct)
case (1 w p f h h' u)
obtain b
where "effect p h h b"
and *: "effect (if b then f ⪢ w p f else return ()) h h' u"
using "1.hyps" and ‹ro_cond p›
by (auto elim!: effect_elims intro: effect_intros) (metis effectE ro_cond.read_only)
then have cond: "success p h" "cond p h = b" by (auto simp: cond_def elim!: effect_elims effectE)
show ?case
proof (cases "b")
assume "¬ b"
then show ?thesis using * and ‹I h› by (auto elim: effect_elims)
next
assume "b"
moreover
with * obtain h'' and r
where "effect f h h'' r" and "effect (w p f) h'' h' u" by (auto elim: effect_elims)
moreover
ultimately
show ?thesis using 1 and cond by blast
qed
qed fact
lemma effect_success_conv:
"(∃h'. effect c h h' () ∧ I h') ⟷ success c h ∧ I (snd (the (execute c h)))"
by (auto simp: success_def effect_def)
context ro_cond
begin
lemmas
effect_while_post = ro_cond_effect_while_post [OF ro_cond] and
effect_while_induct [consumes 1, case_names base step] = ro_cond_effect_while_induct [OF ro_cond]
text ‹A rule for proving total correctness of while loops.›
lemma wf_while_induct [consumes 1, case_names success_cond success_body base step]:
assumes "wf R"
and success_p: "⋀h. I h ⟹ success p h"
and success_f: "⋀h. I h ⟹ success p h ⟹ cond p h ⟹ success f h"
and "I h"
and step: "⋀h h' r. I h ⟹ success p h ⟹ cond p h ⟹ effect f h h' r ⟹ (h', h) ∈ R ∧ I h'"
shows "∃h'. effect (while p f) h h' () ∧ I h'"
using ‹wf R› and ‹I h›
proof (induction h)
case (less h)
show ?case
proof (cases "cond p h")
assume "¬ cond p h" then show ?thesis
using ‹I h› and success_p [of h] by (simp add: effect_def execute_simps)
next
assume "cond p h"
with ‹I h› and success_f [of h] and step [of h] and success_p [of h]
obtain h' and r where "effect f h h' r" and "(h', h) ∈ R" and "I h'" and "success p h"
by (auto simp: success_def effect_def)
with less.IH [of h'] show ?thesis
using ‹cond p h› by (auto simp: execute_simps effect_def)
qed
qed
text ‹A rule for proving termination of while loops.›
lemmas
success_while_induct [consumes 1, case_names success_cond success_body base step] =
wf_while_induct [unfolded effect_success_conv, THEN conjunct1]
end
subsection ‹For Loops›
fun "for" :: "'a list ⇒ ('a ⇒ 'b Heap) ⇒ unit Heap"
where
"for [] f = return ()" |
"for (x # xs) f = f x ⪢ for xs f"
text ‹A rule for proving partial correctness of for loops.›
lemma effect_for_induct [consumes 2, case_names base step]:
assumes "i ≤ j"
and "effect (for [i ..< j] f) h h' u"
and "I i h"
and "⋀k h h' r. i ≤ k ⟹ k < j ⟹ I k h ⟹ effect (f k) h h' r ⟹ I (Suc k) h'"
shows "I j h'"
using assms
proof (induction "j - i" arbitrary: i h)
case 0
then show ?case by (auto elim: effect_elims)
next
case (Suc k)
show ?case
proof (cases "j = i")
case True
with Suc show ?thesis by auto
next
case False
with ‹i ≤ j› and ‹Suc k = j - i›
have "i < j" and "k = j - Suc i" and "Suc i ≤ j" by auto
then have "[i ..< j] = i # [Suc i ..< j]" by (metis upt_rec)
with ‹effect (for [i ..< j] f) h h' u› obtain h'' r
where *: "effect (f i) h h'' r" and **: "effect (for [Suc i ..< j] f) h'' h' u"
by (auto elim: effect_elims)
from Suc(6) [OF _ _ ‹I i h› *] and ‹i < j›
have "I (Suc i) h''" by auto
show ?thesis
by (rule Suc(1) [OF ‹k = j - Suc i› ‹Suc i ≤ j› ** ‹I (Suc i) h''› Suc(6)]) auto
qed
qed
text ‹A rule for proving total correctness of for loops.›
lemma for_induct [consumes 1, case_names succeed base step]:
assumes "i ≤ j"
and "⋀k h. I k h ⟹ i ≤ k ⟹ k < j ⟹ success (f k) h"
and "I i h"
and "⋀k h h' r. I k h ⟹ i ≤ k ⟹ k < j ⟹ effect (f k) h h' r ⟹ I (Suc k) h'"
shows "∃h'. effect (for [i ..< j] f) h h' () ∧ I j h'" (is "?P i h")
using assms
proof (induction "j - i" arbitrary: i h)
case 0
then show ?case by (auto simp: effect_def execute_simps)
next
case (Suc k)
show ?case
proof (cases "j = i")
assume "j = i"
with Suc show ?thesis by auto
next
assume "j ≠ i"
with ‹i ≤ j› and ‹Suc k = j - i›
have "i < j" and "k = j - Suc i" and "Suc i ≤ j" by auto
then have [simp]: "[i ..< j] = i # [Suc i ..< j]" by (metis upt_rec)
obtain h' r where *: "effect (f i) h h' r"
using Suc(4) [OF ‹I i h› le_refl ‹i < j›] by (auto elim!: success_effectE)
moreover
then have "I (Suc i) h'" using Suc by auto
moreover
have "?P (Suc i) h'"
by (rule Suc(1) [OF ‹k = j - Suc i› ‹Suc i ≤ j› Suc(4) ‹I (Suc i) h'› Suc(6)]) auto
ultimately
show ?case by (auto simp: effect_def execute_simps)
qed
qed
text ‹A rule for proving termination of for loops.›
lemmas
success_for_induct [consumes 1, case_names succeed base step] =
for_induct [unfolded effect_success_conv, THEN conjunct1]
end