chapter \Exercise Sheet -- Week 9\ theory Exercise09 imports Main begin section \Exercise 1 -- 5 points\ text \As it was shown in the lecture, one can create a list type via pairs of a natural number (the length) and the index-function.\ definition is_list :: "(nat \ (nat \ 'a)) \ bool" where "is_list nf = (case nf of (n, f) \ \ i \ n. f i = undefined)" typedef 'a List = "{nf :: (nat \ (nat \ 'a)). is_list nf}" by (auto simp: is_list_def) text \Task 1: Define the upcoming four standard operations on lists on the representative type. (1 point)\ definition cons :: "'a \ nat \ (nat \ 'a) \ nat \ (nat \ 'a)" where "cons = undefined" definition tail :: "nat \ (nat \ 'a) \ nat \ (nat \ 'a)" where "tail = undefined" definition head :: "nat \ (nat \ 'a) \ 'a" where "head = undefined" definition nil :: "nat \ (nat \ 'a)" where "nil = undefined" text \Task 2: Use the lifting package to lift all four definitions from the representative type to @{typ "'a List"} (1 point)\ setup_lifting type_definition_List lift_definition NIL :: "'a List" is undefined sorry lift_definition CONS :: "'a \ 'a List \ 'a List" is undefined sorry lift_definition TAIL :: "'a List \ 'a List" is undefined sorry lift_definition HEAD :: "'a List \ 'a" is undefined sorry text \Task 3: Prove the upcoming three lemmas with the help of the transfer package. These show that the list operations work as expected. (1 point)\ lemma "HEAD (CONS x xs) = x" oops lemma "TAIL (CONS x xs) = xs" oops lemma "CONS x xs = CONS y ys \ x = y \ xs = ys" oops text \Task 4: Prove one of the following properties, i.e., either case-analysis or induction. (2 points) Of course you can also do both; the induction property is a bit more challenging.\ lemma "xs = NIL \ (\ y ys. xs = CONS y ys)" oops lemma "P NIL \ (\ x xs. P xs \ P (CONS x xs)) \ P ys" oops section \Exercise 2 -- 5 points\ (* existing formalization about trees from Lecture 09 and Exercise 08 *) datatype 'a tree = Leaf | Node "'a tree" 'a "'a tree" fun set_t :: "'a tree \ 'a set" where "set_t Leaf = {}" | "set_t (Node l x r) = set_t l \ {x} \ set_t r" inductive ordered :: "'a :: linorder tree \ bool" where oLeaf: "ordered Leaf" | oNode: "ordered l \ ordered r \ Ball (set_t l) (\ y. y < x) \ Ball (set_t r) (\ y. y > x) \ ordered (Node l x r)" fun member:: "'a :: linorder \ 'a tree \ bool" where "member x Leaf = False" | "member y (Node l x r) = (if x = y then True else if y < x then member y l else member y r)" lemma member_correct: "ordered t \ member x t = (x \ set_t t)" by (induction rule: ordered.induct, auto) fun insert_t :: "'a :: linorder \ 'a tree \ 'a tree" where "insert_t y Leaf = Node Leaf y Leaf" | "insert_t y (Node l x r) = (if x = y then Node l x r else if y < x then Node (insert_t y l) x r else Node l x (insert_t y r))" lemma set_insert_t[simp]: "set_t (insert_t x t) = insert x (set_t t)" by (induct t, auto) lemma ordered_insert_t: "ordered t \ ordered (insert_t x t)" by (induction rule: ordered.induct, auto intro!: oNode oLeaf) fun delete_right :: "'a :: linorder tree \ 'a tree \ 'a" where "delete_right (Node l x Leaf) = (l, x)" | "delete_right (Node l x r) = (case delete_right r of (r', y) \ (Node l x r', y))" fun delete :: "'a :: linorder \ 'a tree \ 'a tree" where "delete x Leaf = Leaf" | "delete x (Node l y r) = (if x < y then Node (delete x l) y r else if x > y then Node l y (delete x r) else if l = Leaf then r else case delete_right l of (l',z) \ Node l' z r)" lemma delete_right: "ordered t \ t \ Leaf \ delete_right t = (t', x) \ ordered t' \ set_t t = insert x (set_t t') \ Ball (set_t t') (\ y. y < x)" proof (induction t arbitrary: t' x rule: ordered.induct) case (oNode l r x t' y) thus ?case proof (cases r) case Leaf thus ?thesis using oNode by auto next case Node from oNode.prems[unfolded Node, simplified, folded Node] obtain r' where dr: "delete_right r = (r',y)" and t': "t' = Node l x r'" by (cases "delete_right r", auto) from Node have r: "r \ Leaf" by auto from oNode.IH(2)[OF r dr] oNode.hyps show ?thesis unfolding t' by (auto intro: ordered.intros) qed qed auto lemma delete: "ordered t \ ordered (delete x t) \ set_t (delete x t) = set_t t - {x}" proof (induction t rule: ordered.induct) case (oNode l r y) consider (LT) "x < y" | (EQ) "x = y" "l = Leaf" | (EQ2) "x = y" "l \ Leaf" | (GT) "x > y" by fastforce then show ?case proof cases case LT hence id: "delete x (Node l y r) = Node (delete x l) y r" by simp from oNode.IH(1) show ?thesis using oNode.hyps LT unfolding id by (auto intro: ordered.intros) next case EQ then show ?thesis using oNode.hyps by auto next case EQ2 obtain l' z where del: "delete_right l = (l',z)" by force from del EQ2 have id: "delete x (Node l y r) = Node l' z r" by auto from delete_right[OF _ EQ2(2) del] oNode.hyps have "ordered l' \ set_t l = insert z (set_t l') \ (\y\set_t l'. y < z)" by auto with oNode.hyps EQ2 show ?thesis unfolding id by (auto intro!: ordered.intros) next case GT hence id: "delete x (Node l y r) = Node l y (delete x r)" by auto from oNode.IH(2) show ?thesis using oNode.hyps GT unfolding id by (auto intro: ordered.intros) qed qed (auto intro: ordered.intros) typedef (overloaded) ('a :: linorder) otree = "{t :: 'a tree. ordered t}" by (intro exI[of _ Leaf], auto intro: ordered.intros) setup_lifting type_definition_otree lift_definition empty_o :: "('a :: linorder) otree" is Leaf by (auto intro: ordered.intros) lift_definition insert_o :: "'a :: linorder \ 'a otree \ 'a otree" is insert_t by (rule ordered_insert_t) lift_definition delete_o :: "'a :: linorder \ 'a otree \ 'a otree" is delete using delete by blast lift_definition member_o :: "'a :: linorder \ 'a otree \ bool" is member . lift_definition set_o :: "'a :: linorder otree \ 'a set" is set_t . lemma empty_o[simp]: "set_o empty_o = {}" apply transfer by auto lemma insert_o[simp]: "set_o (insert_o x t) = insert x (set_o t)" apply transfer using set_insert_t by auto lemma delete_o[simp]: "set_o (delete_o x t) = (set_o t) - {x}" apply transfer using delete by auto lemma member_o[simp]: "member_o x t = (x \ set_o t)" apply transfer using member_correct by auto fun flatten :: "'a tree \ 'a list" where "flatten Leaf = []" | "flatten (Node l x r) = flatten l @ x # flatten r" lemma flatten_set[simp]: "set (flatten t) = set_t t" by (induction t; fastforce) (* end of existing formalization *) text \In this exercise, we consider data structures that store additional information. As a concrete example, we consider a type of pairs (n,t) where n is a natural number, t is an ordered tree, and n is exactly the size of the tree, i.e., the cardinality of the set of elements in the tree. In this way, the size of the tree can be accessed in constant time.\ typedef (overloaded) ('a :: linorder) ctree = "{ (n,t) | (n :: nat) (t :: 'a otree). n = card (set_o t)}" sorry text \Task 1 -- 1 point Prove that the type is non-empty, define the following two functions: - \set_c :: 'a :: linordered ctree \ 'a set\ returns the elements of the tree as a set - \card_c :: 'a :: linordered ctree \ nat\ returns the stored size of the tree and then prove that \card_c\ is correct. Hint: \lift_definition\ accepts arbitrary expressions, e.g., \\ (n,t). something\. \ setup_lifting type_definition_ctree consts set_c :: "'a :: linorder ctree \ 'a set" (* replace by some proper definition *) consts card_c :: "'a :: linorder ctree \ nat" (* replace by some proper definition *) lemma card_c: "card_c t = card (set_c t)" sorry text \Task 2 -- 2 points Lift \empty_o\, \insert_o\, \delete_o\ and \member_o\ from \'a otree\ to \'a ctree\ and prove correctness of your implementations. For the reasoning about cardinalities, it might be useful to also prove that all sets that are represented by a tree are finite. \ lemma finite_set_o[simp]: "finite (set_o t)" sorry consts insert_c :: "'a :: linorder \ 'a ctree \ 'a ctree" (* replace by some proper definition *) consts delete_c :: "'a :: linorder \ 'a ctree \ 'a ctree" (* replace by some proper definition *) consts empty_c :: "'a :: linorder ctree" (* replace by some proper definition *) consts member_c :: "'a :: linorder \ 'a ctree \ bool" (* replace by some proper definition *) lemma empty_c: "set_c empty_c = {}" sorry lemma insert_c: "set_c (insert_c x t) = insert x (set_c t)" sorry lemma delete_c: "set_c (delete_c x t) = set_c t - {x}" sorry lemma member_c: "member_c x t = (x \ set_c t)" sorry text \Task 3 -- 2 points Now exploit the efficient access to the sizes by formalizing a union-operation on trees that works as follows: Given two trees, the algorithm first selects the smaller one, flattens that into a list, and then iteratively inserts all elements from the list into the larger tree. Hint: Whereas the flatten-function must first be lifted to work on \'a ctree\, all other functionality can stay on the abstract level and just use the abstract existing operations, i.e., by using definition principles like \fun\ and \definition\, but not \lift_definition\. \ consts flatten_c :: "'a :: linorder ctree \ 'a list" (* replace by some proper definition *) lemma flatten_c: "set (flatten_c t) = set_c t" sorry consts union_c :: "'a :: linorder ctree \ 'a ctree \ 'a ctree" (* replace by some proper definition *) lemma union_c: "set_c (union_c t1 t2) = set_c t1 \ set_c t2" sorry end