diff --git a/README.md b/README.md index f4338bd..1c8ee46 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # IsabelleClub -Repo for Isabelle Club problems \ No newline at end of file +Repo for Isabelle Club problems + +This repo requires the installation of the Archive of Formal Proofs (AFP) as a component to your isabelle version. + +Download can be found here -> https://www.isa-afp.org/download/ + +Instructions for adding the AFP as a component can be found here -> https://www.isa-afp.org/help/ diff --git a/VerifyThis2024/Fibonacci.thy~ b/VerifyThis2024/Fibonacci.thy~ deleted file mode 100644 index 4502c8a..0000000 --- a/VerifyThis2024/Fibonacci.thy~ +++ /dev/null @@ -1,64 +0,0 @@ -theory Fibonacci -imports Main HOL.NthRoot -begin - -fun fib :: \nat \ nat\ where -\fib 0 = 0\| -\fib (Suc 0) = Suc 0\| -\fib (Suc (Suc n)) = fib (Suc n) + fib n\ - -definition \\ = (1 + sqrt 5)/2\ -definition \\ = (1 - sqrt 5)/2\ - -definition fib_intvl :: \nat \ nat set\ where -\fib_intvl n = {fib n.. - -lemma \_pow_2: \\^2 = (1 + \)\ unfolding \_def -proof- - have *: \(1+sqrt 5)\<^sup>2 = (1 + 2*sqrt 5 + 5)\ using power2_sum[of \1\ \sqrt 5\] by auto - have \((1 + sqrt 5) / 2)\<^sup>2 = (1+sqrt 5)\<^sup>2 / 4\ - by (simp add: power_divide) - hence \... = (1 + 2*sqrt 5 + 5) / 4\ using * by auto - hence \... = 2*(1 + sqrt 5)/4 + 1\ by simp - thus \((1 + sqrt 5) / 2)\<^sup>2= 1 + (1 + sqrt 5) / 2\ - by (smt (z3) "*" field_sum_of_halves four_x_squared) -qed - -lemma \_pow_2: \\^2 = (1 + \)\ -proof- - have *: \(1-sqrt 5)\<^sup>2 = (1 - 2*sqrt 5 + 5)\ using power2_diff[of \1\ \sqrt 5\] by auto - hence \(1-sqrt 5)\<^sup>2/4 = (1 - 2*sqrt 5 + 5)/4\ by auto - hence \... = 2*(1 - sqrt 5)/4 + 1\ by simp - thus ?thesis - by (smt (z3) "*" \_def field_sum_of_halves four_x_squared) -qed - -lemmas golden_ratios = \_def \_def - -lemma golden_diff: \(\ - \) = sqrt 5\ unfolding golden_ratios - by (smt (z3) field_sum_of_halves) - -lemma fib_correct: \fib n = (\^n - \^n) / sqrt 5\ -proof(induction n rule: fib.induct) - case 1 - then show ?case by simp -next - case 2 - then show ?case - by (simp add: golden_diff) -next - case (3 n) - then show ?case - proof- - have \real (fib (Suc (Suc n))) = real (fib (Suc n)) + real (fib n)\ by auto - moreover have \... = (\ ^ Suc n - \ ^ Suc n) / sqrt 5 + (\ ^ n - \ ^ n) / sqrt 5\ using 3 by auto - moreover have \... = (\ ^ Suc n + \^n - \ ^ Suc n - \ ^ n)/sqrt 5\ - by (smt (verit, best) add_divide_distrib) - moreover have \... = (\ ^ n * (\ + 1) - \ ^ n * (\ + 1))/ sqrt 5\ - by (simp add: distrib_right mult.commute) - ultimately show ?case using \_pow_2 \_pow_2 - by (metis add.commute add_2_eq_Suc power_add) - qed -qed - -end \ No newline at end of file diff --git a/VerifyThis2024/Ropes.thy~ b/VerifyThis2024/Ropes.thy~ deleted file mode 100644 index 785295a..0000000 --- a/VerifyThis2024/Ropes.thy~ +++ /dev/null @@ -1,235 +0,0 @@ -theory Ropes -imports Utils -begin - -section\Challenge 0 from VerifyThis 2024: \<^url>\https://www.pm.inf.ethz.ch/research/verifythis.html\\ - -subsection\The Rope Data Structure\ - -text\The task is to implement a "Rope" ( \<^url>\https://en.wikipedia.org/wiki/Rope_(data_structure)\ ) -originally published by Boehm - \<^url>\https://www.cs.tufts.edu/comp/150FP/archive/hans-boehm/ropes.pdf\ -- a special type of binary tree to represent a string (in honor of Billy who can't be here today).\ - -text\A Rope stores a string as a tree of where leaves contain a specific sub string and a weight that is equal to the number of characters in the sub string (see example from wiki page). -The corresponding parent node stores the sum of left children leaf weights (see example from wiki page).\ - -subsection\Tasks\ - -text\Implement a function @{term \valid_rope (r :: Rope) :: bool\} which checks that a rope is well constructed\ - -lemma mk_leaf_valid: \valid_rope (mk_leaf s)\ by simp - -value \to_str (Node (Leaf (STR ''Hello '') 6) 6 (Leaf (STR ''World'') 5))\ - -value \valid_rope (Node (Leaf (STR ''Hello '') 6) 6 (Leaf (STR ''World'') 5))\ - -text\Implement a function @{term \str_len (r :: Rope)\} that can efficiently compute the length of the string. Further, prove its correctness\ - -fun str_len :: \Rope \ nat\ where -\str_len (Leaf _ N) = N\| -\str_len (Node l w r) = w + str_len r\ - -value \size (to_str hello_world_rope)\ - -lemma sum_weights_eq_size: - assumes \valid_rope r\ - shows \sum_weights r = size (to_str r)\ -using assms proof(induction r) - case (Leaf s w) - then show ?case by simp -next - case (Node l w r) - have \sum_weights (Node l w r) = sum_weights l + sum_weights r\ by simp - moreover have \... = size (to_str l) + size (to_str r)\ using Node by simp - moreover have \... = size (to_str l + to_str r)\ using literal_plus_size_eq by simp - ultimately show ?case by simp -qed - -lemma str_len_eq_size: - assumes \valid_rope r\ - shows \str_len r = size (to_str r)\ -using assms proof(induction r) - case (Leaf s w) - then show ?case by simp -next - case (Node l w r) - hence left_valid: \valid_rope l\ and right_valid: \valid_rope r\ and w_def : \w = sum_weights l\ by simp+ - hence \str_len (Node l w r) = sum_weights l + str_len r\ by (simp add: Node) - moreover have \... = size (to_str l) + size (to_str r)\ by (simp add: sum_weights_eq_size left_valid right_valid Node) - moreover have \... = size (to_str l + to_str r)\ by (simp add: literal_plus_size_eq) - ultimately show ?case by simp -qed - -lemma str_len_sum_weights_eq: - assumes \valid_rope r\ - shows \str_len r = sum_weights r\ - using str_len_eq_size sum_weights_eq_size assms by auto - -text\Implement a function that computes the concatenation of two ropes @{term \rope_concat (l::Rope) (r :: Rope)\}\ - -definition rope_concat :: \Rope \ Rope \ Rope\ where -\rope_concat l r = Node l (str_len l) r\ - -lemma valid_rope_concat: - assumes \valid_rope l\ \valid_rope r\ - shows \valid_rope (rope_concat l r)\ by (simp add: assms str_len_sum_weights_eq rope_concat_def) - -lemma rope_concat_eq: \to_str (rope_concat l r) = to_str l + to_str r\ by (simp add: rope_concat_def) - -text\Implement a function @{term \rope_delete (r :: Rope) (i :: nat) (len :: nat)\} that returns a rope where the @{term \len\} -characters starting from the position @{term \i\} have been removed.\ - - -fun split :: \Rope \ nat \ Rope \ Rope\ where -\split (Leaf s w) i = (mk_leaf (sub_str s {0..| -\split (Node l w r) i = (if i < w then - (let (left, right) = split l i - in (left, rope_concat right r)) - else - (if i > w then - (let (left,right) = split r (i - w) - in (rope_concat l left, right)) - else (l,r)))\ - -value \split (Node (Leaf (STR ''44'') 2) 2 (Leaf (STR ''44'') 2)) 0\ - -value \split (mk_leaf STR ''a'') 0\ - -lemma valid_split: - assumes \valid_rope rope\ - shows \valid_rope (fst (split rope i)) \ valid_rope (snd (split rope i))\ -using assms proof(induction \rope\ arbitrary: i) - case (Leaf x1 x2) - then show ?case by simp -next - case (Node l' w r') - hence l'_valid: \valid_rope l'\ and r'_valid: \valid_rope r'\ by auto - hence l'_lsplit_valid: \valid_rope (fst (split l' i))\ and l'_rsplit_valid: \valid_rope (snd (split l' i))\ - and r'_lsplit_valid: \valid_rope (fst (split r' i))\ and r'_rsplit_valid: \valid_rope (snd (split r' i))\ - using Node by auto - show ?case - proof(cases \i < w\) - case True - then show ?thesis using l'_lsplit_valid l'_rsplit_valid - by (simp add: r'_valid split_beta valid_rope_concat) - next - case False - show ?thesis - proof(cases \i = w\) - case True - then show ?thesis - by (simp add: l'_valid r'_valid) - next - case False - then show ?thesis - by (simp add: Node.IH(2) l'_lsplit_valid l'_rsplit_valid l'_valid r'_valid split_beta valid_rope_concat) - qed - qed -qed - -fun short_rope :: \Rope \ bool\ where -\short_rope r = (str_len r \ 1)\ - -fun is_empty :: \Rope \ bool\ where -\is_empty r = (str_len r = 0)\ - -fun smart_rope_concat :: \Rope \ Rope \ Rope\ where -\smart_rope_concat (Leaf l w_l) (Leaf r w_r) = (if w_r \ 1 then Leaf (l + r) (w_l + w_r) else (Node (Leaf l w_l) w_l (Leaf r w_r)))\| -\smart_rope_concat (Node l w r) (Leaf r' w') = (if w' \ 1 then Node l w (smart_rope_concat r (Leaf r' w')) else (Node (Node l w r) w (Leaf r' w')))\| -\smart_rope_concat (Leaf l w) (Node l' w' r) = (if w \ 1 then Node (smart_rope_concat (Leaf l w) l') (w + w') r else (Node (Leaf l w) w (Node l' w' r)))\| -\smart_rope_concat (Node l w r) (Node l' w' r') = Node (Node l w r) w (Node l' w' r')\ - -value \smart_rope_concat (Node (mk_leaf STR ''?'') 1 (mk_leaf STR ''?'')) (mk_leaf STR '''')\ - -lemma smart_rope_concat_eq: - assumes \valid_rope l\ \valid_rope r\ - shows \to_str (smart_rope_concat l r) = to_str (rope_concat l r)\ -using assms proof(induction l ) - case (Leaf l w_l) - show ?case - using assms(2) proof(induction \r\) - case (Leaf r' w_r) - then show ?case - by (simp add: rope_concat_eq) - next - case (Node r_l w_r r') - then show ?case - by (simp add: add.assoc rope_concat_eq) - qed -next - case (Node l1 x2 l2) - then show ?case - using assms(2) proof(induction r) - case (Leaf x1 x2) - then show ?case - by (simp add: add.assoc rope_concat_eq) - next - case (Node r1 x2 r2) - then show ?case - by (simp add: rope_concat_def) - qed -qed - -lemma smart_concat_lessThanEq_rope_concat: - assumes \valid_rope l\ \valid_rope r\ - shows \size (smart_rope_concat l r) \ size(rope_concat l r)\ - using assms proof(induction l) - case (Leaf x1 x2) - then show ?case - using assms(2) proof(induction r) - case (Leaf x1 x2) - then show ?case - by (simp add: rope_concat_def) - next - case (Node r1 x2 r2) - then show ?case by (simp add: rope_concat_def) - qed -next - case (Node l1 x2 l2) - then show ?case using assms(2) by(induction r, simp_all add: rope_concat_def) -qed - -fun safe_rope_delete :: \Rope \ nat \ nat \ (Rope \ Rope)\ where -\safe_rope_delete rope i len = (let (left,rem) = split rope i; - (_, right) = split rem len; - return = (if is_empty left then right else if is_empty right then left else rope_concat left right) - in (rem, return))\ - -definition rope_delete :: \Rope \ nat \ nat \ Rope\ where -\rope_delete r i len = snd (safe_rope_delete r i len)\ - -definition rope_sub_str :: \Rope \ nat \ nat \ Rope\ where -\rope_sub_str r i len = fst (safe_rope_delete r i len)\ - - -definition \hello_my_rope \ rope_concat (Leaf STR ''Hello_'' 6) (Leaf STR ''my_'' 3)\ - -definition \name_i_rope \ rope_concat (Leaf STR ''na'' 2) (Leaf STR ''me_i'' 4)\ - -definition \s_Simon_rope \ rope_concat (Leaf STR ''s'' 1) (Leaf STR ''_Simon'' 6)\ - -definition \name_is_Simon_rope \ rope_concat name_i_rope s_Simon_rope\ - -definition \hello_my_name_is_Simon_rope \ rope_concat (rope_concat hello_my_rope name_is_Simon_rope) (Leaf STR '''' 0)\ - -value \to_str (rope_delete hello_my_name_is_Simon_rope (2) 15)\ - -text\Implement a function @{term \rope_insert (r :: Rope) (i :: nat) (s :: String.literal)\} that inserts the string @{term s} at position @{term \i\}.\ - -fun rope_insert :: \Rope \ nat \ String.literal \ Rope\ where -\rope_insert r i s = (let (left, right) = split r i in rope_concat (rope_concat left (mk_leaf s)) right)\ - -value \to_str (rope_insert hello_my_name_is_Simon_rope 9 STR ''first_'')\ - -definition \test r i len = rope_insert (rope_delete r i len) i (to_str (rope_sub_str r i len))\ - -value \safe_rope_delete (Node (Leaf STR ''a'' 1) 1 (Leaf STR ''a'' 1)) 1 1 \ - -lemma \rope_insert (rope_delete r i len) i (to_str (rope_sub_str r i len)) = r\ oops -text\These methods are correct as is, but do not perform the most optimally. Optimize these operations by implementing - a function @{term \rebalance\} that rebalances the the Rope.\ - -fun rebalance :: \Rope \ Rope\ where -\rebalance (Leaf s w) = Leaf s w\| -\rebalance (Node l w r) = \ -end \ No newline at end of file diff --git a/VerifyThis2024/Ropes_Template.thy~ b/VerifyThis2024/Ropes_Template.thy~ deleted file mode 100644 index b6ce564..0000000 --- a/VerifyThis2024/Ropes_Template.thy~ +++ /dev/null @@ -1,77 +0,0 @@ -theory Ropes_Template - imports Utils -begin - -chapter\Challenge 0 from VerifyThis 2024: \<^url>\https://www.pm.inf.ethz.ch/research/verifythis.html\\ - -section\The Rope Data Structure\ - -text\The task is to implement a "Rope" ( \<^url>\https://en.wikipedia.org/wiki/Rope_(data_structure)\ ) -originally published by Boehm - \<^url>\https://www.cs.tufts.edu/comp/150FP/archive/hans-boehm/ropes.pdf\ -- a special type of binary tree to efficiently store strings (in honor of Billy who can't be here today).\ - -text\Since the first half of this challenge is quite easy in HOL (termination and non crashing of basic functions), -we will skip the "trivial components" that can be found in \<^file>\Utils.thy\\ - -section\Tasks\ - -text\The following are my play on ADTs using locales. We have three tiers: - -\ Basic -\ Intermediate -\ Advanced - -\ -subsection\Basic Ropes\ - -text\ -Basic ropes require the implementation of efficient length calculation, -inefficient "naive" concatenation and finally splitting a rope into two across an index. -\ - -locale Basic_Ropes = - fixes str_len :: \Rope \ nat\ - and rope_concat :: \Rope \ Rope \ Rope\ - and rope_split :: \Rope \ nat \ Rope \ Rope\ -assumes \\r. valid_rope r \ str_len r = size (to_str r)\ - \\l r. \valid_rope l; valid_rope r\ \ to_str (rope_concat l r) = to_str l + to_str r\ - \\i r. valid_rope r \ valid_rope (fst (rope_split r i)) \ valid_rope (snd (rope_split r i))\ - -subsection\Intermediate Ropes\ - -text\Intermediate Ropes require the implementation of "efficient" concatenation as similar to Boehm's \<^url>\https://www.cs.tufts.edu/comp/150FP/archive/hans-boehm/ropes.pdf\. -and a naive implementation of delete, sub string and insert. Naive in the sense that deleting then inserting the same string is not structure preserving. -However inserting then deleting the same string should be structure preserving. -\ - -locale Intermediate_Ropes = Basic_Ropes + - fixes boehm_concat :: \Rope \ Rope \ Rope\ - and rope_delete :: \Rope \ nat \ nat \ Rope\ - and rope_sub_str :: \Rope \ nat \ nat \ Rope\ - and rope_insert :: \Rope \ nat \ String.literal \ Rope\ -assumes \\l r. \valid_rope l; valid_rope r\ \ to_str (boehm_concat l r) = to_str l + to_str r\ - \\l r. \valid_rope l; valid_rope r\ \ size (boehm_concat l r) \ size (rope_concat l r)\ - \\r i str. valid_rope r \ rope_delete (rope_insert r i str) i (size str) = r\ - \\r i len. valid_rope r \ to_str (rope_insert (rope_delete r i len) i (to_str (rope_sub_str r i len))) = to_str r\ - -subsection\Advanced Ropes\ - -text\Advanced Ropes are really what makes them useful data structures. -Before, all rope functions have been functionally correct, but not efficient due to the lack of rebalancing. -These require the implementation of a rebalance function to balance a Rope, and a function mk_rope which constructs a non-trivially balanced Rope from a string. -Using this rebalance function, implement efficient an efficient insert and delete which preserves the balancing of the tree\ - - -locale Advanced_Ropes = Intermediate_Ropes + - fixes max_leaf_size :: \nat\ - and rebalance :: \Rope \ Rope\ - and mk_Rope :: \String.literal \ Rope\ - and efficient_delete :: \Rope \ nat \ nat \ Rope\ - and efficient_insert :: \Rope \ nat \ String.literal \ Rope\ -assumes \\r. \ is_balanced r \ valid_rope r \ is_balanced (rebalance r)\ - \\s. is_balanced (mk_Rope s)\ - \\r i str. is_balanced r \ is_balanced (rope_insert r i str) \ (\leaf \# all_leaves (rope_insert r i str). str_len leaf \ {0<..max_leaf_size})\ - \\r i len. is_balanced r \ is_balanced (efficient_delete r i len)\ - - -end \ No newline at end of file diff --git a/VerifyThis2024/Utils.thy~ b/VerifyThis2024/Utils.thy~ deleted file mode 100644 index 9d71027..0000000 --- a/VerifyThis2024/Utils.thy~ +++ /dev/null @@ -1,89 +0,0 @@ -theory Utils - imports Main Fibonacci "HOL-Library.Multiset" -begin - -chapter\Helper Lemmas, Functions and Definitions\ - -section\String Literal helper lemmas for Rope proofs\ - -lemma literal_plus_size_eq: \size ((l::String.literal) + r) = size l + size r\ - by (simp add: plus_literal.rep_eq size_literal.rep_eq) - -fun sub_str :: \String.literal \ nat set \ String.literal\ where -\sub_str s I = String.implode (nths (literal.explode s) I)\ - -lemma explode_sub_str: \literal.explode (sub_str s I) = nths (literal.explode s) I\ - by (metis String.implode_explode_eq implode.rep_eq nths_map sub_str.simps) - -lemma size_implode_single: \size (String.implode [x]) = Suc 0\ by (simp add: size_literal.rep_eq) - -lemma size_implode: \size (String.implode xs) = length xs\ -proof(induction xs) - case Nil - then show ?case - by (simp add: size_literal.rep_eq) -next - case (Cons a xs) - have \size (String.implode (a # xs)) = (size (String.implode [a] + String.implode xs))\ - apply (simp add: String.implode_def) - by (metis String.explode_implode_eq add_0 add_Suc implode.abs_eq length_Cons list.simps(8,9) - list.size(3) literal_plus_size_eq size_literal.rep_eq) - moreover have \... = Suc (size (String.implode xs))\ by (simp add: literal_plus_size_eq size_implode_single) - moreover have \... = Suc (length xs)\ using Cons by blast - ultimately show ?case by simp -qed - -lemma size_sub_str: \size (sub_str s I) = card {i. i < size s \ i \ I}\ - by(simp add: size_implode length_nths size_literal.rep_eq) - -lemma atLeastLessThan_eq: \{i.. i \ ia}\ by auto - -lemma atLeastAtMost_eq: \(if i < size s then {..i} else {.. ia \ i}\ by auto - -lemma size_sub_str_atLeast: \size (sub_str s {i..}) = size s - i\ unfolding size_sub_str[of s \{i..}\] - by (simp add: atLeastLessThan_eq[symmetric]) - -lemma size_sub_str_atMost: \size (sub_str s {..i}) = (if i < size s then Suc i else size s)\ unfolding size_sub_str[of s \{..i}\] - by (simp add: atLeastAtMost_eq[symmetric]) - -section\Rope Definitions\ - -subsection\Basics\ - -datatype Rope = Leaf String.literal nat | Node Rope nat Rope - -definition \hello_world_rope \ Node (Leaf (STR ''Hello '') 6) 6 (Leaf (STR ''World'') 5)\ - -fun mk_leaf :: \String.literal \ Rope\ where -\mk_leaf s = Leaf s (size s)\ - -fun sum_weights :: \Rope \ nat\ where -\sum_weights (Leaf _ s) = s\| -\sum_weights (Node l w r) = sum_weights l + sum_weights r\ - -fun valid_rope :: \Rope \ bool\ where -\valid_rope (Leaf s w) = (size s = w)\| -\valid_rope (Node l w r) = (valid_rope l \ valid_rope r \ (w = sum_weights l))\ - -fun to_str :: \Rope \ String.literal\ where -\to_str (Leaf s _) = s\| -\to_str (Node l _ r) = to_str l + to_str r\ - -fun all_leaves :: \Rope \ Rope multiset\ where -\all_leaves (Leaf s w) = {# Leaf s w #}\| -\all_leaves (Node l _ r) = all_leaves l \# all_leaves r\ - -subsection\Advanced\ - -text\The following formalises the definition of balanced from Boehm \<^url>\https://www.cs.tufts.edu/comp/150FP/archive/hans-boehm/ropes.pdf\\ - -definition rope_width :: \Rope \ nat\ where -\rope_width r = size (all_leaves r)\ - -definition is_balanced :: \Rope \ bool\ where -\is_balanced r = (fib (size r + 2) \ sum_weights r)\ - -value \is_balanced hello_world_rope\ - -value \fib 5\ -end \ No newline at end of file