diff -r d826899bc424 -r 087d82632852 thys/FMap.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thys/FMap.thy Tue Apr 29 15:26:48 2014 +0100 @@ -0,0 +1,358 @@ +theory FMap + imports Main "~~/src/HOL/Quotient_Examples/FSet" "~~/src/HOL/Library/DAList" +begin + +subsubsection {* The type of finite maps *} + +typedef ('a, 'b) fmap (infixr "f\" 1) = "{x :: 'a \ 'b. finite (dom x) }" + proof show "empty \ {x. finite (dom x)}" by simp qed + +setup_lifting type_definition_fmap + +lift_definition fdom :: "'key f\ 'value \ 'key set" is "dom" .. + +lift_definition fran :: "'key f\ 'value \ 'value set" is "ran" .. + +lift_definition lookup :: "'key f\ 'value \ 'key \ 'value option" is "(\ x. x)" .. + +abbreviation the_lookup (infix "f!" 55) + where "m f! x \ the (lookup m x)" + +lift_definition fempty :: "'key f\ 'value" ("f\") is Map.empty by simp + +lemma fempty_fdom[simp]: "fdom f\ = {}" + by (transfer, auto) + +lemma fdomIff: "(a : fdom m) = (lookup m a \ None)" + by (transfer, auto) + +lemma lookup_not_fdom: "x \ fdom m \ lookup m x = None" + by (auto iff:fdomIff) + +lemma finite_range: + assumes "finite (dom m)" + shows "finite (ran m)" + apply (rule finite_subset[OF _ finite_imageI[OF assms, of "\ x . the (m x)"]]) + by (auto simp add: ran_def dom_def image_def) + +lemma finite_fdom[simp]: "finite (fdom m)" + by transfer + +lemma finite_fran[simp]: "finite (fran m)" + by (transfer, rule finite_range) + +lemma fmap_eqI[intro]: + assumes "fdom a = fdom b" + and "\ x. x \ fdom a \ a f! x = b f! x" + shows "a = b" +using assms +proof(transfer) + fix a b :: "'a \ 'b" + assume d: "dom a = dom b" + assume eq: "\ x. x \ dom a \ the (a x) = the (b x)" + show "a = b" + proof + fix x + show "a x = b x" + proof(cases "a x") + case None + hence "x \ dom a" by (simp add: dom_def) + hence "x \ dom b" using d by simp + hence " b x = None" by (simp add: dom_def) + thus ?thesis using None by simp + next + case (Some y) + hence d': "x \ dom ( a)" by (simp add: dom_def) + hence "the ( a x) = the ( b x)" using eq by auto + moreover + have "x \ dom ( b)" using Some d' d by simp + then obtain y' where " b x = Some y'" by (auto simp add: dom_def) + ultimately + show " a x = b x" using Some by auto + qed + qed +qed + +subsubsection {* Updates *} + +lift_definition + fmap_upd :: "'key f\ 'value \ 'key \ 'value \ 'key f\ 'value" ("_'(_ f\ _')" [900,900]900) + is "\ m x v. m( x \ v)" by simp + +lemma fmap_upd_fdom[simp]: "fdom (h (x f\ v)) = insert x (fdom h)" + by (transfer, auto) + +lemma the_lookup_fmap_upd[simp]: "lookup (h (x f\ v)) x = Some v" + by (transfer, auto) + +lemma the_lookup_fmap_upd_other[simp]: "x' \ x \ lookup (h (x f\ v)) x' = lookup h x'" + by (transfer, auto) + +lemma fmap_upd_overwrite[simp]: "f (x f\ y) (x f\ z) = f (x f\ z)" + by (transfer, auto) + +lemma fmap_upd_twist: "a \ c \ (m(a f\ b))(c f\ d) = (m(c f\ d))(a f\ b)" + apply (rule fmap_eqI) + apply auto[1] + apply (case_tac "x = a", auto) + apply (case_tac "x = c", auto) + done + +subsubsection {* Restriction *} + +lift_definition fmap_restr :: "'a set \ 'a f\ 'b \ 'a f\ 'b" + is "\ S m. (if finite S then (restrict_map m S) else empty)" by auto + +lemma lookup_fmap_restr[simp]: "finite S \ x \ S \ lookup (fmap_restr S m) x = lookup m x" + by (transfer, auto) + +lemma fdom_fmap_restr[simp]: "finite S \ fdom (fmap_restr S m) = fdom m \ S" + by (transfer, simp) + +lemma fmap_restr_fmap_restr[simp]: + "finite d1 \ finite d2 \ fmap_restr d1 (fmap_restr d2 x) = fmap_restr (d1 \ d2) x" + by (transfer, auto simp add: restrict_map_def) + +lemma fmap_restr_fmap_restr_subset: + "finite d2 \ d1 \ d2 \ fmap_restr d1 (fmap_restr d2 x) = fmap_restr d1 x" + by (metis Int_absorb2 finite_subset fmap_restr_fmap_restr) + +lemma fmap_restr_useless: "finite S \ fdom m \ S \ fmap_restr S m = m" + by (rule fmap_eqI, auto) + +lemma fmap_restr_not_finite: + "\ finite S \ fmap_restr S \ = f\" + by (transfer, simp) + +lemma fmap_restr_fmap_upd: "x \ S \ finite S \ fmap_restr S (m1(x f\ v)) = (fmap_restr S m1)(x f\ v)" + apply (rule fmap_eqI) + apply auto[1] + apply (case_tac "xa = x") + apply auto + done + +subsubsection {* Deleting *} + +lift_definition fmap_delete :: "'a \ 'a f\ 'b \ 'a f\ 'b" + is "\ x m. m(x := None)" by auto + +lemma fdom_fmap_delete[simp]: + "fdom (fmap_delete x m) = fdom m - {x}" + by (transfer, auto) + +lemma fmap_delete_fmap_upd[simp]: + "fmap_delete x (m(x f\ v)) = fmap_delete x m" + by (transfer, simp) + +lemma fmap_delete_noop: + "x \ fdom m \ fmap_delete x m = m" + by (transfer, auto) + +lemma fmap_upd_fmap_delete[simp]: "x \ fdom \ \ (fmap_delete x \)(x f\ \ f! x) = \" + by (transfer, auto) + +lemma fran_fmap_upd[simp]: + "fran (m(x f\ v)) = insert v (fran (fmap_delete x m))" +by (transfer, auto simp add: ran_def) + +subsubsection {* Addition (merging) of finite maps *} + +lift_definition fmap_add :: "'a f\ 'b \ 'a f\ 'b \ 'a f\ 'b" (infixl "f++" 100) + is "map_add" by auto + +lemma fdom_fmap_add[simp]: "fdom (m1 f++ m2) = fdom m1 \ fdom m2" + by (transfer, auto) + +lemma lookup_fmap_add1[simp]: "x \ fdom m2 \ lookup (m1 f++ m2) x = lookup m2 x" + by (transfer, auto) + +lemma lookup_fmap_add2[simp]: "x \ fdom m2 \ lookup (m1 f++ m2) x = lookup m1 x" + apply transfer + by (metis map_add_dom_app_simps(3)) + +lemma [simp]: "\ f++ f\ = \" + by (transfer, auto) + +lemma fmap_add_overwrite: "fdom m1 \ fdom m2 \ m1 f++ m2 = m2" + apply transfer + apply rule + apply (case_tac "x \ dom m2") + apply (auto simp add: map_add_dom_app_simps(1)) + done + +lemma fmap_add_upd_swap: + "x \ fdom \' \ \(x f\ z) f++ \' = (\ f++ \')(x f\ z)" + apply transfer + by (metis map_add_upd_left) + +lemma fmap_add_upd: + "\ f++ (\'(x f\ z)) = (\ f++ \')(x f\ z)" + apply transfer + by (metis map_add_upd) + +lemma fmap_restr_add: "fmap_restr S (m1 f++ m2) = fmap_restr S m1 f++ fmap_restr S m2" + apply (cases "finite S") + apply (rule fmap_eqI) + apply auto[1] + apply (case_tac "x \ fdom m2") + apply auto + apply (simp add: fmap_restr_not_finite) + done + +subsubsection {* Conversion from associative lists *} + +lift_definition fmap_of :: "('a \ 'b) list \ 'a f\ 'b" + is map_of by (rule finite_dom_map_of) + +lemma fmap_of_Nil[simp]: "fmap_of [] = f\" + by (transfer, simp) + +lemma fmap_of_Cons[simp]: "fmap_of (p # l) = (fmap_of l)(fst p f\ snd p)" + by (transfer, simp) + +lemma fmap_of_append[simp]: "fmap_of (l1 @ l2) = fmap_of l2 f++ fmap_of l1" + by (transfer, simp) + +lemma lookup_fmap_of[simp]: + "lookup (fmap_of m) x = map_of m x" + by (transfer, auto) + +lemma fmap_delete_fmap_of[simp]: + "fmap_delete x (fmap_of m) = fmap_of (AList.delete x m)" + by (transfer, metis delete_conv') + +subsubsection {* Less-than-relation for extending finite maps *} + +instantiation fmap :: (type,type) order +begin + definition "\ \ \' = ((fdom \ \ fdom \') \ (\x \ fdom \. lookup \ x = lookup \' x))" + definition "(\::'a f\ 'b) < \' = (\ \ \' \ \ \ \')" + + lemma fmap_less_eqI[intro]: + assumes assm1: "fdom \ \ fdom \'" + and assm2: "\ x. \ x \ fdom \ ; x \ fdom \' \ \ \ f! x = \' f! x " + shows "\ \ \'" + unfolding less_eq_fmap_def + apply rule + apply fact + apply rule+ + apply (frule subsetD[OF `_ \ _`]) + apply (frule assm2) + apply (auto iff: fdomIff) + done + + lemma fmap_less_eqD: + assumes "\ \ \'" + assumes "x \ fdom \" + shows "lookup \ x = lookup \' x" + using assms + unfolding less_eq_fmap_def by auto + + lemma fmap_antisym: assumes "(x:: 'a f\ 'b) \ y" and "y \ x" shows "x = y " + proof(rule fmap_eqI[rule_format]) + show "fdom x = fdom y" using `x \ y` and `y \ x` unfolding less_eq_fmap_def by auto + + fix v + assume "v \ fdom x" + hence "v \ fdom y" using `fdom _ = _` by simp + + thus "x f! v = y f! v" + using `x \ y` `v \ fdom x` unfolding less_eq_fmap_def by simp + qed + + lemma fmap_trans: assumes "(x:: 'a f\ 'b) \ y" and "y \ z" shows "x \ z" + proof + show "fdom x \ fdom z" using `x \ y` and `y \ z` unfolding less_eq_fmap_def + by -(rule order_trans [of _ "fdom y"], auto) + + fix v + assume "v \ fdom x" and "v \ fdom z" + hence "v \ fdom y" using `x \ y` unfolding less_eq_fmap_def by auto + hence "lookup y v = lookup x v" + using `x \ y` `v \ fdom x` unfolding less_eq_fmap_def by auto + moreover + have "lookup y v = lookup z v" + by (rule fmap_less_eqD[OF `y \ z` `v \ fdom y`]) + ultimately + show "x f! v = z f! v" by auto + qed + + instance + apply default + using fmap_antisym apply (auto simp add: less_fmap_def)[1] + apply (auto simp add: less_eq_fmap_def)[1] + using fmap_trans apply assumption + using fmap_antisym apply assumption + done +end + +lemma fmap_less_fdom: + "\1 \ \2 \ fdom \1 \ fdom \2" + by (metis less_eq_fmap_def) + +lemma fmap_less_restrict: + "\1 \ \2 \ \1 = fmap_restr (fdom \1) \2" + unfolding less_eq_fmap_def + apply transfer + apply (auto simp add:restrict_map_def split:option.split_asm) + by (metis option.simps(3))+ + +lemma fmap_restr_less: + "fmap_restr S \ \ \" + unfolding less_eq_fmap_def + by (transfer, auto) + +lemma fmap_upd_less[simp, intro]: + "\1 \ \2 \ v1 = v2 \ \1(x f\ v1) \ \2(x f\ v2)" + apply (rule fmap_less_eqI) + apply (auto dest: fmap_less_fdom)[1] + apply (case_tac "xa = x") + apply (auto dest: fmap_less_eqD) + done + +lemma fmap_update_less[simp, intro]: + "\1 \ \1' \ \2 \ \2' \ (fdom \2' - fdom \2) \ fdom \1 = {} \ \1 f++ \2 \ \1' f++ \2'" + apply (rule fmap_less_eqI) + apply (auto dest: fmap_less_fdom)[1] + apply (case_tac "x \ fdom \2") + apply (auto dest: fmap_less_eqD fmap_less_fdom) + apply (metis fmap_less_eqD fmap_less_fdom lookup_fmap_add1 set_mp) + by (metis Diff_iff Diff_triv fmap_less_eqD lookup_fmap_add2) + +lemma fmap_restr_le: + assumes "\1 \ \2" + assumes "S1 \ S2" + assumes [simp]:"finite S2" + shows "fmap_restr S1 \1 \ fmap_restr S2 \2" +proof- + have [simp]: "finite S1" + by (rule finite_subset[OF `S1 \ S2` `finite S2`]) + show ?thesis + proof (rule fmap_less_eqI) + have "fdom \1 \ fdom \2" + by (metis assms(1) less_eq_fmap_def) + thus "fdom (fmap_restr S1 \1) \ fdom (fmap_restr S2 \2)" + using `S1 \ S2` + by auto + next + fix x + assume "x \ fdom (fmap_restr S1 \1) " + hence [simp]:"x \ fdom \1" and [simp]:"x \ S1" and [simp]: "x \ S2" + by (auto intro: set_mp[OF `S1 \ S2`]) + have "\1 f! x = \2 f! x" + by (metis `x \ fdom \1` assms(1) less_eq_fmap_def) + thus "(fmap_restr S1 \1) f! x = (fmap_restr S2 \2) f! x" + by simp + qed +qed + +definition fmapdom_to_list :: "('a :: linorder) f\ 'b \ 'a list" +where + "fmapdom_to_list f = (THE xs. set xs = fdom f \ sorted xs \ distinct xs)" + +definition fmap_to_alist :: "('a :: linorder) f\ 'b \ ('a \ 'b) list" +where + "fmap_to_alist f = [(x, f f! x). x \ fmapdom_to_list f]" + + +end