theory a2 imports Main begin (*-------------------------------------------------------------*) (* INTRODUCTION *) (* The IMP language *) (* ~~~~~~~~~~~~~~~~ *) type_synonym vname = string type_synonym state = "vname \ nat" type_synonym aexp = "state \ nat" type_synonym bexp = "state \ bool" datatype com = SKIP | Assign vname aexp ("_ :== _ " [60,60] 60) | Semi com com ("_;; _" [50, 51] 50) | Cond bexp com com ("IF _ THEN _ ELSE _ FI" [0,0,59] 60) | While bexp com ("WHILE _ DO _ OD" [0,45] 60) (* IMP semantics *) (* ~~~~~~~~~~~~~ *) inductive eval :: "com \ state \ state \ bool" ("_/ \ _" [60,60] 61) where Skip [intro!,simp]: "(SKIP, s) \ s" | Assign [intro!,simp]: "(x :== a, s) \ s (x := a s)" | Semi [intro!]: "\ (c\<^sub>1,s) \ s''; (c\<^sub>2,s'') \ s' \ \ (c\<^sub>1;; c\<^sub>2, s) \ s'" | IfTrue[intro]: "\ b s; (c\<^sub>1,s) \ s' \ \ (IF b THEN c\<^sub>1 ELSE c\<^sub>2 FI, s) \ s'" | IfFalse[intro]: "\ \b s; (c\<^sub>2,s) \ s' \ \ (IF b THEN c\<^sub>1 ELSE c\<^sub>2 FI, s) \ s'" | WhileFalse[intro]: "\b s \ (WHILE b DO c OD, s) \ s" | WhileTrue[intro]: "\b s; (c,s) \ s''; (WHILE b DO c OD, s'') \ s'\ \ (WHILE b DO c OD, s) \ s'" (* The default induction rule only allows eval to have 2 parameters. We define a new induction rule eval_induct where we split the first tuple to get the 3 parameters c, s and s'*) thm eval.induct lemmas eval_induct = eval.induct[split_format(complete)] thm eval_induct (* We want to deduce from "(SKIP,s) \ t" that "s = t". We want to deduce from "(x:==a,s) \ t" that "t = s(x := a s)". Etc. We do this with the following *) inductive_cases skip [elim!]: "(SKIP, s) \ s'" and assign [elim!]: "(x :== a, s) \ s'" and semi [elim!]: "(c\<^sub>1;; c\<^sub>2, s) \ s'" and "if" [elim!]: "(IF b THEN c\<^sub>1 ELSE c\<^sub>2 FI, s) \ s'" and while: "(WHILE b DO c OD, s) \ s'" lemma skip_eq [simp]: "(SKIP, s) \ s' = (s' = s)" by blast lemma assign_eq [simp]: "(x :== a, s) \ s' = (s' = s (x := a s))" by blast (* EXAMPLE PROGRAMS *) (* ~~~~~~~~~~~~~~~~ *) definition max :: com where "max \ (IF (\s. s ''A'' > s ''B'') THEN ''R'' :== (\s. s ''A'') ELSE ''R'' :== (\s. s ''B'') FI)" definition factorial :: com where "factorial \ ''B'' :== (\s. 1);; WHILE (\s. s ''A'' \ 0) DO ''B'' :== (\s. s ''B'' * s ''A'');; ''A'' :== (\s. s ''A'' - 1) OD" (*---------------------------------------------------------*) (* QUESTION 1: Variable Assignment (10 marks) *) (* (a) Define var_assig :: "com \ vname set" (7 marks)*) (* TODO *) lemma assig_max: "var_assig max = {''R''}" by eval lemma assig_factorial: "var_assig factorial = {''A'',''B''}" by eval (* (b) Prove the following lemma (3 marks)*) lemma eval_assig: "\ (c, s) \ t; x \ var_assig c \ \ s x = t x" (* TODO *) sorry (*---------------------------------------------------------*) (* QUESTION 2: Equivalent programs (12 marks) *) (* Definition of equivalent programs *) definition equival :: "com \ com \ bool" (infix "\" 50) where "c \ c' \ (\s t. (c,s) \ t = (c',s) \ t)" (* (a) Prove that \ is an equivalence relation (3 marks)*) lemma equival_refl: "c\c" (*TODO*) sorry lemma equival_sym: "(c\c')=(c'\c)" (*TODO*) sorry lemma equival_trans: "\x\y; y\z\\ x\z" (*TODO*) sorry (* (b) Prove the following lemma (2 marks) *) lemma equival_semi: "\c\c'; d\d'\\ (c;;d)\(c';;d')" (*TODO*) sorry (* (c) Prove the following lemma (2 marks) *) lemma equival_if: "\c\c'; d\d'\ \ IF b THEN c ELSE d FI\ IF b THEN c' ELSE d' FI" (*TODO*) sorry (* (d) Prove the following lemma (2 marks) *) lemma equival_while_aux: "\(p,s) \ t; p=WHILE b DO c OD; c \ c'\ \ (WHILE b DO c' OD,s) \ t" (*TODO*) sorry (* (e) Prove the following lemma (2 marks) *) lemma equival_while: "c\c'\ WHILE b DO c OD \ WHILE b DO c' OD" (*TODO*) sorry (*---------------------------------------------------------*) (* QUESTION 3: The SKIP command (30 marks) *) primrec equivtoskip :: "com \ bool" where "equivtoskip SKIP = True" | "equivtoskip (x:==a) = False" | "equivtoskip (c1;;c2) = (equivtoskip c1 \ equivtoskip c2)" | "equivtoskip (IF b THEN c1 ELSE c2 FI) = (equivtoskip c1 \ equivtoskip c2)" | "equivtoskip (WHILE b DO c OD) = False" (* (a) Prove equivtoskip is correct (5 marks) *) lemma equivtoskip_correct: "equivtoskip c \ c \ SKIP" (*TODO*) sorry (* (b) Find some program that behaves like SKIP but for which equivtoskip returns False (5 marks) *) lemma not_equivtoskip: "\c. c \ SKIP \ \ equivtoskip c" (*TODO*) sorry (* (c) Define less_skip :: "com \ com" (5 marks) *) (*TODO*) lemma less_skip1: "less_skip ((SKIP;;SKIP);; WHILE b DO (x :== a;; SKIP) OD) = WHILE b DO x :== a OD" (*TODO*) sorry lemma less_skip2: "less_skip (IF b THEN (SKIP;;SKIP) ELSE (x :== a;; SKIP) FI) = (IF b THEN SKIP ELSE x :== a FI)" (*TODO*) sorry lemma less_skip3: "less_skip (IF b THEN (SKIP;;SKIP) ELSE SKIP FI) = SKIP" (*TODO*) sorry lemma less_skip4: "less_skip (WHILE b DO (SKIP;;SKIP) OD) = (WHILE b DO SKIP OD)" (*TODO*) sorry (* (d) Prove less_skip is correct (15 marks) *) lemma less_skip_correct: "less_skip c \ c" (*TODO *) sorry (*---------------------------------------------------------*) (* QUESTION 4: Sequencing associativity (36 marks)*) (* Tree structure *) datatype tag = S | A vname aexp | C bexp | W bexp datatype tree = Node tag "tree list" | Branch tree tree (* Function from command to tree *) fun com_to_tree where "com_to_tree SKIP = Node S []" | "com_to_tree (Assign v a) = Node (A v a) []" | "com_to_tree (Semi c1 c2) = Branch (com_to_tree c1) (com_to_tree c2)" | "com_to_tree (Cond b c1 c2) = Node (C b) [com_to_tree c1, com_to_tree c2]" | "com_to_tree (While b c) = Node (W b) [com_to_tree c]" (* (a) Define function from tree to command: tree_to_com :: "tree \ com" (3 marks) *) (* TODO *) (* (b) Proof the following lemma (2 marks) *) lemma com_to_tree_inverse: "tree_to_com (com_to_tree c) = c" (* TODO *) sorry (* (c) Define wf_tree:: "tree \ bool" and prove the following lemma (6 marks)*) lemma tree_to_com_inverse[simp]: "wf_tree t \ com_to_tree (tree_to_com t) = t" (*TODO*) sorry (* (d) Define Branch_assoc and prove its termination (10 marks) *) function Branch_assoc where "Branch_assoc (Branch (Branch t1 t2) t3) = Branch_assoc (Branch t1 (Branch t2 t3))" | "Branch_assoc (Branch (Node t ls) t3) = Branch (Node t (map Branch_assoc ls)) (Branch_assoc t3)" | "Branch_assoc (Node t ls) = Node t (map Branch_assoc ls)" (*TODO*) sorry termination Branch_assoc apply (relation "inv_image (less_than <*lex*> less_than) (\t. (size\<^sub>1 t, size\<^sub>2 t))") (*TODO*) sorry (* (e) We first define map_Semi: *) fun map_Semi where "map_Semi f (Semi c1 c2) = f (map_Semi f c1) (map_Semi f c2)" | "map_Semi f (Cond b c1 c2) = Cond b (map_Semi f c1) (map_Semi f c2)" | "map_Semi f (While b c) = While b (map_Semi f c)" | "map_Semi f x = x" (* Now define Semi_assoc1:: "com \ com \ com" such that you can prove Branch_assoc_map (10 marks) *) fun Semi_assoc1 where (* TODO *) lemma Branch_assoc_map: "wf_tree t \ tree_to_com (Branch_assoc t) = map_Semi Semi_assoc1 (tree_to_com t)" (*TODO*) sorry (* (f) Prove that the transformation preserves the semantics (5 marks) *) theorem Branch_assoc_eval: "(c,s) \ s' \ (tree_to_com (Branch_assoc (com_to_tree c)),s) \ s'" (*TODO*) sorry (*---------------------------------------------------------*) section \ Compilation (12 marks) \ (* LAB language *) (* ~~~~~~~~~~~~ *) type_synonym label = nat datatype lcom = LAssign vname aexp | Label label | LCGoto bexp label | LGoto label type_synonym lprog = "lcom list" (* EXAMPLES *) (* ~~~~~~~~ *) definition lmax :: lprog where "lmax \ [ LCGoto (\s. s ''A'' \ s ''B'') 0, LAssign ''R'' (\s. s ''A''), LGoto 1, Label 0, LAssign ''R'' (\s. s ''B''), Label 1]" definition lfactorial :: lprog where "lfactorial \ [ LAssign ''B'' (\s. 1), Label 1, LCGoto (\s. s ''A'' = 0) 0, LAssign ''B'' (\s. s ''B'' * s ''A''), LAssign ''A'' (\s. s ''A'' - 1), LGoto 1, Label 0]" (* Define compile::"com \ lprog" such that you can prove compile_max and compile_factorial. You may need a helper function compile' :: "com \ label\ lprog \ label" *) lemma compile_max: "compile max =lmax" (*TODO*) sorry lemma compile_factorial: "compile factorial =lfactorial" (*TODO*) sorry end