1 (* Title: HOL/Imperative_HOL/ex/Linked_Lists.thy |
1 (* Title: HOL/Imperative_HOL/ex/Linked_Lists.thy |
2 Author: Lukas Bulwahn, TU Muenchen |
2 Author: Lukas Bulwahn, TU Muenchen |
3 *) |
3 *) |
4 |
4 |
5 section {* Linked Lists by ML references *} |
5 section \<open>Linked Lists by ML references\<close> |
6 |
6 |
7 theory Linked_Lists |
7 theory Linked_Lists |
8 imports "../Imperative_HOL" "~~/src/HOL/Library/Code_Target_Int" |
8 imports "../Imperative_HOL" "~~/src/HOL/Library/Code_Target_Int" |
9 begin |
9 begin |
10 |
10 |
11 section {* Definition of Linked Lists *} |
11 section \<open>Definition of Linked Lists\<close> |
12 |
12 |
13 setup {* Sign.add_const_constraint (@{const_name Ref}, SOME @{typ "nat \<Rightarrow> 'a::type ref"}) *} |
13 setup \<open>Sign.add_const_constraint (@{const_name Ref}, SOME @{typ "nat \<Rightarrow> 'a::type ref"})\<close> |
14 datatype 'a node = Empty | Node 'a "'a node ref" |
14 datatype 'a node = Empty | Node 'a "'a node ref" |
15 |
15 |
16 primrec |
16 primrec |
17 node_encode :: "'a::countable node \<Rightarrow> nat" |
17 node_encode :: "'a::countable node \<Rightarrow> nat" |
18 where |
18 where |
53 return (x#xs) |
53 return (x#xs) |
54 }" |
54 }" |
55 by (simp_all add: traverse.simps[of "Empty"] traverse.simps[of "Node x r"]) |
55 by (simp_all add: traverse.simps[of "Empty"] traverse.simps[of "Node x r"]) |
56 |
56 |
57 |
57 |
58 section {* Proving correctness with relational abstraction *} |
58 section \<open>Proving correctness with relational abstraction\<close> |
59 |
59 |
60 subsection {* Definition of list_of, list_of', refs_of and refs_of' *} |
60 subsection \<open>Definition of list_of, list_of', refs_of and refs_of'\<close> |
61 |
61 |
62 primrec list_of :: "heap \<Rightarrow> ('a::heap) node \<Rightarrow> 'a list \<Rightarrow> bool" |
62 primrec list_of :: "heap \<Rightarrow> ('a::heap) node \<Rightarrow> 'a list \<Rightarrow> bool" |
63 where |
63 where |
64 "list_of h r [] = (r = Empty)" |
64 "list_of h r [] = (r = Empty)" |
65 | "list_of h r (a#as) = (case r of Empty \<Rightarrow> False | Node b bs \<Rightarrow> (a = b \<and> list_of h (Ref.get h bs) as))" |
65 | "list_of h r (a#as) = (case r of Empty \<Rightarrow> False | Node b bs \<Rightarrow> (a = b \<and> list_of h (Ref.get h bs) as))" |
77 where |
77 where |
78 "refs_of' h r [] = False" |
78 "refs_of' h r [] = False" |
79 | "refs_of' h r (x#xs) = ((x = r) \<and> refs_of h (Ref.get h x) xs)" |
79 | "refs_of' h r (x#xs) = ((x = r) \<and> refs_of h (Ref.get h x) xs)" |
80 |
80 |
81 |
81 |
82 subsection {* Properties of these definitions *} |
82 subsection \<open>Properties of these definitions\<close> |
83 |
83 |
84 lemma list_of_Empty[simp]: "list_of h Empty xs = (xs = [])" |
84 lemma list_of_Empty[simp]: "list_of h Empty xs = (xs = [])" |
85 by (cases xs, auto) |
85 by (cases xs, auto) |
86 |
86 |
87 lemma list_of_Node[simp]: "list_of h (Node x ps) xs = (\<exists>xs'. (xs = x # xs') \<and> list_of h (Ref.get h ps) xs')" |
87 lemma list_of_Node[simp]: "list_of h (Node x ps) xs = (\<exists>xs'. (xs = x # xs') \<and> list_of h (Ref.get h ps) xs')" |
214 proof - |
214 proof - |
215 from assms obtain rs where "refs_of' h r rs" by (rule list_of'_refs_of') |
215 from assms obtain rs where "refs_of' h r rs" by (rule list_of'_refs_of') |
216 thus ?thesis by (auto simp add: refs_of'_def') |
216 thus ?thesis by (auto simp add: refs_of'_def') |
217 qed |
217 qed |
218 |
218 |
219 subsection {* More complicated properties of these predicates *} |
219 subsection \<open>More complicated properties of these predicates\<close> |
220 |
220 |
221 lemma list_of_append: |
221 lemma list_of_append: |
222 "list_of h n (as @ bs) \<Longrightarrow> \<exists>m. list_of h m bs" |
222 "list_of h n (as @ bs) \<Longrightarrow> \<exists>m. list_of h m bs" |
223 apply (induct as arbitrary: n) |
223 apply (induct as arbitrary: n) |
224 apply auto |
224 apply auto |
256 lemma refs_of'_distinct: "refs_of' h p rs \<Longrightarrow> distinct rs" |
256 lemma refs_of'_distinct: "refs_of' h p rs \<Longrightarrow> distinct rs" |
257 unfolding refs_of'_def' |
257 unfolding refs_of'_def' |
258 by (fastforce simp add: refs_of_distinct refs_of_next) |
258 by (fastforce simp add: refs_of_distinct refs_of_next) |
259 |
259 |
260 |
260 |
261 subsection {* Interaction of these predicates with our heap transitions *} |
261 subsection \<open>Interaction of these predicates with our heap transitions\<close> |
262 |
262 |
263 lemma list_of_set_ref: "refs_of h q rs \<Longrightarrow> p \<notin> set rs \<Longrightarrow> list_of (Ref.set p v h) q as = list_of h q as" |
263 lemma list_of_set_ref: "refs_of h q rs \<Longrightarrow> p \<notin> set rs \<Longrightarrow> list_of (Ref.set p v h) q as = list_of h q as" |
264 proof (induct as arbitrary: q rs) |
264 proof (induct as arbitrary: q rs) |
265 case Nil thus ?case by simp |
265 case Nil thus ?case by simp |
266 next |
266 next |
376 unfolding refs_of'_def'[of _ p] |
376 unfolding refs_of'_def'[of _ p] |
377 apply (auto, frule refs_of_set_ref2) by (auto dest: Ref.noteq_sym) |
377 apply (auto, frule refs_of_set_ref2) by (auto dest: Ref.noteq_sym) |
378 with assms that show thesis by auto |
378 with assms that show thesis by auto |
379 qed |
379 qed |
380 |
380 |
381 section {* Proving make_llist and traverse correct *} |
381 section \<open>Proving make_llist and traverse correct\<close> |
382 |
382 |
383 lemma refs_of_invariant: |
383 lemma refs_of_invariant: |
384 assumes "refs_of h (r::('a::heap) node) xs" |
384 assumes "refs_of h (r::('a::heap) node) xs" |
385 assumes "\<forall>refs. refs_of h r refs \<longrightarrow> (\<forall>ref \<in> set refs. Ref.present h ref \<and> Ref.present h' ref \<and> Ref.get h ref = Ref.get h' ref)" |
385 assumes "\<forall>refs. refs_of h r refs \<longrightarrow> (\<forall>ref \<in> set refs. Ref.present h ref \<and> Ref.present h' ref \<and> Ref.get h ref = Ref.get h' ref)" |
386 shows "refs_of h' r xs" |
386 shows "refs_of h' r xs" |
516 from make_llist[OF makell] have "list_of h1 r1 xs" .. |
516 from make_llist[OF makell] have "list_of h1 r1 xs" .. |
517 from traverse [OF this] trav show ?thesis |
517 from traverse [OF this] trav show ?thesis |
518 using effect_deterministic by fastforce |
518 using effect_deterministic by fastforce |
519 qed |
519 qed |
520 |
520 |
521 section {* Proving correctness of in-place reversal *} |
521 section \<open>Proving correctness of in-place reversal\<close> |
522 |
522 |
523 subsection {* Definition of in-place reversal *} |
523 subsection \<open>Definition of in-place reversal\<close> |
524 |
524 |
525 partial_function (heap) rev' :: "('a::heap) node ref \<Rightarrow> 'a node ref \<Rightarrow> 'a node ref Heap" |
525 partial_function (heap) rev' :: "('a::heap) node ref \<Rightarrow> 'a node ref \<Rightarrow> 'a node ref Heap" |
526 where |
526 where |
527 [code]: "rev' q p = |
527 [code]: "rev' q p = |
528 do { |
528 do { |
539 primrec rev :: "('a:: heap) node \<Rightarrow> 'a node Heap" |
539 primrec rev :: "('a:: heap) node \<Rightarrow> 'a node Heap" |
540 where |
540 where |
541 "rev Empty = return Empty" |
541 "rev Empty = return Empty" |
542 | "rev (Node x n) = do { q \<leftarrow> ref Empty; p \<leftarrow> ref (Node x n); v \<leftarrow> rev' q p; !v }" |
542 | "rev (Node x n) = do { q \<leftarrow> ref Empty; p \<leftarrow> ref (Node x n); v \<leftarrow> rev' q p; !v }" |
543 |
543 |
544 subsection {* Correctness Proof *} |
544 subsection \<open>Correctness Proof\<close> |
545 |
545 |
546 lemma rev'_invariant: |
546 lemma rev'_invariant: |
547 assumes "effect (rev' q p) h h' v" |
547 assumes "effect (rev' q p) h h' v" |
548 assumes "list_of' h q qs" |
548 assumes "list_of' h q qs" |
549 assumes "list_of' h p ps" |
549 assumes "list_of' h p ps" |
647 with lookup show ?thesis |
647 with lookup show ?thesis |
648 by (auto elim: effect_lookupE) |
648 by (auto elim: effect_lookupE) |
649 qed |
649 qed |
650 |
650 |
651 |
651 |
652 section {* The merge function on Linked Lists *} |
652 section \<open>The merge function on Linked Lists\<close> |
653 text {* We also prove merge correct *} |
653 text \<open>We also prove merge correct\<close> |
654 |
654 |
655 text{* First, we define merge on lists in a natural way. *} |
655 text\<open>First, we define merge on lists in a natural way.\<close> |
656 |
656 |
657 fun Lmerge :: "('a::ord) list \<Rightarrow> 'a list \<Rightarrow> 'a list" |
657 fun Lmerge :: "('a::ord) list \<Rightarrow> 'a list \<Rightarrow> 'a list" |
658 where |
658 where |
659 "Lmerge (x#xs) (y#ys) = |
659 "Lmerge (x#xs) (y#ys) = |
660 (if x \<le> y then x # Lmerge xs (y#ys) else y # Lmerge (x#xs) ys)" |
660 (if x \<le> y then x # Lmerge xs (y#ys) else y # Lmerge (x#xs) ys)" |
661 | "Lmerge [] ys = ys" |
661 | "Lmerge [] ys = ys" |
662 | "Lmerge xs [] = xs" |
662 | "Lmerge xs [] = xs" |
663 |
663 |
664 subsection {* Definition of merge function *} |
664 subsection \<open>Definition of merge function\<close> |
665 |
665 |
666 partial_function (heap) merge :: "('a::{heap, ord}) node ref \<Rightarrow> 'a node ref \<Rightarrow> 'a node ref Heap" |
666 partial_function (heap) merge :: "('a::{heap, ord}) node ref \<Rightarrow> 'a node ref \<Rightarrow> 'a node ref Heap" |
667 where |
667 where |
668 [code]: "merge p q = (do { v \<leftarrow> !p; w \<leftarrow> !q; |
668 [code]: "merge p q = (do { v \<leftarrow> !p; w \<leftarrow> !q; |
669 (case v of Empty \<Rightarrow> return q |
669 (case v of Empty \<Rightarrow> return q |
692 |
692 |
693 |
693 |
694 lemma sum_distrib: "case_sum fl fr (case x of Empty \<Rightarrow> y | Node v n \<Rightarrow> (z v n)) = (case x of Empty \<Rightarrow> case_sum fl fr y | Node v n \<Rightarrow> case_sum fl fr (z v n))" |
694 lemma sum_distrib: "case_sum fl fr (case x of Empty \<Rightarrow> y | Node v n \<Rightarrow> (z v n)) = (case x of Empty \<Rightarrow> case_sum fl fr y | Node v n \<Rightarrow> case_sum fl fr (z v n))" |
695 by (cases x) auto |
695 by (cases x) auto |
696 |
696 |
697 subsection {* Induction refinement by applying the abstraction function to our induct rule *} |
697 subsection \<open>Induction refinement by applying the abstraction function to our induct rule\<close> |
698 |
698 |
699 text {* From our original induction rule Lmerge.induct, we derive a new rule with our list_of' predicate *} |
699 text \<open>From our original induction rule Lmerge.induct, we derive a new rule with our list_of' predicate\<close> |
700 |
700 |
701 lemma merge_induct2: |
701 lemma merge_induct2: |
702 assumes "list_of' h (p::'a::{heap, ord} node ref) xs" |
702 assumes "list_of' h (p::'a::{heap, ord} node ref) xs" |
703 assumes "list_of' h q ys" |
703 assumes "list_of' h q ys" |
704 assumes "\<And> ys p q. \<lbrakk> list_of' h p []; list_of' h q ys; Ref.get h p = Empty \<rbrakk> \<Longrightarrow> P p q [] ys" |
704 assumes "\<And> ys p q. \<lbrakk> list_of' h p []; list_of' h q ys; Ref.get h p = Empty \<rbrakk> \<Longrightarrow> P p q [] ys" |
739 show ?thesis by blast |
739 show ?thesis by blast |
740 qed |
740 qed |
741 qed |
741 qed |
742 |
742 |
743 |
743 |
744 text {* secondly, we add the effect statement in the premise, and derive the effect statements for the single cases which we then eliminate with our effect elim rules. *} |
744 text \<open>secondly, we add the effect statement in the premise, and derive the effect statements for the single cases which we then eliminate with our effect elim rules.\<close> |
745 |
745 |
746 lemma merge_induct3: |
746 lemma merge_induct3: |
747 assumes "list_of' h p xs" |
747 assumes "list_of' h p xs" |
748 assumes "list_of' h q ys" |
748 assumes "list_of' h q ys" |
749 assumes "effect (merge p q) h h' r" |
749 assumes "effect (merge p q) h h' r" |
788 by (auto elim!: effect_lookupE effect_bindE effect_returnE effect_ifE effect_updateE) |
788 by (auto elim!: effect_lookupE effect_bindE effect_returnE effect_ifE effect_updateE) |
789 from 4(6)[OF 1] assms(7) [OF 4(1-5)] 1 2 show ?case by simp |
789 from 4(6)[OF 1] assms(7) [OF 4(1-5)] 1 2 show ?case by simp |
790 qed |
790 qed |
791 |
791 |
792 |
792 |
793 subsection {* Proving merge correct *} |
793 subsection \<open>Proving merge correct\<close> |
794 |
794 |
795 text {* As many parts of the following three proofs are identical, we could actually move the |
795 text \<open>As many parts of the following three proofs are identical, we could actually move the |
796 same reasoning into an extended induction rule *} |
796 same reasoning into an extended induction rule\<close> |
797 |
797 |
798 lemma merge_unchanged: |
798 lemma merge_unchanged: |
799 assumes "refs_of' h p xs" |
799 assumes "refs_of' h p xs" |
800 assumes "refs_of' h q ys" |
800 assumes "refs_of' h q ys" |
801 assumes "effect (merge p q) h h' r'" |
801 assumes "effect (merge p q) h h' r'" |
820 from pnrs_def 3(12) have "r \<noteq> p" by auto |
820 from pnrs_def 3(12) have "r \<noteq> p" by auto |
821 with 3(11) 3(12) pnrs_def refs_of'_distinct[OF 3(9)] have p_in: "p \<notin> set pnrs \<union> set ys" by auto |
821 with 3(11) 3(12) pnrs_def refs_of'_distinct[OF 3(9)] have p_in: "p \<notin> set pnrs \<union> set ys" by auto |
822 from 3(11) pnrs_def have no_inter: "set pnrs \<inter> set ys = {}" by auto |
822 from 3(11) pnrs_def have no_inter: "set pnrs \<inter> set ys = {}" by auto |
823 from 3(7)[OF refs_of'_pn 3(10) this p_in] 3(3) have p_is_Node: "Ref.get h1 p = Node x pn" |
823 from 3(7)[OF refs_of'_pn 3(10) this p_in] 3(3) have p_is_Node: "Ref.get h1 p = Node x pn" |
824 by simp |
824 by simp |
825 from 3(7)[OF refs_of'_pn 3(10) no_inter r_in] 3(8) `r \<noteq> p` show ?case |
825 from 3(7)[OF refs_of'_pn 3(10) no_inter r_in] 3(8) \<open>r \<noteq> p\<close> show ?case |
826 by simp |
826 by simp |
827 next |
827 next |
828 case (4 x xs' y ys' p q pn qn h1 r1 h' xs ys r) |
828 case (4 x xs' y ys' p q pn qn h1 r1 h' xs ys r) |
829 from 4(10) 4(4) obtain qnrs |
829 from 4(10) 4(4) obtain qnrs |
830 where qnrs_def: "ys = q#qnrs" |
830 where qnrs_def: "ys = q#qnrs" |
833 with 4(12) have r_in: "r \<notin> set xs \<union> set qnrs" by auto |
833 with 4(12) have r_in: "r \<notin> set xs \<union> set qnrs" by auto |
834 from qnrs_def 4(12) have "r \<noteq> q" by auto |
834 from qnrs_def 4(12) have "r \<noteq> q" by auto |
835 with 4(11) 4(12) qnrs_def refs_of'_distinct[OF 4(10)] have q_in: "q \<notin> set xs \<union> set qnrs" by auto |
835 with 4(11) 4(12) qnrs_def refs_of'_distinct[OF 4(10)] have q_in: "q \<notin> set xs \<union> set qnrs" by auto |
836 from 4(11) qnrs_def have no_inter: "set xs \<inter> set qnrs = {}" by auto |
836 from 4(11) qnrs_def have no_inter: "set xs \<inter> set qnrs = {}" by auto |
837 from 4(7)[OF 4(9) refs_of'_qn this q_in] 4(4) have q_is_Node: "Ref.get h1 q = Node y qn" by simp |
837 from 4(7)[OF 4(9) refs_of'_qn this q_in] 4(4) have q_is_Node: "Ref.get h1 q = Node y qn" by simp |
838 from 4(7)[OF 4(9) refs_of'_qn no_inter r_in] 4(8) `r \<noteq> q` show ?case |
838 from 4(7)[OF 4(9) refs_of'_qn no_inter r_in] 4(8) \<open>r \<noteq> q\<close> show ?case |
839 by simp |
839 by simp |
840 qed |
840 qed |
841 qed |
841 qed |
842 |
842 |
843 lemma refs_of'_merge: |
843 lemma refs_of'_merge: |
935 from refs_of'_merge[OF prs_def refs_of'_qn 4(6) no_inter this] q_in have q_rs: "q \<notin> set rs" by auto |
935 from refs_of'_merge[OF prs_def refs_of'_qn 4(6) no_inter this] q_in have q_rs: "q \<notin> set rs" by auto |
936 with 4(7)[OF no_inter2] 4(1-5) 4(8) q_rs rs_def q_stays |
936 with 4(7)[OF no_inter2] 4(1-5) 4(8) q_rs rs_def q_stays |
937 show ?case by (auto simp: list_of'_set_ref) |
937 show ?case by (auto simp: list_of'_set_ref) |
938 qed |
938 qed |
939 |
939 |
940 section {* Code generation *} |
940 section \<open>Code generation\<close> |
941 |
941 |
942 text {* A simple example program *} |
942 text \<open>A simple example program\<close> |
943 |
943 |
944 definition test_1 where "test_1 = (do { ll_xs \<leftarrow> make_llist [1..(15::int)]; xs \<leftarrow> traverse ll_xs; return xs })" |
944 definition test_1 where "test_1 = (do { ll_xs \<leftarrow> make_llist [1..(15::int)]; xs \<leftarrow> traverse ll_xs; return xs })" |
945 definition test_2 where "test_2 = (do { ll_xs \<leftarrow> make_llist [1..(15::int)]; ll_ys \<leftarrow> rev ll_xs; ys \<leftarrow> traverse ll_ys; return ys })" |
945 definition test_2 where "test_2 = (do { ll_xs \<leftarrow> make_llist [1..(15::int)]; ll_ys \<leftarrow> rev ll_xs; ys \<leftarrow> traverse ll_ys; return ys })" |
946 |
946 |
947 definition test_3 where "test_3 = |
947 definition test_3 where "test_3 = |
956 return zs |
956 return zs |
957 })" |
957 })" |
958 |
958 |
959 code_reserved SML upto |
959 code_reserved SML upto |
960 |
960 |
961 ML_val {* @{code test_1} () *} |
961 ML_val \<open>@{code test_1} ()\<close> |
962 ML_val {* @{code test_2} () *} |
962 ML_val \<open>@{code test_2} ()\<close> |
963 ML_val {* @{code test_3} () *} |
963 ML_val \<open>@{code test_3} ()\<close> |
964 |
964 |
965 export_code test_1 test_2 test_3 checking SML SML_imp OCaml? OCaml_imp? Haskell? Scala Scala_imp |
965 export_code test_1 test_2 test_3 checking SML SML_imp OCaml? OCaml_imp? Haskell? Scala Scala_imp |
966 |
966 |
967 end |
967 end |