theory BinTree imports Main begin datatype bt = Leaf | Node bt int bt fun in_order :: "bt \ int list" where "in_order Leaf = []" | "in_order (Node l v r) = in_order l @ [ v ] @ in_order r" definition "bt_elems t \ set (in_order t)" definition "bt_contains t x \ x \ bt_elems t" subsection {* Suchen im Baum *} fun bt_search_full :: "bt \ int \ bool" where "bt_search_full Leaf x = False" | "bt_search_full (Node l v r) x = (v = x \ bt_search_full l x \ bt_search_full r x)" export_code bt_search_full in OCaml module_name BTSearchFull file "btsearchfull.ML" lemma bt_search_full_correct: "bt_search_full t x \ bt_contains t x" apply (induct t) -- "Induktion durchführen" apply (rename_tac[2] l v r) apply (unfold bt_contains_def bt_elems_def) apply auto done subsection {* Sorted Trees *} definition "bt_sorted t \ sorted (in_order t)" fun bt_search_split :: "bt \ int \ bool" where "bt_search_split Leaf x = False" | "bt_search_split (Node l v r) x = (v = x \ (if x < v then bt_search_split l x else bt_search_split r x))" text {* See why sortedness is required *} lemma bt_search_split_correct_FAIL: "bt_search_split t x = bt_contains t x" apply (induct t) apply (unfold bt_contains_def) apply auto oops text {* Trying induction directly *} lemma bt_search_split_correct: "bt_sorted t \ (bt_search_split t x \ bt_contains t x)" apply (induct t) apply simp txt {* The cases are as expected but we need a few auxiliary facts *} oops lemma bt_sorted_branchesD: "bt_sorted (Node l v r) \ bt_sorted l \ bt_sorted r" apply (simp add: bt_sorted_def) apply (simp add: sorted_append sorted_Cons) done lemma bt_sorted_elemsD: "bt_sorted (Node l v r) \ (\x \ bt_elems l. x \ v) \ (\x \ bt_elems r. v \ x)" apply (simp add: bt_sorted_def bt_elems_def) apply (simp add: sorted_append sorted_Cons) done lemma bt_search_split_correct: "bt_sorted t \ (bt_search_split t x \ bt_contains t x)" apply (induct t) apply (unfold bt_contains_def) apply (simp add: bt_elems_def) apply (rename_tac l v r) apply (simp add: bt_elems_def) txt {* Two cases, depending on outcome of if test *} apply (rule conjI) apply clarsimp apply (frule bt_sorted_branchesD) apply simp txt {* Here is the main point: how do we know that? *} apply (frule bt_sorted_elemsD) apply (simp add: bt_elems_def) apply force txt {* The second case should be analogous - just copy the proof *} apply clarsimp apply (frule bt_sorted_branchesD) apply simp txt {* Here is the main point: how do we know that? *} apply (frule bt_sorted_elemsD) apply (simp add: bt_elems_def) apply force done subsection {* Insertion into a sorted tree *} fun bt_insert :: "[ int, bt ] \ bt" where "bt_insert x Leaf = Node Leaf x Leaf" | "bt_insert x (Node l v r) = (if x = v then (Node l v r) else if x < v then Node (bt_insert x l) v r else Node l v (bt_insert x r))" lemma elems_of_insert: "set (in_order (bt_insert x t)) = {x} \ set (in_order t)" apply (induct t) apply auto done lemma bt_insert_is_sorted: "bt_sorted t \ bt_sorted (bt_insert x t)" apply (induct t) apply (simp add: bt_sorted_def) txt {* Hey, these are the same questions as before! *} apply (frule bt_sorted_branchesD) apply (frule bt_sorted_elemsD) apply clarsimp apply (rule conjI, clarify) apply (simp add: bt_sorted_def bt_elems_def) apply (simp(no_asm_use) only: sorted_append sorted_Cons) txt {* The induction hypothesis is being used *} apply simp apply (rename_tac l v r) txt {* What is contained in @{term "set (in_order (bt_insert x l))"} ? *} apply (simp add: elems_of_insert) apply force txt {* Is this again analogous? After we have understood the proof, we can ask Isabelle's automatic provers to find it: *} apply (auto simp add: elems_of_insert bt_sorted_def bt_elems_def sorted_append sorted_Cons) done text {* Can we have a really short proof, now that we know how it works out? *} lemma bt_insert_is_sorted': "bt_sorted t \ bt_sorted (bt_insert x t)" apply (induct t) apply (auto dest: bt_sorted_branchesD bt_sorted_elemsD simp add: bt_sorted_def sorted_append sorted_Cons elems_of_insert) done text {* Observation: insertion never introduced duplicates. New proof strategy: rather than expanding definitions all the time, we derive the required properties beforehand. *} lemma bt_elems_Leaf[simp]: "bt_elems Leaf = {}" "bt_elems (Node l v r) = {v} \ bt_elems l \ bt_elems r" by (simp_all add: bt_elems_def) lemma bt_insert_no_duplicates: "\ x \ bt_elems t; bt_sorted t \ \ bt_insert x t = t" apply (induct t) apply simp apply simp apply auto apply (auto dest: bt_sorted_branchesD) apply (drule bt_sorted_elemsD) apply force apply (drule bt_sorted_elemsD) apply force done text {* Now we prove the abstract, intended behaviour of @{term bt_insert}: it implements addition into a set *} lemma bt_insert_result_set: "bt_elems (bt_insert x t) = {x} \ bt_elems t" apply (induct t) apply simp apply simp apply (simp add: insert_commute) done lemma bt_insert_distinct: "\ distinct (in_order t); bt_sorted t \ \ distinct (in_order (bt_insert x t))" apply (induct t) apply simp apply (rename_tac l v r) apply clarsimp txt {* Too bad: all our lemmas are about @{const bt_elems}! The latter is, however, only an abbreviation, and we succeed in applying its definition backwards. *} apply (fold bt_elems_def) txt {* Now we can get rid of the induction hypotheses *} apply (frule bt_sorted_branchesD) apply simp txt {* And now we can "compute" the result of @{term bt_insert}. *} apply (simp add: bt_insert_result_set) txt {* What's left??? Only that the tree is indeed sorted! *} apply (frule bt_sorted_elemsD) apply auto done subsection {* Using correctness *} lemma bt_contains_bt_insert: "bt_contains (bt_insert x t) y = (y = x \ bt_contains t y)" apply (simp add: bt_contains_def) apply (simp add: bt_insert_result_set) done lemma "bt_sorted t \ let t' = bt_insert x t in let t'' = bt_insert y t' in bt_search_split t'' x = True" apply (simp add: Let_def) apply (subst bt_search_split_correct) apply (subst bt_insert_is_sorted) apply (subst bt_insert_is_sorted) apply assumption apply rule apply (simp add: bt_contains_bt_insert) done lemma "bt_sorted t \ let t' = bt_insert x t in let t'' = bt_insert y t' in bt_search_split t'' x = True" by (simp add: Let_def bt_insert_is_sorted bt_search_split_correct bt_contains_bt_insert) subsection {* Binary trees as data structures *} text {* Use a binary tree as a set representation with the following invariant *} definition "bt_set_inv t \ bt_sorted t \ distinct (in_order t)" text {* We can now formulate that @{const bt_insert} maintains this invariant. *} lemma bt_insert_correct: "\ bt_set_inv t; t' = bt_insert x t \ \ bt_set_inv t' \ x \ bt_elems t'" apply (unfold bt_set_inv_def) apply (auto intro: bt_insert_is_sorted bt_insert_distinct simp add: bt_insert_result_set) done end