diff --git a/src/HOL/Finite_Set.thy b/src/HOL/Finite_Set.thy --- a/src/HOL/Finite_Set.thy +++ b/src/HOL/Finite_Set.thy @@ -1,2351 +1,2526 @@ (* Title: HOL/Finite_Set.thy Author: Tobias Nipkow Author: Lawrence C Paulson Author: Markus Wenzel Author: Jeremy Avigad Author: Andrei Popescu *) section \Finite sets\ theory Finite_Set imports Product_Type Sum_Type Fields begin subsection \Predicate for finite sets\ context notes [[inductive_internals]] begin inductive finite :: "'a set \ bool" where emptyI [simp, intro!]: "finite {}" | insertI [simp, intro!]: "finite A \ finite (insert a A)" end simproc_setup finite_Collect ("finite (Collect P)") = \K Set_Comprehension_Pointfree.simproc\ declare [[simproc del: finite_Collect]] lemma finite_induct [case_names empty insert, induct set: finite]: \ \Discharging \x \ F\ entails extra work.\ assumes "finite F" assumes "P {}" and insert: "\x F. finite F \ x \ F \ P F \ P (insert x F)" shows "P F" using \finite F\ proof induct show "P {}" by fact next fix x F assume F: "finite F" and P: "P F" show "P (insert x F)" proof cases assume "x \ F" then have "insert x F = F" by (rule insert_absorb) with P show ?thesis by (simp only:) next assume "x \ F" from F this P show ?thesis by (rule insert) qed qed lemma infinite_finite_induct [case_names infinite empty insert]: assumes infinite: "\A. \ finite A \ P A" and empty: "P {}" and insert: "\x F. finite F \ x \ F \ P F \ P (insert x F)" shows "P A" proof (cases "finite A") case False with infinite show ?thesis . next case True then show ?thesis by (induct A) (fact empty insert)+ qed subsubsection \Choice principles\ lemma ex_new_if_finite: \ \does not depend on def of finite at all\ assumes "\ finite (UNIV :: 'a set)" and "finite A" shows "\a::'a. a \ A" proof - from assms have "A \ UNIV" by blast then show ?thesis by blast qed text \A finite choice principle. Does not need the SOME choice operator.\ lemma finite_set_choice: "finite A \ \x\A. \y. P x y \ \f. \x\A. P x (f x)" proof (induct rule: finite_induct) case empty then show ?case by simp next case (insert a A) then obtain f b where f: "\x\A. P x (f x)" and ab: "P a b" by auto show ?case (is "\f. ?P f") proof show "?P (\x. if x = a then b else f x)" using f ab by auto qed qed subsubsection \Finite sets are the images of initial segments of natural numbers\ lemma finite_imp_nat_seg_image_inj_on: assumes "finite A" shows "\(n::nat) f. A = f ` {i. i < n} \ inj_on f {i. i < n}" using assms proof induct case empty show ?case proof show "\f. {} = f ` {i::nat. i < 0} \ inj_on f {i. i < 0}" by simp qed next case (insert a A) have notinA: "a \ A" by fact from insert.hyps obtain n f where "A = f ` {i::nat. i < n}" "inj_on f {i. i < n}" by blast then have "insert a A = f(n:=a) ` {i. i < Suc n}" and "inj_on (f(n:=a)) {i. i < Suc n}" using notinA by (auto simp add: image_def Ball_def inj_on_def less_Suc_eq) then show ?case by blast qed lemma nat_seg_image_imp_finite: "A = f ` {i::nat. i < n} \ finite A" proof (induct n arbitrary: A) case 0 then show ?case by simp next case (Suc n) let ?B = "f ` {i. i < n}" have finB: "finite ?B" by (rule Suc.hyps[OF refl]) show ?case proof (cases "\k (\n f. A = f ` {i::nat. i < n})" by (blast intro: nat_seg_image_imp_finite dest: finite_imp_nat_seg_image_inj_on) lemma finite_imp_inj_to_nat_seg: assumes "finite A" shows "\f n. f ` A = {i::nat. i < n} \ inj_on f A" proof - from finite_imp_nat_seg_image_inj_on [OF \finite A\] obtain f and n :: nat where bij: "bij_betw f {i. i ?f ` A = {i. i k}" by (simp add: le_eq_less_or_eq Collect_disj_eq) subsection \Finiteness and common set operations\ lemma rev_finite_subset: "finite B \ A \ B \ finite A" proof (induct arbitrary: A rule: finite_induct) case empty then show ?case by simp next case (insert x F A) have A: "A \ insert x F" and r: "A - {x} \ F \ finite (A - {x})" by fact+ show "finite A" proof cases assume x: "x \ A" with A have "A - {x} \ F" by (simp add: subset_insert_iff) with r have "finite (A - {x})" . then have "finite (insert x (A - {x}))" .. also have "insert x (A - {x}) = A" using x by (rule insert_Diff) finally show ?thesis . next show ?thesis when "A \ F" using that by fact assume "x \ A" with A show "A \ F" by (simp add: subset_insert_iff) qed qed lemma finite_subset: "A \ B \ finite B \ finite A" by (rule rev_finite_subset) lemma finite_UnI: assumes "finite F" and "finite G" shows "finite (F \ G)" using assms by induct simp_all lemma finite_Un [iff]: "finite (F \ G) \ finite F \ finite G" by (blast intro: finite_UnI finite_subset [of _ "F \ G"]) lemma finite_insert [simp]: "finite (insert a A) \ finite A" proof - have "finite {a} \ finite A \ finite A" by simp then have "finite ({a} \ A) \ finite A" by (simp only: finite_Un) then show ?thesis by simp qed lemma finite_Int [simp, intro]: "finite F \ finite G \ finite (F \ G)" by (blast intro: finite_subset) lemma finite_Collect_conjI [simp, intro]: "finite {x. P x} \ finite {x. Q x} \ finite {x. P x \ Q x}" by (simp add: Collect_conj_eq) lemma finite_Collect_disjI [simp]: "finite {x. P x \ Q x} \ finite {x. P x} \ finite {x. Q x}" by (simp add: Collect_disj_eq) lemma finite_Diff [simp, intro]: "finite A \ finite (A - B)" by (rule finite_subset, rule Diff_subset) lemma finite_Diff2 [simp]: assumes "finite B" shows "finite (A - B) \ finite A" proof - have "finite A \ finite ((A - B) \ (A \ B))" by (simp add: Un_Diff_Int) also have "\ \ finite (A - B)" using \finite B\ by simp finally show ?thesis .. qed lemma finite_Diff_insert [iff]: "finite (A - insert a B) \ finite (A - B)" proof - have "finite (A - B) \ finite (A - B - {a})" by simp moreover have "A - insert a B = A - B - {a}" by auto ultimately show ?thesis by simp qed lemma finite_compl [simp]: "finite (A :: 'a set) \ finite (- A) \ finite (UNIV :: 'a set)" by (simp add: Compl_eq_Diff_UNIV) lemma finite_Collect_not [simp]: "finite {x :: 'a. P x} \ finite {x. \ P x} \ finite (UNIV :: 'a set)" by (simp add: Collect_neg_eq) lemma finite_Union [simp, intro]: "finite A \ (\M. M \ A \ finite M) \ finite (\A)" by (induct rule: finite_induct) simp_all lemma finite_UN_I [intro]: "finite A \ (\a. a \ A \ finite (B a)) \ finite (\a\A. B a)" by (induct rule: finite_induct) simp_all lemma finite_UN [simp]: "finite A \ finite (\(B ` A)) \ (\x\A. finite (B x))" by (blast intro: finite_subset) lemma finite_Inter [intro]: "\A\M. finite A \ finite (\M)" by (blast intro: Inter_lower finite_subset) lemma finite_INT [intro]: "\x\I. finite (A x) \ finite (\x\I. A x)" by (blast intro: INT_lower finite_subset) lemma finite_imageI [simp, intro]: "finite F \ finite (h ` F)" by (induct rule: finite_induct) simp_all lemma finite_image_set [simp]: "finite {x. P x} \ finite {f x |x. P x}" by (simp add: image_Collect [symmetric]) lemma finite_image_set2: "finite {x. P x} \ finite {y. Q y} \ finite {f x y |x y. P x \ Q y}" by (rule finite_subset [where B = "\x \ {x. P x}. \y \ {y. Q y}. {f x y}"]) auto lemma finite_imageD: assumes "finite (f ` A)" and "inj_on f A" shows "finite A" using assms proof (induct "f ` A" arbitrary: A) case empty then show ?case by simp next case (insert x B) then have B_A: "insert x B = f ` A" by simp then obtain y where "x = f y" and "y \ A" by blast from B_A \x \ B\ have "B = f ` A - {x}" by blast with B_A \x \ B\ \x = f y\ \inj_on f A\ \y \ A\ have "B = f ` (A - {y})" by (simp add: inj_on_image_set_diff) moreover from \inj_on f A\ have "inj_on f (A - {y})" by (rule inj_on_diff) ultimately have "finite (A - {y})" by (rule insert.hyps) then show "finite A" by simp qed lemma finite_image_iff: "inj_on f A \ finite (f ` A) \ finite A" using finite_imageD by blast lemma finite_surj: "finite A \ B \ f ` A \ finite B" by (erule finite_subset) (rule finite_imageI) lemma finite_range_imageI: "finite (range g) \ finite (range (\x. f (g x)))" by (drule finite_imageI) (simp add: range_composition) lemma finite_subset_image: assumes "finite B" shows "B \ f ` A \ \C\A. finite C \ B = f ` C" using assms proof induct case empty then show ?case by simp next case insert then show ?case by (clarsimp simp del: image_insert simp add: image_insert [symmetric]) blast qed lemma all_subset_image: "(\B. B \ f ` A \ P B) \ (\B. B \ A \ P(f ` B))" by (safe elim!: subset_imageE) (use image_mono in \blast+\) (* slow *) lemma all_finite_subset_image: "(\B. finite B \ B \ f ` A \ P B) \ (\B. finite B \ B \ A \ P (f ` B))" proof safe fix B :: "'a set" assume B: "finite B" "B \ f ` A" and P: "\B. finite B \ B \ A \ P (f ` B)" show "P B" using finite_subset_image [OF B] P by blast qed blast lemma ex_finite_subset_image: "(\B. finite B \ B \ f ` A \ P B) \ (\B. finite B \ B \ A \ P (f ` B))" proof safe fix B :: "'a set" assume B: "finite B" "B \ f ` A" and "P B" show "\B. finite B \ B \ A \ P (f ` B)" using finite_subset_image [OF B] \P B\ by blast qed blast lemma finite_vimage_IntI: "finite F \ inj_on h A \ finite (h -` F \ A)" proof (induct rule: finite_induct) case (insert x F) then show ?case by (simp add: vimage_insert [of h x F] finite_subset [OF inj_on_vimage_singleton] Int_Un_distrib2) qed simp lemma finite_finite_vimage_IntI: assumes "finite F" and "\y. y \ F \ finite ((h -` {y}) \ A)" shows "finite (h -` F \ A)" proof - have *: "h -` F \ A = (\ y\F. (h -` {y}) \ A)" by blast show ?thesis by (simp only: * assms finite_UN_I) qed lemma finite_vimageI: "finite F \ inj h \ finite (h -` F)" using finite_vimage_IntI[of F h UNIV] by auto lemma finite_vimageD': "finite (f -` A) \ A \ range f \ finite A" by (auto simp add: subset_image_iff intro: finite_subset[rotated]) lemma finite_vimageD: "finite (h -` F) \ surj h \ finite F" by (auto dest: finite_vimageD') lemma finite_vimage_iff: "bij h \ finite (h -` F) \ finite F" unfolding bij_def by (auto elim: finite_vimageD finite_vimageI) lemma finite_Collect_bex [simp]: assumes "finite A" shows "finite {x. \y\A. Q x y} \ (\y\A. finite {x. Q x y})" proof - have "{x. \y\A. Q x y} = (\y\A. {x. Q x y})" by auto with assms show ?thesis by simp qed lemma finite_Collect_bounded_ex [simp]: assumes "finite {y. P y}" shows "finite {x. \y. P y \ Q x y} \ (\y. P y \ finite {x. Q x y})" proof - have "{x. \y. P y \ Q x y} = (\y\{y. P y}. {x. Q x y})" by auto with assms show ?thesis by simp qed lemma finite_Plus: "finite A \ finite B \ finite (A <+> B)" by (simp add: Plus_def) lemma finite_PlusD: fixes A :: "'a set" and B :: "'b set" assumes fin: "finite (A <+> B)" shows "finite A" "finite B" proof - have "Inl ` A \ A <+> B" by auto then have "finite (Inl ` A :: ('a + 'b) set)" using fin by (rule finite_subset) then show "finite A" by (rule finite_imageD) (auto intro: inj_onI) next have "Inr ` B \ A <+> B" by auto then have "finite (Inr ` B :: ('a + 'b) set)" using fin by (rule finite_subset) then show "finite B" by (rule finite_imageD) (auto intro: inj_onI) qed lemma finite_Plus_iff [simp]: "finite (A <+> B) \ finite A \ finite B" by (auto intro: finite_PlusD finite_Plus) lemma finite_Plus_UNIV_iff [simp]: "finite (UNIV :: ('a + 'b) set) \ finite (UNIV :: 'a set) \ finite (UNIV :: 'b set)" by (subst UNIV_Plus_UNIV [symmetric]) (rule finite_Plus_iff) lemma finite_SigmaI [simp, intro]: "finite A \ (\a. a\A \ finite (B a)) \ finite (SIGMA a:A. B a)" unfolding Sigma_def by blast lemma finite_SigmaI2: assumes "finite {x\A. B x \ {}}" and "\a. a \ A \ finite (B a)" shows "finite (Sigma A B)" proof - from assms have "finite (Sigma {x\A. B x \ {}} B)" by auto also have "Sigma {x:A. B x \ {}} B = Sigma A B" by auto finally show ?thesis . qed lemma finite_cartesian_product: "finite A \ finite B \ finite (A \ B)" by (rule finite_SigmaI) lemma finite_Prod_UNIV: "finite (UNIV :: 'a set) \ finite (UNIV :: 'b set) \ finite (UNIV :: ('a \ 'b) set)" by (simp only: UNIV_Times_UNIV [symmetric] finite_cartesian_product) lemma finite_cartesian_productD1: assumes "finite (A \ B)" and "B \ {}" shows "finite A" proof - from assms obtain n f where "A \ B = f ` {i::nat. i < n}" by (auto simp add: finite_conv_nat_seg_image) then have "fst ` (A \ B) = fst ` f ` {i::nat. i < n}" by simp with \B \ {}\ have "A = (fst \ f) ` {i::nat. i < n}" by (simp add: image_comp) then have "\n f. A = f ` {i::nat. i < n}" by blast then show ?thesis by (auto simp add: finite_conv_nat_seg_image) qed lemma finite_cartesian_productD2: assumes "finite (A \ B)" and "A \ {}" shows "finite B" proof - from assms obtain n f where "A \ B = f ` {i::nat. i < n}" by (auto simp add: finite_conv_nat_seg_image) then have "snd ` (A \ B) = snd ` f ` {i::nat. i < n}" by simp with \A \ {}\ have "B = (snd \ f) ` {i::nat. i < n}" by (simp add: image_comp) then have "\n f. B = f ` {i::nat. i < n}" by blast then show ?thesis by (auto simp add: finite_conv_nat_seg_image) qed lemma finite_cartesian_product_iff: "finite (A \ B) \ (A = {} \ B = {} \ (finite A \ finite B))" by (auto dest: finite_cartesian_productD1 finite_cartesian_productD2 finite_cartesian_product) lemma finite_prod: "finite (UNIV :: ('a \ 'b) set) \ finite (UNIV :: 'a set) \ finite (UNIV :: 'b set)" using finite_cartesian_product_iff[of UNIV UNIV] by simp lemma finite_Pow_iff [iff]: "finite (Pow A) \ finite A" proof assume "finite (Pow A)" then have "finite ((\x. {x}) ` A)" by (blast intro: finite_subset) (* somewhat slow *) then show "finite A" by (rule finite_imageD [unfolded inj_on_def]) simp next assume "finite A" then show "finite (Pow A)" by induct (simp_all add: Pow_insert) qed corollary finite_Collect_subsets [simp, intro]: "finite A \ finite {B. B \ A}" by (simp add: Pow_def [symmetric]) lemma finite_set: "finite (UNIV :: 'a set set) \ finite (UNIV :: 'a set)" by (simp only: finite_Pow_iff Pow_UNIV[symmetric]) lemma finite_UnionD: "finite (\A) \ finite A" by (blast intro: finite_subset [OF subset_Pow_Union]) lemma finite_bind: assumes "finite S" assumes "\x \ S. finite (f x)" shows "finite (Set.bind S f)" using assms by (simp add: bind_UNION) lemma finite_filter [simp]: "finite S \ finite (Set.filter P S)" unfolding Set.filter_def by simp lemma finite_set_of_finite_funs: assumes "finite A" "finite B" shows "finite {f. \x. (x \ A \ f x \ B) \ (x \ A \ f x = d)}" (is "finite ?S") proof - let ?F = "\f. {(a,b). a \ A \ b = f a}" have "?F ` ?S \ Pow(A \ B)" by auto from finite_subset[OF this] assms have 1: "finite (?F ` ?S)" by simp have 2: "inj_on ?F ?S" by (fastforce simp add: inj_on_def set_eq_iff fun_eq_iff) (* somewhat slow *) show ?thesis by (rule finite_imageD [OF 1 2]) qed lemma not_finite_existsD: assumes "\ finite {a. P a}" shows "\a. P a" proof (rule classical) assume "\ ?thesis" with assms show ?thesis by auto qed subsection \Further induction rules on finite sets\ lemma finite_ne_induct [case_names singleton insert, consumes 2]: assumes "finite F" and "F \ {}" assumes "\x. P {x}" and "\x F. finite F \ F \ {} \ x \ F \ P F \ P (insert x F)" shows "P F" using assms proof induct case empty then show ?case by simp next case (insert x F) then show ?case by cases auto qed lemma finite_subset_induct [consumes 2, case_names empty insert]: assumes "finite F" and "F \ A" and empty: "P {}" and insert: "\a F. finite F \ a \ A \ a \ F \ P F \ P (insert a F)" shows "P F" using \finite F\ \F \ A\ proof induct show "P {}" by fact next fix x F assume "finite F" and "x \ F" and P: "F \ A \ P F" and i: "insert x F \ A" show "P (insert x F)" proof (rule insert) from i show "x \ A" by blast from i have "F \ A" by blast with P show "P F" . show "finite F" by fact show "x \ F" by fact qed qed lemma finite_empty_induct: assumes "finite A" and "P A" and remove: "\a A. finite A \ a \ A \ P A \ P (A - {a})" shows "P {}" proof - have "P (A - B)" if "B \ A" for B :: "'a set" proof - from \finite A\ that have "finite B" by (rule rev_finite_subset) from this \B \ A\ show "P (A - B)" proof induct case empty from \P A\ show ?case by simp next case (insert b B) have "P (A - B - {b})" proof (rule remove) from \finite A\ show "finite (A - B)" by induct auto from insert show "b \ A - B" by simp from insert show "P (A - B)" by simp qed also have "A - B - {b} = A - insert b B" by (rule Diff_insert [symmetric]) finally show ?case . qed qed then have "P (A - A)" by blast then show ?thesis by simp qed lemma finite_update_induct [consumes 1, case_names const update]: assumes finite: "finite {a. f a \ c}" and const: "P (\a. c)" and update: "\a b f. finite {a. f a \ c} \ f a = c \ b \ c \ P f \ P (f(a := b))" shows "P f" using finite proof (induct "{a. f a \ c}" arbitrary: f) case empty with const show ?case by simp next case (insert a A) then have "A = {a'. (f(a := c)) a' \ c}" and "f a \ c" by auto with \finite A\ have "finite {a'. (f(a := c)) a' \ c}" by simp have "(f(a := c)) a = c" by simp from insert \A = {a'. (f(a := c)) a' \ c}\ have "P (f(a := c))" by simp with \finite {a'. (f(a := c)) a' \ c}\ \(f(a := c)) a = c\ \f a \ c\ have "P ((f(a := c))(a := f a))" by (rule update) then show ?case by simp qed lemma finite_subset_induct' [consumes 2, case_names empty insert]: assumes "finite F" and "F \ A" and empty: "P {}" and insert: "\a F. \finite F; a \ A; F \ A; a \ F; P F \ \ P (insert a F)" shows "P F" using assms(1,2) proof induct show "P {}" by fact next fix x F assume "finite F" and "x \ F" and P: "F \ A \ P F" and i: "insert x F \ A" show "P (insert x F)" proof (rule insert) from i show "x \ A" by blast from i have "F \ A" by blast with P show "P F" . show "finite F" by fact show "x \ F" by fact show "F \ A" by fact qed qed subsection \Class \finite\\ class finite = assumes finite_UNIV: "finite (UNIV :: 'a set)" begin lemma finite [simp]: "finite (A :: 'a set)" by (rule subset_UNIV finite_UNIV finite_subset)+ lemma finite_code [code]: "finite (A :: 'a set) \ True" by simp end instance prod :: (finite, finite) finite by standard (simp only: UNIV_Times_UNIV [symmetric] finite_cartesian_product finite) lemma inj_graph: "inj (\f. {(x, y). y = f x})" by (rule inj_onI) (auto simp add: set_eq_iff fun_eq_iff) instance "fun" :: (finite, finite) finite proof show "finite (UNIV :: ('a \ 'b) set)" proof (rule finite_imageD) let ?graph = "\f::'a \ 'b. {(x, y). y = f x}" have "range ?graph \ Pow UNIV" by simp moreover have "finite (Pow (UNIV :: ('a * 'b) set))" by (simp only: finite_Pow_iff finite) ultimately show "finite (range ?graph)" by (rule finite_subset) show "inj ?graph" by (rule inj_graph) qed qed instance bool :: finite by standard (simp add: UNIV_bool) instance set :: (finite) finite by standard (simp only: Pow_UNIV [symmetric] finite_Pow_iff finite) instance unit :: finite by standard (simp add: UNIV_unit) instance sum :: (finite, finite) finite by standard (simp only: UNIV_Plus_UNIV [symmetric] finite_Plus finite) subsection \A basic fold functional for finite sets\ -text \The intended behaviour is - \fold f z {x\<^sub>1, \, x\<^sub>n} = f x\<^sub>1 (\ (f x\<^sub>n z)\)\ - if \f\ is ``left-commutative'': +text \ + The intended behaviour is \fold f z {x\<^sub>1, \, x\<^sub>n} = f x\<^sub>1 (\ (f x\<^sub>n z)\)\ + if \f\ is ``left-commutative''. + The commutativity requirement is relativised to the carrier set \S\: \ -locale comp_fun_commute = +locale comp_fun_commute_on = + fixes S :: "'a set" fixes f :: "'a \ 'b \ 'b" - assumes comp_fun_commute: "f y \ f x = f x \ f y" + assumes comp_fun_commute_on: "x \ S \ y \ S \ f y \ f x = f x \ f y" begin -lemma fun_left_comm: "f y (f x z) = f x (f y z)" - using comp_fun_commute by (simp add: fun_eq_iff) +lemma fun_left_comm: "x \ S \ y \ S \ f y (f x z) = f x (f y z)" + using comp_fun_commute_on by (simp add: fun_eq_iff) -lemma commute_left_comp: "f y \ (f x \ g) = f x \ (f y \ g)" - by (simp add: o_assoc comp_fun_commute) +lemma commute_left_comp: "x \ S \ y \ S \ f y \ (f x \ g) = f x \ (f y \ g)" + by (simp add: o_assoc comp_fun_commute_on) end inductive fold_graph :: "('a \ 'b \ 'b) \ 'b \ 'a set \ 'b \ bool" for f :: "'a \ 'b \ 'b" and z :: 'b where emptyI [intro]: "fold_graph f z {} z" | insertI [intro]: "x \ A \ fold_graph f z A y \ fold_graph f z (insert x A) (f x y)" inductive_cases empty_fold_graphE [elim!]: "fold_graph f z {} x" lemma fold_graph_closed_lemma: "fold_graph f z A x \ x \ B" if "fold_graph g z A x" "\a b. a \ A \ b \ B \ f a b = g a b" "\a b. a \ A \ b \ B \ g a b \ B" "z \ B" using that(1-3) proof (induction rule: fold_graph.induct) case (insertI x A y) have "fold_graph f z A y" "y \ B" unfolding atomize_conj by (rule insertI.IH) (auto intro: insertI.prems) then have "g x y \ B" and f_eq: "f x y = g x y" by (auto simp: insertI.prems) moreover have "fold_graph f z (insert x A) (f x y)" by (rule fold_graph.insertI; fact) ultimately show ?case by (simp add: f_eq) qed (auto intro!: that) lemma fold_graph_closed_eq: "fold_graph f z A = fold_graph g z A" if "\a b. a \ A \ b \ B \ f a b = g a b" "\a b. a \ A \ b \ B \ g a b \ B" "z \ B" using fold_graph_closed_lemma[of f z A _ B g] fold_graph_closed_lemma[of g z A _ B f] that by auto definition fold :: "('a \ 'b \ 'b) \ 'b \ 'a set \ 'b" where "fold f z A = (if finite A then (THE y. fold_graph f z A y) else z)" lemma fold_closed_eq: "fold f z A = fold g z A" if "\a b. a \ A \ b \ B \ f a b = g a b" "\a b. a \ A \ b \ B \ g a b \ B" "z \ B" unfolding Finite_Set.fold_def by (subst fold_graph_closed_eq[where B=B and g=g]) (auto simp: that) text \ - A tempting alternative for the definiens is + A tempting alternative for the definition is \<^term>\if finite A then THE y. fold_graph f z A y else e\. It allows the removal of finiteness assumptions from the theorems \fold_comm\, \fold_reindex\ and \fold_distrib\. The proofs become ugly. It is not worth the effort. (???) \ lemma finite_imp_fold_graph: "finite A \ \x. fold_graph f z A x" by (induct rule: finite_induct) auto subsubsection \From \<^const>\fold_graph\ to \<^term>\fold\\ -context comp_fun_commute +context comp_fun_commute_on begin lemma fold_graph_finite: assumes "fold_graph f z A y" shows "finite A" using assms by induct simp_all lemma fold_graph_insertE_aux: - "fold_graph f z A y \ a \ A \ \y'. y = f a y' \ fold_graph f z (A - {a}) y'" + assumes "A \ S" + assumes "fold_graph f z A y" "a \ A" + shows "\y'. y = f a y' \ fold_graph f z (A - {a}) y'" + using assms(2-,1) proof (induct set: fold_graph) case emptyI then show ?case by simp next case (insertI x A y) show ?case proof (cases "x = a") case True with insertI show ?thesis by auto next case False then obtain y' where y: "y = f a y'" and y': "fold_graph f z (A - {a}) y'" using insertI by auto - have "f x y = f a (f x y')" - unfolding y by (rule fun_left_comm) + from insertI have "x \ S" "a \ S" by auto + then have "f x y = f a (f x y')" + unfolding y by (intro fun_left_comm; simp) moreover have "fold_graph f z (insert x A - {a}) (f x y')" using y' and \x \ a\ and \x \ A\ by (simp add: insert_Diff_if fold_graph.insertI) ultimately show ?thesis by fast qed qed lemma fold_graph_insertE: + assumes "insert x A \ S" assumes "fold_graph f z (insert x A) v" and "x \ A" obtains y where "v = f x y" and "fold_graph f z A y" - using assms by (auto dest: fold_graph_insertE_aux [OF _ insertI1]) + using assms by (auto dest: fold_graph_insertE_aux[OF \insert x A \ S\ _ insertI1]) -lemma fold_graph_determ: "fold_graph f z A x \ fold_graph f z A y \ y = x" +lemma fold_graph_determ: + assumes "A \ S" + assumes "fold_graph f z A x" "fold_graph f z A y" + shows "y = x" + using assms(2-,1) proof (induct arbitrary: y set: fold_graph) case emptyI then show ?case by fast next case (insertI x A y v) - from \fold_graph f z (insert x A) v\ and \x \ A\ + from \insert x A \ S\ and \fold_graph f z (insert x A) v\ and \x \ A\ obtain y' where "v = f x y'" and "fold_graph f z A y'" by (rule fold_graph_insertE) - from \fold_graph f z A y'\ have "y' = y" - by (rule insertI) + from \fold_graph f z A y'\ insertI have "y' = y" + by simp with \v = f x y'\ show "v = f x y" by simp qed -lemma fold_equality: "fold_graph f z A y \ fold f z A = y" +lemma fold_equality: "A \ S \ fold_graph f z A y \ fold f z A = y" by (cases "finite A") (auto simp add: fold_def intro: fold_graph_determ dest: fold_graph_finite) lemma fold_graph_fold: + assumes "A \ S" assumes "finite A" shows "fold_graph f z A (fold f z A)" proof - - from assms have "\x. fold_graph f z A x" + from \finite A\ have "\x. fold_graph f z A x" by (rule finite_imp_fold_graph) - moreover note fold_graph_determ + moreover note fold_graph_determ[OF \A \ S\] ultimately have "\!x. fold_graph f z A x" by (rule ex_ex1I) then have "fold_graph f z A (The (fold_graph f z A))" by (rule theI') with assms show ?thesis by (simp add: fold_def) qed text \The base case for \fold\:\ lemma (in -) fold_infinite [simp]: "\ finite A \ fold f z A = z" by (auto simp: fold_def) lemma (in -) fold_empty [simp]: "fold f z {} = z" by (auto simp: fold_def) text \The various recursion equations for \<^const>\fold\:\ lemma fold_insert [simp]: + assumes "insert x A \ S" assumes "finite A" and "x \ A" shows "fold f z (insert x A) = f x (fold f z A)" -proof (rule fold_equality) +proof (rule fold_equality[OF \insert x A \ S\]) fix z - from \finite A\ have "fold_graph f z A (fold f z A)" - by (rule fold_graph_fold) + from \insert x A \ S\ \finite A\ have "fold_graph f z A (fold f z A)" + by (blast intro: fold_graph_fold) with \x \ A\ have "fold_graph f z (insert x A) (f x (fold f z A))" by (rule fold_graph.insertI) then show "fold_graph f z (insert x A) (f x (fold f z A))" by simp qed declare (in -) empty_fold_graphE [rule del] fold_graph.intros [rule del] \ \No more proofs involve these.\ -lemma fold_fun_left_comm: "finite A \ f x (fold f z A) = fold f (f x z) A" +lemma fold_fun_left_comm: + assumes "insert x A \ S" "finite A" + shows "f x (fold f z A) = fold f (f x z) A" + using assms(2,1) proof (induct rule: finite_induct) case empty then show ?case by simp next - case insert - then show ?case - by (simp add: fun_left_comm [of x]) + case (insert y F) + then have "fold f (f x z) (insert y F) = f y (fold f (f x z) F)" + by simp + also have "\ = f x (f y (fold f z F))" + using insert by (simp add: fun_left_comm[where ?y=x]) + also have "\ = f x (fold f z (insert y F))" + proof - + from insert have "insert y F \ S" by simp + from fold_insert[OF this] insert show ?thesis by simp + qed + finally show ?case .. qed -lemma fold_insert2: "finite A \ x \ A \ fold f z (insert x A) = fold f (f x z) A" +lemma fold_insert2: + "insert x A \ S \ finite A \ x \ A \ fold f z (insert x A) = fold f (f x z) A" by (simp add: fold_fun_left_comm) lemma fold_rec: + assumes "A \ S" assumes "finite A" and "x \ A" shows "fold f z A = f x (fold f z (A - {x}))" proof - have A: "A = insert x (A - {x})" using \x \ A\ by blast then have "fold f z A = fold f z (insert x (A - {x}))" by simp also have "\ = f x (fold f z (A - {x}))" - by (rule fold_insert) (simp add: \finite A\)+ + by (rule fold_insert) (use assms in \auto\) finally show ?thesis . qed lemma fold_insert_remove: + assumes "insert x A \ S" assumes "finite A" shows "fold f z (insert x A) = f x (fold f z (A - {x}))" proof - from \finite A\ have "finite (insert x A)" by auto moreover have "x \ insert x A" by auto ultimately have "fold f z (insert x A) = f x (fold f z (insert x A - {x}))" - by (rule fold_rec) + using \insert x A \ S\ by (blast intro: fold_rec) then show ?thesis by simp qed lemma fold_set_union_disj: + assumes "A \ S" "B \ S" assumes "finite A" "finite B" "A \ B = {}" shows "Finite_Set.fold f z (A \ B) = Finite_Set.fold f (Finite_Set.fold f z A) B" - using assms(2,1,3) by induct simp_all + using \finite B\ assms(1,2,3,5) +proof induct + case (insert x F) + have "fold f z (A \ insert x F) = f x (fold f (fold f z A) F)" + using insert by auto + also have "\ = fold f (fold f z A) (insert x F)" + using insert by (blast intro: fold_insert[symmetric]) + finally show ?case . +qed simp + end text \Other properties of \<^const>\fold\:\ +lemma fold_graph_image: + assumes "inj_on g A" + shows "fold_graph f z (g ` A) = fold_graph (f \ g) z A" +proof + fix w + show "fold_graph f z (g ` A) w = fold_graph (f o g) z A w" + proof + assume "fold_graph f z (g ` A) w" + then show "fold_graph (f \ g) z A w" + using assms + proof (induct "g ` A" w arbitrary: A) + case emptyI + then show ?case by (auto intro: fold_graph.emptyI) + next + case (insertI x A r B) + from \inj_on g B\ \x \ A\ \insert x A = image g B\ obtain x' A' + where "x' \ A'" and [simp]: "B = insert x' A'" "x = g x'" "A = g ` A'" + by (rule inj_img_insertE) + from insertI.prems have "fold_graph (f \ g) z A' r" + by (auto intro: insertI.hyps) + with \x' \ A'\ have "fold_graph (f \ g) z (insert x' A') ((f \ g) x' r)" + by (rule fold_graph.insertI) + then show ?case + by simp + qed + next + assume "fold_graph (f \ g) z A w" + then show "fold_graph f z (g ` A) w" + using assms + proof induct + case emptyI + then show ?case + by (auto intro: fold_graph.emptyI) + next + case (insertI x A r) + from \x \ A\ insertI.prems have "g x \ g ` A" + by auto + moreover from insertI have "fold_graph f z (g ` A) r" + by simp + ultimately have "fold_graph f z (insert (g x) (g ` A)) (f (g x) r)" + by (rule fold_graph.insertI) + then show ?case + by simp + qed + qed +qed + lemma fold_image: assumes "inj_on g A" shows "fold f z (g ` A) = fold (f \ g) z A" proof (cases "finite A") case False with assms show ?thesis by (auto dest: finite_imageD simp add: fold_def) next case True - have "fold_graph f z (g ` A) = fold_graph (f \ g) z A" - proof - fix w - show "fold_graph f z (g ` A) w \ fold_graph (f \ g) z A w" (is "?P \ ?Q") - proof - assume ?P - then show ?Q - using assms - proof (induct "g ` A" w arbitrary: A) - case emptyI - then show ?case by (auto intro: fold_graph.emptyI) - next - case (insertI x A r B) - from \inj_on g B\ \x \ A\ \insert x A = image g B\ obtain x' A' - where "x' \ A'" and [simp]: "B = insert x' A'" "x = g x'" "A = g ` A'" - by (rule inj_img_insertE) - from insertI.prems have "fold_graph (f \ g) z A' r" - by (auto intro: insertI.hyps) - with \x' \ A'\ have "fold_graph (f \ g) z (insert x' A') ((f \ g) x' r)" - by (rule fold_graph.insertI) - then show ?case - by simp - qed - next - assume ?Q - then show ?P - using assms - proof induct - case emptyI - then show ?case - by (auto intro: fold_graph.emptyI) - next - case (insertI x A r) - from \x \ A\ insertI.prems have "g x \ g ` A" - by auto - moreover from insertI have "fold_graph f z (g ` A) r" - by simp - ultimately have "fold_graph f z (insert (g x) (g ` A)) (f (g x) r)" - by (rule fold_graph.insertI) - then show ?case - by simp - qed - qed - qed - with True assms show ?thesis - by (auto simp add: fold_def) + then show ?thesis + by (auto simp add: fold_def fold_graph_image[OF assms]) qed lemma fold_cong: - assumes "comp_fun_commute f" "comp_fun_commute g" - and "finite A" + assumes "comp_fun_commute_on S f" "comp_fun_commute_on S g" + and "A \ S" "finite A" and cong: "\x. x \ A \ f x = g x" and "s = t" and "A = B" shows "fold f s A = fold g t B" proof - have "fold f s A = fold g s A" - using \finite A\ cong + using \finite A\ \A \ S\ cong proof (induct A) case empty then show ?case by simp next case insert - interpret f: comp_fun_commute f by (fact \comp_fun_commute f\) - interpret g: comp_fun_commute g by (fact \comp_fun_commute g\) + interpret f: comp_fun_commute_on S f by (fact \comp_fun_commute_on S f\) + interpret g: comp_fun_commute_on S g by (fact \comp_fun_commute_on S g\) from insert show ?case by simp qed with assms show ?thesis by simp qed text \A simplified version for idempotent functions:\ -locale comp_fun_idem = comp_fun_commute + - assumes comp_fun_idem: "f x \ f x = f x" +locale comp_fun_idem_on = comp_fun_commute_on + + assumes comp_fun_idem_on: "x \ S \ f x \ f x = f x" begin -lemma fun_left_idem: "f x (f x z) = f x z" - using comp_fun_idem by (simp add: fun_eq_iff) +lemma fun_left_idem: "x \ S \ f x (f x z) = f x z" + using comp_fun_idem_on by (simp add: fun_eq_iff) lemma fold_insert_idem: + assumes "insert x A \ S" assumes fin: "finite A" shows "fold f z (insert x A) = f x (fold f z A)" proof cases assume "x \ A" then obtain B where "A = insert x B" and "x \ B" by (rule set_insert) then show ?thesis - using assms by (simp add: comp_fun_idem fun_left_idem) + using assms by (simp add: comp_fun_idem_on fun_left_idem) next assume "x \ A" then show ?thesis - using assms by simp + using assms by auto qed declare fold_insert [simp del] fold_insert_idem [simp] -lemma fold_insert_idem2: "finite A \ fold f z (insert x A) = fold f (f x z) A" +lemma fold_insert_idem2: "insert x A \ S \ finite A \ fold f z (insert x A) = fold f (f x z) A" by (simp add: fold_fun_left_comm) end -subsubsection \Liftings to \comp_fun_commute\ etc.\ - -lemma (in comp_fun_commute) comp_comp_fun_commute: "comp_fun_commute (f \ g)" - by standard (simp_all add: comp_fun_commute) +subsubsection \Liftings to \comp_fun_commute_on\ etc.\ + +lemma (in comp_fun_commute_on) comp_comp_fun_commute_on: + "range g \ S \ comp_fun_commute_on R (f \ g)" + by standard (force intro: comp_fun_commute_on) -lemma (in comp_fun_idem) comp_comp_fun_idem: "comp_fun_idem (f \ g)" - by (rule comp_fun_idem.intro, rule comp_comp_fun_commute, unfold_locales) - (simp_all add: comp_fun_idem) +lemma (in comp_fun_idem_on) comp_comp_fun_idem_on: + assumes "range g \ S" + shows "comp_fun_idem_on R (f \ g)" +proof + interpret f_g: comp_fun_commute_on R "f o g" + by (fact comp_comp_fun_commute_on[OF \range g \ S\]) + show "x \ R \ y \ R \ (f \ g) y \ (f \ g) x = (f \ g) x \ (f \ g) y" for x y + by (fact f_g.comp_fun_commute_on) +qed (use \range g \ S\ in \force intro: comp_fun_idem_on\) -lemma (in comp_fun_commute) comp_fun_commute_funpow: "comp_fun_commute (\x. f x ^^ g x)" +lemma (in comp_fun_commute_on) comp_fun_commute_on_funpow: + "comp_fun_commute_on S (\x. f x ^^ g x)" proof - show "f y ^^ g y \ f x ^^ g x = f x ^^ g x \ f y ^^ g y" for x y + fix x y assume "x \ S" "y \ S" + show "f y ^^ g y \ f x ^^ g x = f x ^^ g x \ f y ^^ g y" proof (cases "x = y") case True then show ?thesis by simp next case False show ?thesis proof (induct "g x" arbitrary: g) case 0 then show ?case by simp next case (Suc n g) have hyp1: "f y ^^ g y \ f x = f x \ f y ^^ g y" proof (induct "g y" arbitrary: g) case 0 then show ?case by simp next case (Suc n g) define h where "h z = g z - 1" for z with Suc have "n = h y" by simp with Suc have hyp: "f y ^^ h y \ f x = f x \ f y ^^ h y" by auto from Suc h_def have "g y = Suc (h y)" by simp - then show ?case - by (simp add: comp_assoc hyp) (simp add: o_assoc comp_fun_commute) + with \x \ S\ \y \ S\ show ?case + by (simp add: comp_assoc hyp) (simp add: o_assoc comp_fun_commute_on) qed define h where "h z = (if z = x then g x - 1 else g z)" for z with Suc have "n = h x" by simp with Suc have "f y ^^ h y \ f x ^^ h x = f x ^^ h x \ f y ^^ h y" by auto with False h_def have hyp2: "f y ^^ g y \ f x ^^ h x = f x ^^ h x \ f y ^^ g y" by simp from Suc h_def have "g x = Suc (h x)" by simp then show ?case by (simp del: funpow.simps add: funpow_Suc_right o_assoc hyp2) (simp add: comp_assoc hyp1) qed qed qed +subsubsection \\<^term>\UNIV\ as carrier set\ + +locale comp_fun_commute = + fixes f :: "'a \ 'b \ 'b" + assumes comp_fun_commute: "f y \ f x = f x \ f y" +begin + +lemma (in -) comp_fun_commute_def': "comp_fun_commute f = comp_fun_commute_on UNIV f" + unfolding comp_fun_commute_def comp_fun_commute_on_def by blast + +text \ + We abuse the \rewrites\ functionality of locales to remove trivial assumptions that + result from instantiating the carrier set to \<^term>\UNIV\. +\ +sublocale comp_fun_commute_on UNIV f + rewrites "\X. (X \ UNIV) \ True" + and "\x. x \ UNIV \ True" + and "\P. (True \ P) \ Trueprop P" + and "\P Q. (True \ PROP P \ PROP Q) \ (PROP P \ True \ PROP Q)" +proof - + show "comp_fun_commute_on UNIV f" + by standard (simp add: comp_fun_commute) +qed simp_all + +end + +lemma (in comp_fun_commute) comp_comp_fun_commute: "comp_fun_commute (f o g)" + unfolding comp_fun_commute_def' by (fact comp_comp_fun_commute_on) + +lemma (in comp_fun_commute) comp_fun_commute_funpow: "comp_fun_commute (\x. f x ^^ g x)" + unfolding comp_fun_commute_def' by (fact comp_fun_commute_on_funpow) + +locale comp_fun_idem = comp_fun_commute + + assumes comp_fun_idem: "f x o f x = f x" +begin + +lemma (in -) comp_fun_idem_def': "comp_fun_idem f = comp_fun_idem_on UNIV f" + unfolding comp_fun_idem_on_def comp_fun_idem_def comp_fun_commute_def' + unfolding comp_fun_idem_axioms_def comp_fun_idem_on_axioms_def + by blast + +text \ + Again, we abuse the \rewrites\ functionality of locales to remove trivial assumptions that + result from instantiating the carrier set to \<^term>\UNIV\. +\ +sublocale comp_fun_idem_on UNIV f + rewrites "\X. (X \ UNIV) \ True" + and "\x. x \ UNIV \ True" + and "\P. (True \ P) \ Trueprop P" + and "\P Q. (True \ PROP P \ PROP Q) \ (PROP P \ True \ PROP Q)" +proof - + show "comp_fun_idem_on UNIV f" + by standard (simp_all add: comp_fun_idem comp_fun_commute) +qed simp_all + +end + +lemma (in comp_fun_idem) comp_comp_fun_idem: "comp_fun_idem (f o g)" + unfolding comp_fun_idem_def' by (fact comp_comp_fun_idem_on) + + subsubsection \Expressing set operations via \<^const>\fold\\ lemma comp_fun_commute_const: "comp_fun_commute (\_. f)" by standard rule lemma comp_fun_idem_insert: "comp_fun_idem insert" by standard auto lemma comp_fun_idem_remove: "comp_fun_idem Set.remove" by standard auto lemma (in semilattice_inf) comp_fun_idem_inf: "comp_fun_idem inf" by standard (auto simp add: inf_left_commute) lemma (in semilattice_sup) comp_fun_idem_sup: "comp_fun_idem sup" by standard (auto simp add: sup_left_commute) lemma union_fold_insert: assumes "finite A" shows "A \ B = fold insert B A" proof - interpret comp_fun_idem insert by (fact comp_fun_idem_insert) from \finite A\ show ?thesis by (induct A arbitrary: B) simp_all qed lemma minus_fold_remove: assumes "finite A" shows "B - A = fold Set.remove B A" proof - interpret comp_fun_idem Set.remove by (fact comp_fun_idem_remove) from \finite A\ have "fold Set.remove B A = B - A" by (induct A arbitrary: B) auto (* slow *) then show ?thesis .. qed lemma comp_fun_commute_filter_fold: "comp_fun_commute (\x A'. if P x then Set.insert x A' else A')" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) show ?thesis by standard (auto simp: fun_eq_iff) qed lemma Set_filter_fold: assumes "finite A" shows "Set.filter P A = fold (\x A'. if P x then Set.insert x A' else A') {} A" using assms - by induct - (auto simp add: Set.filter_def comp_fun_commute.fold_insert[OF comp_fun_commute_filter_fold]) +proof - + interpret commute_insert: comp_fun_commute "(\x A'. if P x then Set.insert x A' else A')" + by (fact comp_fun_commute_filter_fold) + from \finite A\ show ?thesis + by induct (auto simp add: Set.filter_def) +qed lemma inter_Set_filter: assumes "finite B" shows "A \ B = Set.filter (\x. x \ A) B" using assms by induct (auto simp: Set.filter_def) lemma image_fold_insert: assumes "finite A" shows "image f A = fold (\k A. Set.insert (f k) A) {} A" proof - interpret comp_fun_commute "\k A. Set.insert (f k) A" by standard auto show ?thesis using assms by (induct A) auto qed lemma Ball_fold: assumes "finite A" shows "Ball A P = fold (\k s. s \ P k) True A" proof - interpret comp_fun_commute "\k s. s \ P k" by standard auto show ?thesis using assms by (induct A) auto qed lemma Bex_fold: assumes "finite A" shows "Bex A P = fold (\k s. s \ P k) False A" proof - interpret comp_fun_commute "\k s. s \ P k" by standard auto show ?thesis using assms by (induct A) auto qed lemma comp_fun_commute_Pow_fold: "comp_fun_commute (\x A. A \ Set.insert x ` A)" - by (clarsimp simp: fun_eq_iff comp_fun_commute_def) blast (* somewhat slow *) + by (clarsimp simp: fun_eq_iff comp_fun_commute_def) blast lemma Pow_fold: assumes "finite A" shows "Pow A = fold (\x A. A \ Set.insert x ` A) {{}} A" proof - interpret comp_fun_commute "\x A. A \ Set.insert x ` A" by (rule comp_fun_commute_Pow_fold) show ?thesis using assms by (induct A) (auto simp: Pow_insert) qed lemma fold_union_pair: assumes "finite B" shows "(\y\B. {(x, y)}) \ A = fold (\y. Set.insert (x, y)) A B" proof - interpret comp_fun_commute "\y. Set.insert (x, y)" by standard auto show ?thesis using assms by (induct arbitrary: A) simp_all qed lemma comp_fun_commute_product_fold: "finite B \ comp_fun_commute (\x z. fold (\y. Set.insert (x, y)) z B)" by standard (auto simp: fold_union_pair [symmetric]) lemma product_fold: assumes "finite A" "finite B" shows "A \ B = fold (\x z. fold (\y. Set.insert (x, y)) z B) {} A" - using assms unfolding Sigma_def - by (induct A) - (simp_all add: comp_fun_commute.fold_insert[OF comp_fun_commute_product_fold] fold_union_pair) +proof - + interpret commute_product: comp_fun_commute "(\x z. fold (\y. Set.insert (x, y)) z B)" + by (fact comp_fun_commute_product_fold[OF \finite B\]) + from assms show ?thesis unfolding Sigma_def + by (induct A) (simp_all add: fold_union_pair) +qed context complete_lattice begin lemma inf_Inf_fold_inf: assumes "finite A" shows "inf (Inf A) B = fold inf B A" proof - interpret comp_fun_idem inf by (fact comp_fun_idem_inf) from \finite A\ fold_fun_left_comm show ?thesis by (induct A arbitrary: B) (simp_all add: inf_commute fun_eq_iff) qed lemma sup_Sup_fold_sup: assumes "finite A" shows "sup (Sup A) B = fold sup B A" proof - interpret comp_fun_idem sup by (fact comp_fun_idem_sup) from \finite A\ fold_fun_left_comm show ?thesis by (induct A arbitrary: B) (simp_all add: sup_commute fun_eq_iff) qed lemma Inf_fold_inf: "finite A \ Inf A = fold inf top A" using inf_Inf_fold_inf [of A top] by (simp add: inf_absorb2) lemma Sup_fold_sup: "finite A \ Sup A = fold sup bot A" using sup_Sup_fold_sup [of A bot] by (simp add: sup_absorb2) lemma inf_INF_fold_inf: assumes "finite A" shows "inf B (\(f ` A)) = fold (inf \ f) B A" (is "?inf = ?fold") proof - interpret comp_fun_idem inf by (fact comp_fun_idem_inf) interpret comp_fun_idem "inf \ f" by (fact comp_comp_fun_idem) from \finite A\ have "?fold = ?inf" by (induct A arbitrary: B) (simp_all add: inf_left_commute) then show ?thesis .. qed lemma sup_SUP_fold_sup: assumes "finite A" shows "sup B (\(f ` A)) = fold (sup \ f) B A" (is "?sup = ?fold") proof - interpret comp_fun_idem sup by (fact comp_fun_idem_sup) interpret comp_fun_idem "sup \ f" by (fact comp_comp_fun_idem) from \finite A\ have "?fold = ?sup" by (induct A arbitrary: B) (simp_all add: sup_left_commute) then show ?thesis .. qed lemma INF_fold_inf: "finite A \ \(f ` A) = fold (inf \ f) top A" using inf_INF_fold_inf [of A top] by simp lemma SUP_fold_sup: "finite A \ \(f ` A) = fold (sup \ f) bot A" using sup_SUP_fold_sup [of A bot] by simp lemma finite_Inf_in: assumes "finite A" "A\{}" and inf: "\x y. \x \ A; y \ A\ \ inf x y \ A" shows "Inf A \ A" proof - have "Inf B \ A" if "B \ A" "B\{}" for B using finite_subset [OF \B \ A\ \finite A\] that by (induction B) (use inf in \force+\) then show ?thesis by (simp add: assms) qed lemma finite_Sup_in: assumes "finite A" "A\{}" and sup: "\x y. \x \ A; y \ A\ \ sup x y \ A" shows "Sup A \ A" proof - have "Sup B \ A" if "B \ A" "B\{}" for B using finite_subset [OF \B \ A\ \finite A\] that by (induction B) (use sup in \force+\) then show ?thesis by (simp add: assms) qed end subsection \Locales as mini-packages for fold operations\ subsubsection \The natural case\ -locale folding = +locale folding_on = + fixes S :: "'a set" fixes f :: "'a \ 'b \ 'b" and z :: "'b" - assumes comp_fun_commute: "f y \ f x = f x \ f y" + assumes comp_fun_commute_on: "x \ S \ y \ S \ f y o f x = f x o f y" begin -interpretation fold?: comp_fun_commute f - by standard (use comp_fun_commute in \simp add: fun_eq_iff\) +interpretation fold?: comp_fun_commute_on S f + by standard (simp add: comp_fun_commute_on) definition F :: "'a set \ 'b" - where eq_fold: "F A = fold f z A" + where eq_fold: "F A = Finite_Set.fold f z A" -lemma empty [simp]:"F {} = z" +lemma empty [simp]: "F {} = z" by (simp add: eq_fold) lemma infinite [simp]: "\ finite A \ F A = z" by (simp add: eq_fold) lemma insert [simp]: - assumes "finite A" and "x \ A" + assumes "insert x A \ S" and "finite A" and "x \ A" shows "F (insert x A) = f x (F A)" proof - from fold_insert assms - have "fold f z (insert x A) = f x (fold f z A)" by simp + have "Finite_Set.fold f z (insert x A) + = f x (Finite_Set.fold f z A)" + by simp with \finite A\ show ?thesis by (simp add: eq_fold fun_eq_iff) qed lemma remove: - assumes "finite A" and "x \ A" + assumes "A \ S" and "finite A" and "x \ A" shows "F A = f x (F (A - {x}))" proof - from \x \ A\ obtain B where A: "A = insert x B" and "x \ B" by (auto dest: mk_disjoint_insert) moreover from \finite A\ A have "finite B" by simp - ultimately show ?thesis by simp + ultimately show ?thesis + using \A \ S\ by auto qed -lemma insert_remove: "finite A \ F (insert x A) = f x (F (A - {x}))" - by (cases "x \ A") (simp_all add: remove insert_absorb) +lemma insert_remove: + assumes "insert x A \ S" and "finite A" + shows "F (insert x A) = f x (F (A - {x}))" + using assms by (cases "x \ A") (simp_all add: remove insert_absorb) end subsubsection \With idempotency\ -locale folding_idem = folding + - assumes comp_fun_idem: "f x \ f x = f x" +locale folding_idem_on = folding_on + + assumes comp_fun_idem_on: "x \ S \ y \ S \ f x \ f x = f x" begin declare insert [simp del] -interpretation fold?: comp_fun_idem f - by standard (insert comp_fun_commute comp_fun_idem, simp add: fun_eq_iff) +interpretation fold?: comp_fun_idem_on S f + by standard (simp_all add: comp_fun_commute_on comp_fun_idem_on) lemma insert_idem [simp]: - assumes "finite A" + assumes "insert x A \ S" and "finite A" shows "F (insert x A) = f x (F A)" proof - from fold_insert_idem assms have "fold f z (insert x A) = f x (fold f z A)" by simp with \finite A\ show ?thesis by (simp add: eq_fold fun_eq_iff) qed end +subsubsection \\<^term>\UNIV\ as the carrier set\ + +locale folding = + fixes f :: "'a \ 'b \ 'b" and z :: "'b" + assumes comp_fun_commute: "f y \ f x = f x \ f y" +begin + +lemma (in -) folding_def': "folding f = folding_on UNIV f" + unfolding folding_def folding_on_def by blast + +text \ + Again, we abuse the \rewrites\ functionality of locales to remove trivial assumptions that + result from instantiating the carrier set to \<^term>\UNIV\. +\ +sublocale folding_on UNIV f + rewrites "\X. (X \ UNIV) \ True" + and "\x. x \ UNIV \ True" + and "\P. (True \ P) \ Trueprop P" + and "\P Q. (True \ PROP P \ PROP Q) \ (PROP P \ True \ PROP Q)" +proof - + show "folding_on UNIV f" + by standard (simp add: comp_fun_commute) +qed simp_all + +end + +locale folding_idem = folding + + assumes comp_fun_idem: "f x \ f x = f x" +begin + +lemma (in -) folding_idem_def': "folding_idem f = folding_idem_on UNIV f" + unfolding folding_idem_def folding_def' folding_idem_on_def + unfolding folding_idem_axioms_def folding_idem_on_axioms_def + by blast + +text \ + Again, we abuse the \rewrites\ functionality of locales to remove trivial assumptions that + result from instantiating the carrier set to \<^term>\UNIV\. +\ +sublocale folding_idem_on UNIV f + rewrites "\X. (X \ UNIV) \ True" + and "\x. x \ UNIV \ True" + and "\P. (True \ P) \ Trueprop P" + and "\P Q. (True \ PROP P \ PROP Q) \ (PROP P \ True \ PROP Q)" +proof - + show "folding_idem_on UNIV f" + by standard (simp add: comp_fun_idem) +qed simp_all + +end + subsection \Finite cardinality\ text \ The traditional definition \<^prop>\card A \ LEAST n. \f. A = {f i |i. i < n}\ is ugly to work with. But now that we have \<^const>\fold\ things are easy: \ global_interpretation card: folding "\_. Suc" 0 - defines card = "folding.F (\_. Suc) 0" + defines card = "folding_on.F (\_. Suc) 0" by standard rule lemma card_insert_disjoint: "finite A \ x \ A \ card (insert x A) = Suc (card A)" by (fact card.insert) lemma card_insert_if: "finite A \ card (insert x A) = (if x \ A then card A else Suc (card A))" by auto (simp add: card.insert_remove card.remove) lemma card_ge_0_finite: "card A > 0 \ finite A" by (rule ccontr) simp lemma card_0_eq [simp]: "finite A \ card A = 0 \ A = {}" by (auto dest: mk_disjoint_insert) lemma finite_UNIV_card_ge_0: "finite (UNIV :: 'a set) \ card (UNIV :: 'a set) > 0" by (rule ccontr) simp lemma card_eq_0_iff: "card A = 0 \ A = {} \ \ finite A" by auto lemma card_range_greater_zero: "finite (range f) \ card (range f) > 0" by (rule ccontr) (simp add: card_eq_0_iff) lemma card_gt_0_iff: "0 < card A \ A \ {} \ finite A" by (simp add: neq0_conv [symmetric] card_eq_0_iff) lemma card_Suc_Diff1: assumes "finite A" "x \ A" shows "Suc (card (A - {x})) = card A" proof - have "Suc (card (A - {x})) = card (insert x (A - {x}))" using assms by (simp add: card.insert_remove) also have "... = card A" using assms by (simp add: card_insert_if) finally show ?thesis . qed lemma card_insert_le_m1: assumes "n > 0" "card y \ n - 1" shows "card (insert x y) \ n" using assms by (cases "finite y") (auto simp: card_insert_if) lemma card_Diff_singleton: "finite A \ x \ A \ card (A - {x}) = card A - 1" by (simp add: card_Suc_Diff1 [symmetric]) lemma card_Diff_singleton_if: "finite A \ card (A - {x}) = (if x \ A then card A - 1 else card A)" by (simp add: card_Diff_singleton) lemma card_Diff_insert[simp]: assumes "finite A" and "a \ A" and "a \ B" shows "card (A - insert a B) = card (A - B) - 1" proof - have "A - insert a B = (A - B) - {a}" using assms by blast then show ?thesis using assms by (simp add: card_Diff_singleton) qed lemma card_insert_le: "finite A \ card A \ card (insert x A)" by (simp add: card_insert_if) lemma card_Collect_less_nat[simp]: "card {i::nat. i < n} = n" by (induct n) (simp_all add:less_Suc_eq Collect_disj_eq) lemma card_Collect_le_nat[simp]: "card {i::nat. i \ n} = Suc n" using card_Collect_less_nat[of "Suc n"] by (simp add: less_Suc_eq_le) lemma card_mono: assumes "finite B" and "A \ B" shows "card A \ card B" proof - from assms have "finite A" by (auto intro: finite_subset) then show ?thesis using assms proof (induct A arbitrary: B) case empty then show ?case by simp next case (insert x A) then have "x \ B" by simp from insert have "A \ B - {x}" and "finite (B - {x})" by auto with insert.hyps have "card A \ card (B - {x})" by auto with \finite A\ \x \ A\ \finite B\ \x \ B\ show ?case by simp (simp only: card.remove) qed qed lemma card_seteq: assumes "finite B" and A: "A \ B" "card B \ card A" shows "A = B" using assms proof (induction arbitrary: A rule: finite_induct) case (insert b B) then have A: "finite A" "A - {b} \ B" by force+ then have "card B \ card (A - {b})" using insert by (auto simp add: card_Diff_singleton_if) then have "A - {b} = B" using A insert.IH by auto then show ?case using insert.hyps insert.prems by auto qed auto lemma psubset_card_mono: "finite B \ A < B \ card A < card B" using card_seteq [of B A] by (auto simp add: psubset_eq) lemma card_Un_Int: assumes "finite A" "finite B" shows "card A + card B = card (A \ B) + card (A \ B)" using assms proof (induct A) case empty then show ?case by simp next case insert then show ?case by (auto simp add: insert_absorb Int_insert_left) qed lemma card_Un_disjoint: "finite A \ finite B \ A \ B = {} \ card (A \ B) = card A + card B" using card_Un_Int [of A B] by simp lemma card_Un_disjnt: "\finite A; finite B; disjnt A B\ \ card (A \ B) = card A + card B" by (simp add: card_Un_disjoint disjnt_def) lemma card_Un_le: "card (A \ B) \ card A + card B" proof (cases "finite A \ finite B") case True then show ?thesis using le_iff_add card_Un_Int [of A B] by auto qed auto lemma card_Diff_subset: assumes "finite B" and "B \ A" shows "card (A - B) = card A - card B" using assms proof (cases "finite A") case False with assms show ?thesis by simp next case True with assms show ?thesis by (induct B arbitrary: A) simp_all qed lemma card_Diff_subset_Int: assumes "finite (A \ B)" shows "card (A - B) = card A - card (A \ B)" proof - have "A - B = A - A \ B" by auto with assms show ?thesis by (simp add: card_Diff_subset) qed lemma diff_card_le_card_Diff: assumes "finite B" shows "card A - card B \ card (A - B)" proof - have "card A - card B \ card A - card (A \ B)" using card_mono[OF assms Int_lower2, of A] by arith also have "\ = card (A - B)" using assms by (simp add: card_Diff_subset_Int) finally show ?thesis . qed lemma card_le_sym_Diff: assumes "finite A" "finite B" "card A \ card B" shows "card(A - B) \ card(B - A)" proof - have "card(A - B) = card A - card (A \ B)" using assms(1,2) by(simp add: card_Diff_subset_Int) also have "\ \ card B - card (A \ B)" using assms(3) by linarith also have "\ = card(B - A)" using assms(1,2) by(simp add: card_Diff_subset_Int Int_commute) finally show ?thesis . qed lemma card_less_sym_Diff: assumes "finite A" "finite B" "card A < card B" shows "card(A - B) < card(B - A)" proof - have "card(A - B) = card A - card (A \ B)" using assms(1,2) by(simp add: card_Diff_subset_Int) also have "\ < card B - card (A \ B)" using assms(1,3) by (simp add: card_mono diff_less_mono) also have "\ = card(B - A)" using assms(1,2) by(simp add: card_Diff_subset_Int Int_commute) finally show ?thesis . qed lemma card_Diff1_less_iff: "card (A - {x}) < card A \ finite A \ x \ A" proof (cases "finite A \ x \ A") case True then show ?thesis by (auto simp: card_gt_0_iff intro: diff_less) qed auto lemma card_Diff1_less: "finite A \ x \ A \ card (A - {x}) < card A" unfolding card_Diff1_less_iff by auto lemma card_Diff2_less: assumes "finite A" "x \ A" "y \ A" shows "card (A - {x} - {y}) < card A" proof (cases "x = y") case True with assms show ?thesis by (simp add: card_Diff1_less del: card_Diff_insert) next case False then have "card (A - {x} - {y}) < card (A - {x})" "card (A - {x}) < card A" using assms by (intro card_Diff1_less; simp)+ then show ?thesis by (blast intro: less_trans) qed lemma card_Diff1_le: "finite A \ card (A - {x}) \ card A" by (cases "x \ A") (simp_all add: card_Diff1_less less_imp_le) lemma card_psubset: "finite B \ A \ B \ card A < card B \ A < B" by (erule psubsetI) blast lemma card_le_inj: assumes fA: "finite A" and fB: "finite B" and c: "card A \ card B" shows "\f. f ` A \ B \ inj_on f A" using fA fB c proof (induct arbitrary: B rule: finite_induct) case empty then show ?case by simp next case (insert x s t) then show ?case proof (induct rule: finite_induct [OF insert.prems(1)]) case 1 then show ?case by simp next case (2 y t) from "2.prems"(1,2,5) "2.hyps"(1,2) have cst: "card s \ card t" by simp from "2.prems"(3) [OF "2.hyps"(1) cst] obtain f where "f ` s \ t" "inj_on f s" by blast with "2.prems"(2) "2.hyps"(2) show ?case unfolding inj_on_def by (rule_tac x = "\z. if z = x then y else f z" in exI) auto qed qed lemma card_subset_eq: assumes fB: "finite B" and AB: "A \ B" and c: "card A = card B" shows "A = B" proof - from fB AB have fA: "finite A" by (auto intro: finite_subset) from fA fB have fBA: "finite (B - A)" by auto have e: "A \ (B - A) = {}" by blast have eq: "A \ (B - A) = B" using AB by blast from card_Un_disjoint[OF fA fBA e, unfolded eq c] have "card (B - A) = 0" by arith then have "B - A = {}" unfolding card_eq_0_iff using fA fB by simp with AB show "A = B" by blast qed lemma insert_partition: "x \ F \ \c1 \ insert x F. \c2 \ insert x F. c1 \ c2 \ c1 \ c2 = {} \ x \ \F = {}" by auto (* somewhat slow *) lemma finite_psubset_induct [consumes 1, case_names psubset]: assumes finite: "finite A" and major: "\A. finite A \ (\B. B \ A \ P B) \ P A" shows "P A" using finite proof (induct A taking: card rule: measure_induct_rule) case (less A) have fin: "finite A" by fact have ih: "card B < card A \ finite B \ P B" for B by fact have "P B" if "B \ A" for B proof - from that have "card B < card A" using psubset_card_mono fin by blast moreover from that have "B \ A" by auto then have "finite B" using fin finite_subset by blast ultimately show ?thesis using ih by simp qed with fin show "P A" using major by blast qed lemma finite_induct_select [consumes 1, case_names empty select]: assumes "finite S" and "P {}" and select: "\T. T \ S \ P T \ \s\S - T. P (insert s T)" shows "P S" proof - have "0 \ card S" by simp then have "\T \ S. card T = card S \ P T" proof (induct rule: dec_induct) case base with \P {}\ show ?case by (intro exI[of _ "{}"]) auto next case (step n) then obtain T where T: "T \ S" "card T = n" "P T" by auto with \n < card S\ have "T \ S" "P T" by auto with select[of T] obtain s where "s \ S" "s \ T" "P (insert s T)" by auto with step(2) T \finite S\ show ?case by (intro exI[of _ "insert s T"]) (auto dest: finite_subset) qed with \finite S\ show "P S" by (auto dest: card_subset_eq) qed lemma remove_induct [case_names empty infinite remove]: assumes empty: "P ({} :: 'a set)" and infinite: "\ finite B \ P B" and remove: "\A. finite A \ A \ {} \ A \ B \ (\x. x \ A \ P (A - {x})) \ P A" shows "P B" proof (cases "finite B") case False then show ?thesis by (rule infinite) next case True define A where "A = B" with True have "finite A" "A \ B" by simp_all then show "P A" proof (induct "card A" arbitrary: A) case 0 then have "A = {}" by auto with empty show ?case by simp next case (Suc n A) from \A \ B\ and \finite B\ have "finite A" by (rule finite_subset) moreover from Suc.hyps have "A \ {}" by auto moreover note \A \ B\ moreover have "P (A - {x})" if x: "x \ A" for x using x Suc.prems \Suc n = card A\ by (intro Suc) auto ultimately show ?case by (rule remove) qed qed lemma finite_remove_induct [consumes 1, case_names empty remove]: fixes P :: "'a set \ bool" assumes "finite B" and "P {}" and "\A. finite A \ A \ {} \ A \ B \ (\x. x \ A \ P (A - {x})) \ P A" defines "B' \ B" shows "P B'" by (induct B' rule: remove_induct) (simp_all add: assms) text \Main cardinality theorem.\ lemma card_partition [rule_format]: "finite C \ finite (\C) \ (\c\C. card c = k) \ (\c1 \ C. \c2 \ C. c1 \ c2 \ c1 \ c2 = {}) \ k * card C = card (\C)" proof (induct rule: finite_induct) case empty then show ?case by simp next case (insert x F) then show ?case by (simp add: card_Un_disjoint insert_partition finite_subset [of _ "\(insert _ _)"]) qed lemma card_eq_UNIV_imp_eq_UNIV: assumes fin: "finite (UNIV :: 'a set)" and card: "card A = card (UNIV :: 'a set)" shows "A = (UNIV :: 'a set)" proof show "A \ UNIV" by simp show "UNIV \ A" proof show "x \ A" for x proof (rule ccontr) assume "x \ A" then have "A \ UNIV" by auto with fin have "card A < card (UNIV :: 'a set)" by (fact psubset_card_mono) with card show False by simp qed qed qed text \The form of a finite set of given cardinality\ lemma card_eq_SucD: assumes "card A = Suc k" shows "\b B. A = insert b B \ b \ B \ card B = k \ (k = 0 \ B = {})" proof - have fin: "finite A" using assms by (auto intro: ccontr) moreover have "card A \ 0" using assms by auto ultimately obtain b where b: "b \ A" by auto show ?thesis proof (intro exI conjI) show "A = insert b (A - {b})" using b by blast show "b \ A - {b}" by blast show "card (A - {b}) = k" and "k = 0 \ A - {b} = {}" using assms b fin by (fastforce dest: mk_disjoint_insert)+ qed qed lemma card_Suc_eq: "card A = Suc k \ (\b B. A = insert b B \ b \ B \ card B = k \ (k = 0 \ B = {}))" by (auto simp: card_insert_if card_gt_0_iff elim!: card_eq_SucD) lemma card_Suc_eq_finite: "card A = Suc k \ (\b B. A = insert b B \ b \ B \ card B = k \ finite B)" unfolding card_Suc_eq using card_gt_0_iff by fastforce lemma card_1_singletonE: assumes "card A = 1" obtains x where "A = {x}" using assms by (auto simp: card_Suc_eq) lemma is_singleton_altdef: "is_singleton A \ card A = 1" unfolding is_singleton_def by (auto elim!: card_1_singletonE is_singletonE simp del: One_nat_def) lemma card_1_singleton_iff: "card A = Suc 0 \ (\x. A = {x})" by (simp add: card_Suc_eq) lemma card_le_Suc0_iff_eq: assumes "finite A" shows "card A \ Suc 0 \ (\a1 \ A. \a2 \ A. a1 = a2)" (is "?C = ?A") proof assume ?C thus ?A using assms by (auto simp: le_Suc_eq dest: card_eq_SucD) next assume ?A show ?C proof cases assume "A = {}" thus ?C using \?A\ by simp next assume "A \ {}" then obtain a where "A = {a}" using \?A\ by blast thus ?C by simp qed qed lemma card_le_Suc_iff: "Suc n \ card A = (\a B. A = insert a B \ a \ B \ n \ card B \ finite B)" proof (cases "finite A") case True then show ?thesis by (fastforce simp: card_Suc_eq less_eq_nat.simps split: nat.splits) qed auto lemma finite_fun_UNIVD2: assumes fin: "finite (UNIV :: ('a \ 'b) set)" shows "finite (UNIV :: 'b set)" proof - from fin have "finite (range (\f :: 'a \ 'b. f arbitrary))" for arbitrary by (rule finite_imageI) moreover have "UNIV = range (\f :: 'a \ 'b. f arbitrary)" for arbitrary by (rule UNIV_eq_I) auto ultimately show "finite (UNIV :: 'b set)" by simp qed lemma card_UNIV_unit [simp]: "card (UNIV :: unit set) = 1" unfolding UNIV_unit by simp lemma infinite_arbitrarily_large: assumes "\ finite A" shows "\B. finite B \ card B = n \ B \ A" proof (induction n) case 0 show ?case by (intro exI[of _ "{}"]) auto next case (Suc n) then obtain B where B: "finite B \ card B = n \ B \ A" .. with \\ finite A\ have "A \ B" by auto with B have "B \ A" by auto then have "\x. x \ A - B" by (elim psubset_imp_ex_mem) then obtain x where x: "x \ A - B" .. with B have "finite (insert x B) \ card (insert x B) = Suc n \ insert x B \ A" by auto then show "\B. finite B \ card B = Suc n \ B \ A" .. qed text \Sometimes, to prove that a set is finite, it is convenient to work with finite subsets and to show that their cardinalities are uniformly bounded. This possibility is formalized in the next criterion.\ lemma finite_if_finite_subsets_card_bdd: assumes "\G. G \ F \ finite G \ card G \ C" shows "finite F \ card F \ C" proof (cases "finite F") case False obtain n::nat where n: "n > max C 0" by auto obtain G where G: "G \ F" "card G = n" using infinite_arbitrarily_large[OF False] by auto hence "finite G" using \n > max C 0\ using card.infinite gr_implies_not0 by blast hence False using assms G n not_less by auto thus ?thesis .. next case True thus ?thesis using assms[of F] by auto qed subsubsection \Cardinality of image\ lemma card_image_le: "finite A \ card (f ` A) \ card A" by (induct rule: finite_induct) (simp_all add: le_SucI card_insert_if) lemma card_image: "inj_on f A \ card (f ` A) = card A" proof (induct A rule: infinite_finite_induct) case (infinite A) then have "\ finite (f ` A)" by (auto dest: finite_imageD) with infinite show ?case by simp qed simp_all lemma bij_betw_same_card: "bij_betw f A B \ card A = card B" by (auto simp: card_image bij_betw_def) lemma endo_inj_surj: "finite A \ f ` A \ A \ inj_on f A \ f ` A = A" by (simp add: card_seteq card_image) lemma eq_card_imp_inj_on: assumes "finite A" "card(f ` A) = card A" shows "inj_on f A" using assms proof (induct rule:finite_induct) case empty show ?case by simp next case (insert x A) then show ?case using card_image_le [of A f] by (simp add: card_insert_if split: if_splits) qed lemma inj_on_iff_eq_card: "finite A \ inj_on f A \ card (f ` A) = card A" by (blast intro: card_image eq_card_imp_inj_on) lemma card_inj_on_le: assumes "inj_on f A" "f ` A \ B" "finite B" shows "card A \ card B" proof - have "finite A" using assms by (blast intro: finite_imageD dest: finite_subset) then show ?thesis using assms by (force intro: card_mono simp: card_image [symmetric]) qed lemma inj_on_iff_card_le: "\ finite A; finite B \ \ (\f. inj_on f A \ f ` A \ B) = (card A \ card B)" using card_inj_on_le[of _ A B] card_le_inj[of A B] by blast lemma surj_card_le: "finite A \ B \ f ` A \ card B \ card A" by (blast intro: card_image_le card_mono le_trans) lemma card_bij_eq: "inj_on f A \ f ` A \ B \ inj_on g B \ g ` B \ A \ finite A \ finite B \ card A = card B" by (auto intro: le_antisym card_inj_on_le) lemma bij_betw_finite: "bij_betw f A B \ finite A \ finite B" unfolding bij_betw_def using finite_imageD [of f A] by auto lemma inj_on_finite: "inj_on f A \ f ` A \ B \ finite B \ finite A" using finite_imageD finite_subset by blast lemma card_vimage_inj: "inj f \ A \ range f \ card (f -` A) = card A" by (auto 4 3 simp: subset_image_iff inj_vimage_image_eq intro: card_image[symmetric, OF subset_inj_on]) subsubsection \Pigeonhole Principles\ lemma pigeonhole: "card A > card (f ` A) \ \ inj_on f A " by (auto dest: card_image less_irrefl_nat) lemma pigeonhole_infinite: assumes "\ finite A" and "finite (f`A)" shows "\a0\A. \ finite {a\A. f a = f a0}" using assms(2,1) proof (induct "f`A" arbitrary: A rule: finite_induct) case empty then show ?case by simp next case (insert b F) show ?case proof (cases "finite {a\A. f a = b}") case True with \\ finite A\ have "\ finite (A - {a\A. f a = b})" by simp also have "A - {a\A. f a = b} = {a\A. f a \ b}" by blast finally have "\ finite {a\A. f a \ b}" . from insert(3)[OF _ this] insert(2,4) show ?thesis by simp (blast intro: rev_finite_subset) next case False then have "{a \ A. f a = b} \ {}" by force with False show ?thesis by blast qed qed lemma pigeonhole_infinite_rel: assumes "\ finite A" and "finite B" and "\a\A. \b\B. R a b" shows "\b\B. \ finite {a:A. R a b}" proof - let ?F = "\a. {b\B. R a b}" from finite_Pow_iff[THEN iffD2, OF \finite B\] have "finite (?F ` A)" by (blast intro: rev_finite_subset) from pigeonhole_infinite [where f = ?F, OF assms(1) this] obtain a0 where "a0 \ A" and infinite: "\ finite {a\A. ?F a = ?F a0}" .. obtain b0 where "b0 \ B" and "R a0 b0" using \a0 \ A\ assms(3) by blast have "finite {a\A. ?F a = ?F a0}" if "finite {a\A. R a b0}" using \b0 \ B\ \R a0 b0\ that by (blast intro: rev_finite_subset) with infinite \b0 \ B\ show ?thesis by blast qed subsubsection \Cardinality of sums\ lemma card_Plus: assumes "finite A" "finite B" shows "card (A <+> B) = card A + card B" proof - have "Inl`A \ Inr`B = {}" by fast with assms show ?thesis by (simp add: Plus_def card_Un_disjoint card_image) qed lemma card_Plus_conv_if: "card (A <+> B) = (if finite A \ finite B then card A + card B else 0)" by (auto simp add: card_Plus) text \Relates to equivalence classes. Based on a theorem of F. Kammüller.\ lemma dvd_partition: assumes f: "finite (\C)" and "\c\C. k dvd card c" "\c1\C. \c2\C. c1 \ c2 \ c1 \ c2 = {}" shows "k dvd card (\C)" proof - have "finite C" by (rule finite_UnionD [OF f]) then show ?thesis using assms proof (induct rule: finite_induct) case empty show ?case by simp next case (insert c C) then have "c \ \C = {}" by auto with insert show ?case by (simp add: card_Un_disjoint) qed qed subsubsection \Finite orders\ context order begin lemma finite_has_maximal: "\ finite A; A \ {} \ \ \ m \ A. \ b \ A. m \ b \ m = b" proof (induction rule: finite_psubset_induct) case (psubset A) from \A \ {}\ obtain a where "a \ A" by auto let ?B = "{b \ A. a < b}" show ?case proof cases assume "?B = {}" hence "\ b \ A. a \ b \ a = b" using le_neq_trans by blast thus ?thesis using \a \ A\ by blast next assume "?B \ {}" have "a \ ?B" by auto hence "?B \ A" using \a \ A\ by blast from psubset.IH[OF this \?B \ {}\] show ?thesis using order.strict_trans2 by blast qed qed lemma finite_has_maximal2: "\ finite A; a \ A \ \ \ m \ A. a \ m \ (\ b \ A. m \ b \ m = b)" using finite_has_maximal[of "{b \ A. a \ b}"] by fastforce lemma finite_has_minimal: "\ finite A; A \ {} \ \ \ m \ A. \ b \ A. b \ m \ m = b" proof (induction rule: finite_psubset_induct) case (psubset A) from \A \ {}\ obtain a where "a \ A" by auto let ?B = "{b \ A. b < a}" show ?case proof cases assume "?B = {}" hence "\ b \ A. b \ a \ a = b" using le_neq_trans by blast thus ?thesis using \a \ A\ by blast next assume "?B \ {}" have "a \ ?B" by auto hence "?B \ A" using \a \ A\ by blast from psubset.IH[OF this \?B \ {}\] show ?thesis using order.strict_trans1 by blast qed qed lemma finite_has_minimal2: "\ finite A; a \ A \ \ \ m \ A. m \ a \ (\ b \ A. b \ m \ m = b)" using finite_has_minimal[of "{b \ A. b \ a}"] by fastforce end subsubsection \Relating injectivity and surjectivity\ lemma finite_surj_inj: assumes "finite A" "A \ f ` A" shows "inj_on f A" proof - have "f ` A = A" by (rule card_seteq [THEN sym]) (auto simp add: assms card_image_le) then show ?thesis using assms by (simp add: eq_card_imp_inj_on) qed lemma finite_UNIV_surj_inj: "finite(UNIV:: 'a set) \ surj f \ inj f" for f :: "'a \ 'a" by (blast intro: finite_surj_inj subset_UNIV) lemma finite_UNIV_inj_surj: "finite(UNIV:: 'a set) \ inj f \ surj f" for f :: "'a \ 'a" by (fastforce simp:surj_def dest!: endo_inj_surj) lemma surjective_iff_injective_gen: assumes fS: "finite S" and fT: "finite T" and c: "card S = card T" and ST: "f ` S \ T" shows "(\y \ T. \x \ S. f x = y) \ inj_on f S" (is "?lhs \ ?rhs") proof assume h: "?lhs" { fix x y assume x: "x \ S" assume y: "y \ S" assume f: "f x = f y" from x fS have S0: "card S \ 0" by auto have "x = y" proof (rule ccontr) assume xy: "\ ?thesis" have th: "card S \ card (f ` (S - {y}))" unfolding c proof (rule card_mono) show "finite (f ` (S - {y}))" by (simp add: fS) have "\x \ y; x \ S; z \ S; f x = f y\ \ \x \ S. x \ y \ f z = f x" for z by (case_tac "z = y \ z = x") auto then show "T \ f ` (S - {y})" using h xy x y f by fastforce qed also have " \ \ card (S - {y})" by (simp add: card_image_le fS) also have "\ \ card S - 1" using y fS by simp finally show False using S0 by arith qed } then show ?rhs unfolding inj_on_def by blast next assume h: ?rhs have "f ` S = T" by (simp add: ST c card_image card_subset_eq fT h) then show ?lhs by blast qed hide_const (open) Finite_Set.fold subsection \Infinite Sets\ text \ Some elementary facts about infinite sets, mostly by Stephan Merz. Beware! Because "infinite" merely abbreviates a negation, these lemmas may not work well with \blast\. \ abbreviation infinite :: "'a set \ bool" where "infinite S \ \ finite S" text \ Infinite sets are non-empty, and if we remove some elements from an infinite set, the result is still infinite. \ lemma infinite_UNIV_nat [iff]: "infinite (UNIV :: nat set)" proof assume "finite (UNIV :: nat set)" with finite_UNIV_inj_surj [of Suc] show False by simp (blast dest: Suc_neq_Zero surjD) qed lemma infinite_UNIV_char_0: "infinite (UNIV :: 'a::semiring_char_0 set)" proof assume "finite (UNIV :: 'a set)" with subset_UNIV have "finite (range of_nat :: 'a set)" by (rule finite_subset) moreover have "inj (of_nat :: nat \ 'a)" by (simp add: inj_on_def) ultimately have "finite (UNIV :: nat set)" by (rule finite_imageD) then show False by simp qed lemma infinite_imp_nonempty: "infinite S \ S \ {}" by auto lemma infinite_remove: "infinite S \ infinite (S - {a})" by simp lemma Diff_infinite_finite: assumes "finite T" "infinite S" shows "infinite (S - T)" using \finite T\ proof induct from \infinite S\ show "infinite (S - {})" by auto next fix T x assume ih: "infinite (S - T)" have "S - (insert x T) = (S - T) - {x}" by (rule Diff_insert) with ih show "infinite (S - (insert x T))" by (simp add: infinite_remove) qed lemma Un_infinite: "infinite S \ infinite (S \ T)" by simp lemma infinite_Un: "infinite (S \ T) \ infinite S \ infinite T" by simp lemma infinite_super: assumes "S \ T" and "infinite S" shows "infinite T" proof assume "finite T" with \S \ T\ have "finite S" by (simp add: finite_subset) with \infinite S\ show False by simp qed proposition infinite_coinduct [consumes 1, case_names infinite]: assumes "X A" and step: "\A. X A \ \x\A. X (A - {x}) \ infinite (A - {x})" shows "infinite A" proof assume "finite A" then show False using \X A\ proof (induction rule: finite_psubset_induct) case (psubset A) then obtain x where "x \ A" "X (A - {x}) \ infinite (A - {x})" using local.step psubset.prems by blast then have "X (A - {x})" using psubset.hyps by blast show False proof (rule psubset.IH [where B = "A - {x}"]) show "A - {x} \ A" using \x \ A\ by blast qed fact qed qed text \ For any function with infinite domain and finite range there is some element that is the image of infinitely many domain elements. In particular, any infinite sequence of elements from a finite set contains some element that occurs infinitely often. \ lemma inf_img_fin_dom': assumes img: "finite (f ` A)" and dom: "infinite A" shows "\y \ f ` A. infinite (f -` {y} \ A)" proof (rule ccontr) have "A \ (\y\f ` A. f -` {y} \ A)" by auto moreover assume "\ ?thesis" with img have "finite (\y\f ` A. f -` {y} \ A)" by blast ultimately have "finite A" by (rule finite_subset) with dom show False by contradiction qed lemma inf_img_fin_domE': assumes "finite (f ` A)" and "infinite A" obtains y where "y \ f`A" and "infinite (f -` {y} \ A)" using assms by (blast dest: inf_img_fin_dom') lemma inf_img_fin_dom: assumes img: "finite (f`A)" and dom: "infinite A" shows "\y \ f`A. infinite (f -` {y})" using inf_img_fin_dom'[OF assms] by auto lemma inf_img_fin_domE: assumes "finite (f`A)" and "infinite A" obtains y where "y \ f`A" and "infinite (f -` {y})" using assms by (blast dest: inf_img_fin_dom) proposition finite_image_absD: "finite (abs ` S) \ finite S" for S :: "'a::linordered_ring set" by (rule ccontr) (auto simp: abs_eq_iff vimage_def dest: inf_img_fin_dom) subsection \The finite powerset operator\ definition Fpow :: "'a set \ 'a set set" where "Fpow A \ {X. X \ A \ finite X}" lemma Fpow_mono: "A \ B \ Fpow A \ Fpow B" unfolding Fpow_def by auto lemma empty_in_Fpow: "{} \ Fpow A" unfolding Fpow_def by auto lemma Fpow_not_empty: "Fpow A \ {}" using empty_in_Fpow by blast lemma Fpow_subset_Pow: "Fpow A \ Pow A" unfolding Fpow_def by auto lemma Fpow_Pow_finite: "Fpow A = Pow A Int {A. finite A}" unfolding Fpow_def Pow_def by blast lemma inj_on_image_Fpow: assumes "inj_on f A" shows "inj_on (image f) (Fpow A)" using assms Fpow_subset_Pow[of A] subset_inj_on[of "image f" "Pow A"] inj_on_image_Pow by blast lemma image_Fpow_mono: assumes "f ` A \ B" shows "(image f) ` (Fpow A) \ Fpow B" using assms by(unfold Fpow_def, auto) end diff --git a/src/HOL/Library/AList.thy b/src/HOL/Library/AList.thy --- a/src/HOL/Library/AList.thy +++ b/src/HOL/Library/AList.thy @@ -1,777 +1,780 @@ (* Title: HOL/Library/AList.thy Author: Norbert Schirmer, Tobias Nipkow, Martin Wildmoser, TU Muenchen *) section \Implementation of Association Lists\ theory AList imports Main begin context begin text \ The operations preserve distinctness of keys and function \<^term>\clearjunk\ distributes over them. Since \<^term>\clearjunk\ enforces distinctness of keys it can be used to establish the invariant, e.g. for inductive proofs. \ subsection \\update\ and \updates\\ qualified primrec update :: "'key \ 'val \ ('key \ 'val) list \ ('key \ 'val) list" where "update k v [] = [(k, v)]" | "update k v (p # ps) = (if fst p = k then (k, v) # ps else p # update k v ps)" lemma update_conv': "map_of (update k v al) = (map_of al)(k\v)" by (induct al) (auto simp add: fun_eq_iff) corollary update_conv: "map_of (update k v al) k' = ((map_of al)(k\v)) k'" by (simp add: update_conv') lemma dom_update: "fst ` set (update k v al) = {k} \ fst ` set al" by (induct al) auto lemma update_keys: "map fst (update k v al) = (if k \ set (map fst al) then map fst al else map fst al @ [k])" by (induct al) simp_all lemma distinct_update: assumes "distinct (map fst al)" shows "distinct (map fst (update k v al))" using assms by (simp add: update_keys) lemma update_filter: "a \ k \ update k v [q\ps. fst q \ a] = [q\update k v ps. fst q \ a]" by (induct ps) auto lemma update_triv: "map_of al k = Some v \ update k v al = al" by (induct al) auto lemma update_nonempty [simp]: "update k v al \ []" by (induct al) auto lemma update_eqD: "update k v al = update k v' al' \ v = v'" proof (induct al arbitrary: al') case Nil then show ?case by (cases al') (auto split: if_split_asm) next case Cons then show ?case by (cases al') (auto split: if_split_asm) qed lemma update_last [simp]: "update k v (update k v' al) = update k v al" by (induct al) auto text \Note that the lists are not necessarily the same: \<^term>\update k v (update k' v' []) = [(k', v'), (k, v)]\ and \<^term>\update k' v' (update k v []) = [(k, v), (k', v')]\.\ lemma update_swap: "k \ k' \ map_of (update k v (update k' v' al)) = map_of (update k' v' (update k v al))" by (simp add: update_conv' fun_eq_iff) lemma update_Some_unfold: "map_of (update k v al) x = Some y \ x = k \ v = y \ x \ k \ map_of al x = Some y" by (simp add: update_conv' map_upd_Some_unfold) lemma image_update [simp]: "x \ A \ map_of (update x y al) ` A = map_of al ` A" by (auto simp add: update_conv') qualified definition updates :: "'key list \ 'val list \ ('key \ 'val) list \ ('key \ 'val) list" where "updates ks vs = fold (case_prod update) (zip ks vs)" lemma updates_simps [simp]: "updates [] vs ps = ps" "updates ks [] ps = ps" "updates (k#ks) (v#vs) ps = updates ks vs (update k v ps)" by (simp_all add: updates_def) lemma updates_key_simp [simp]: "updates (k # ks) vs ps = (case vs of [] \ ps | v # vs \ updates ks vs (update k v ps))" by (cases vs) simp_all lemma updates_conv': "map_of (updates ks vs al) = (map_of al)(ks[\]vs)" proof - have "map_of \ fold (case_prod update) (zip ks vs) = fold (\(k, v) f. f(k \ v)) (zip ks vs) \ map_of" by (rule fold_commute) (auto simp add: fun_eq_iff update_conv') then show ?thesis by (auto simp add: updates_def fun_eq_iff map_upds_fold_map_upd foldl_conv_fold split_def) qed lemma updates_conv: "map_of (updates ks vs al) k = ((map_of al)(ks[\]vs)) k" by (simp add: updates_conv') lemma distinct_updates: assumes "distinct (map fst al)" shows "distinct (map fst (updates ks vs al))" proof - have "distinct (fold (\(k, v) al. if k \ set al then al else al @ [k]) (zip ks vs) (map fst al))" by (rule fold_invariant [of "zip ks vs" "\_. True"]) (auto intro: assms) moreover have "map fst \ fold (case_prod update) (zip ks vs) = fold (\(k, v) al. if k \ set al then al else al @ [k]) (zip ks vs) \ map fst" by (rule fold_commute) (simp add: update_keys split_def case_prod_beta comp_def) ultimately show ?thesis by (simp add: updates_def fun_eq_iff) qed lemma updates_append1[simp]: "size ks < size vs \ updates (ks@[k]) vs al = update k (vs!size ks) (updates ks vs al)" by (induct ks arbitrary: vs al) (auto split: list.splits) lemma updates_list_update_drop[simp]: "size ks \ i \ i < size vs \ updates ks (vs[i:=v]) al = updates ks vs al" by (induct ks arbitrary: al vs i) (auto split: list.splits nat.splits) lemma update_updates_conv_if: "map_of (updates xs ys (update x y al)) = map_of (if x \ set (take (length ys) xs) then updates xs ys al else (update x y (updates xs ys al)))" by (simp add: updates_conv' update_conv' map_upd_upds_conv_if) lemma updates_twist [simp]: "k \ set ks \ map_of (updates ks vs (update k v al)) = map_of (update k v (updates ks vs al))" by (simp add: updates_conv' update_conv') lemma updates_apply_notin [simp]: "k \ set ks \ map_of (updates ks vs al) k = map_of al k" by (simp add: updates_conv) lemma updates_append_drop [simp]: "size xs = size ys \ updates (xs @ zs) ys al = updates xs ys al" by (induct xs arbitrary: ys al) (auto split: list.splits) lemma updates_append2_drop [simp]: "size xs = size ys \ updates xs (ys @ zs) al = updates xs ys al" by (induct xs arbitrary: ys al) (auto split: list.splits) subsection \\delete\\ qualified definition delete :: "'key \ ('key \ 'val) list \ ('key \ 'val) list" where delete_eq: "delete k = filter (\(k', _). k \ k')" lemma delete_simps [simp]: "delete k [] = []" "delete k (p # ps) = (if fst p = k then delete k ps else p # delete k ps)" by (auto simp add: delete_eq) lemma delete_conv': "map_of (delete k al) = (map_of al)(k := None)" by (induct al) (auto simp add: fun_eq_iff) corollary delete_conv: "map_of (delete k al) k' = ((map_of al)(k := None)) k'" by (simp add: delete_conv') lemma delete_keys: "map fst (delete k al) = removeAll k (map fst al)" by (simp add: delete_eq removeAll_filter_not_eq filter_map split_def comp_def) lemma distinct_delete: assumes "distinct (map fst al)" shows "distinct (map fst (delete k al))" using assms by (simp add: delete_keys distinct_removeAll) lemma delete_id [simp]: "k \ fst ` set al \ delete k al = al" by (auto simp add: image_iff delete_eq filter_id_conv) lemma delete_idem: "delete k (delete k al) = delete k al" by (simp add: delete_eq) lemma map_of_delete [simp]: "k' \ k \ map_of (delete k al) k' = map_of al k'" by (simp add: delete_conv') lemma delete_notin_dom: "k \ fst ` set (delete k al)" by (auto simp add: delete_eq) lemma dom_delete_subset: "fst ` set (delete k al) \ fst ` set al" by (auto simp add: delete_eq) lemma delete_update_same: "delete k (update k v al) = delete k al" by (induct al) simp_all lemma delete_update: "k \ l \ delete l (update k v al) = update k v (delete l al)" by (induct al) simp_all lemma delete_twist: "delete x (delete y al) = delete y (delete x al)" by (simp add: delete_eq conj_commute) lemma length_delete_le: "length (delete k al) \ length al" by (simp add: delete_eq) subsection \\update_with_aux\ and \delete_aux\\ qualified primrec update_with_aux :: "'val \ 'key \ ('val \ 'val) \ ('key \ 'val) list \ ('key \ 'val) list" where "update_with_aux v k f [] = [(k, f v)]" | "update_with_aux v k f (p # ps) = (if (fst p = k) then (k, f (snd p)) # ps else p # update_with_aux v k f ps)" text \ The above \<^term>\delete\ traverses all the list even if it has found the key. This one does not have to keep going because is assumes the invariant that keys are distinct. \ qualified fun delete_aux :: "'key \ ('key \ 'val) list \ ('key \ 'val) list" where "delete_aux k [] = []" | "delete_aux k ((k', v) # xs) = (if k = k' then xs else (k', v) # delete_aux k xs)" lemma map_of_update_with_aux': "map_of (update_with_aux v k f ps) k' = ((map_of ps)(k \ (case map_of ps k of None \ f v | Some v \ f v))) k'" by (induct ps) auto lemma map_of_update_with_aux: "map_of (update_with_aux v k f ps) = (map_of ps)(k \ (case map_of ps k of None \ f v | Some v \ f v))" by (simp add: fun_eq_iff map_of_update_with_aux') lemma dom_update_with_aux: "fst ` set (update_with_aux v k f ps) = {k} \ fst ` set ps" by (induct ps) auto lemma distinct_update_with_aux [simp]: "distinct (map fst (update_with_aux v k f ps)) = distinct (map fst ps)" by (induct ps) (auto simp add: dom_update_with_aux) lemma set_update_with_aux: "distinct (map fst xs) \ set (update_with_aux v k f xs) = (set xs - {k} \ UNIV \ {(k, f (case map_of xs k of None \ v | Some v \ v))})" by (induct xs) (auto intro: rev_image_eqI) lemma set_delete_aux: "distinct (map fst xs) \ set (delete_aux k xs) = set xs - {k} \ UNIV" apply (induct xs) apply simp_all apply clarsimp apply (fastforce intro: rev_image_eqI) done lemma dom_delete_aux: "distinct (map fst ps) \ fst ` set (delete_aux k ps) = fst ` set ps - {k}" by (auto simp add: set_delete_aux) lemma distinct_delete_aux [simp]: "distinct (map fst ps) \ distinct (map fst (delete_aux k ps))" proof (induct ps) case Nil then show ?case by simp next case (Cons a ps) obtain k' v where a: "a = (k', v)" by (cases a) show ?case proof (cases "k' = k") case True with Cons a show ?thesis by simp next case False with Cons a have "k' \ fst ` set ps" "distinct (map fst ps)" by simp_all with False a have "k' \ fst ` set (delete_aux k ps)" by (auto dest!: dom_delete_aux[where k=k]) with Cons a show ?thesis by simp qed qed lemma map_of_delete_aux': "distinct (map fst xs) \ map_of (delete_aux k xs) = (map_of xs)(k := None)" apply (induct xs) apply (fastforce simp add: map_of_eq_None_iff fun_upd_twist) apply (auto intro!: ext) apply (simp add: map_of_eq_None_iff) done lemma map_of_delete_aux: "distinct (map fst xs) \ map_of (delete_aux k xs) k' = ((map_of xs)(k := None)) k'" by (simp add: map_of_delete_aux') lemma delete_aux_eq_Nil_conv: "delete_aux k ts = [] \ ts = [] \ (\v. ts = [(k, v)])" by (cases ts) (auto split: if_split_asm) subsection \\restrict\\ qualified definition restrict :: "'key set \ ('key \ 'val) list \ ('key \ 'val) list" where restrict_eq: "restrict A = filter (\(k, v). k \ A)" lemma restr_simps [simp]: "restrict A [] = []" "restrict A (p#ps) = (if fst p \ A then p # restrict A ps else restrict A ps)" by (auto simp add: restrict_eq) lemma restr_conv': "map_of (restrict A al) = ((map_of al)|` A)" proof show "map_of (restrict A al) k = ((map_of al)|` A) k" for k apply (induct al) apply simp apply (cases "k \ A") apply auto done qed corollary restr_conv: "map_of (restrict A al) k = ((map_of al)|` A) k" by (simp add: restr_conv') lemma distinct_restr: "distinct (map fst al) \ distinct (map fst (restrict A al))" by (induct al) (auto simp add: restrict_eq) lemma restr_empty [simp]: "restrict {} al = []" "restrict A [] = []" by (induct al) (auto simp add: restrict_eq) lemma restr_in [simp]: "x \ A \ map_of (restrict A al) x = map_of al x" by (simp add: restr_conv') lemma restr_out [simp]: "x \ A \ map_of (restrict A al) x = None" by (simp add: restr_conv') lemma dom_restr [simp]: "fst ` set (restrict A al) = fst ` set al \ A" by (induct al) (auto simp add: restrict_eq) lemma restr_upd_same [simp]: "restrict (-{x}) (update x y al) = restrict (-{x}) al" by (induct al) (auto simp add: restrict_eq) lemma restr_restr [simp]: "restrict A (restrict B al) = restrict (A\B) al" by (induct al) (auto simp add: restrict_eq) lemma restr_update[simp]: "map_of (restrict D (update x y al)) = map_of ((if x \ D then (update x y (restrict (D-{x}) al)) else restrict D al))" by (simp add: restr_conv' update_conv') lemma restr_delete [simp]: "delete x (restrict D al) = (if x \ D then restrict (D - {x}) al else restrict D al)" apply (simp add: delete_eq restrict_eq) apply (auto simp add: split_def) proof - have "y \ x \ x \ y" for y by auto then show "[p \ al. fst p \ D \ x \ fst p] = [p \ al. fst p \ D \ fst p \ x]" by simp assume "x \ D" then have "y \ D \ y \ D \ x \ y" for y by auto then show "[p \ al . fst p \ D \ x \ fst p] = [p \ al . fst p \ D]" by simp qed lemma update_restr: "map_of (update x y (restrict D al)) = map_of (update x y (restrict (D - {x}) al))" by (simp add: update_conv' restr_conv') (rule fun_upd_restrict) lemma update_restr_conv [simp]: "x \ D \ map_of (update x y (restrict D al)) = map_of (update x y (restrict (D - {x}) al))" by (simp add: update_conv' restr_conv') lemma restr_updates [simp]: "length xs = length ys \ set xs \ D \ map_of (restrict D (updates xs ys al)) = map_of (updates xs ys (restrict (D - set xs) al))" by (simp add: updates_conv' restr_conv') lemma restr_delete_twist: "(restrict A (delete a ps)) = delete a (restrict A ps)" by (induct ps) auto subsection \\clearjunk\\ qualified function clearjunk :: "('key \ 'val) list \ ('key \ 'val) list" where "clearjunk [] = []" | "clearjunk (p#ps) = p # clearjunk (delete (fst p) ps)" by pat_completeness auto termination by (relation "measure length") (simp_all add: less_Suc_eq_le length_delete_le) lemma map_of_clearjunk: "map_of (clearjunk al) = map_of al" by (induct al rule: clearjunk.induct) (simp_all add: fun_eq_iff) lemma clearjunk_keys_set: "set (map fst (clearjunk al)) = set (map fst al)" by (induct al rule: clearjunk.induct) (simp_all add: delete_keys) lemma dom_clearjunk: "fst ` set (clearjunk al) = fst ` set al" using clearjunk_keys_set by simp lemma distinct_clearjunk [simp]: "distinct (map fst (clearjunk al))" by (induct al rule: clearjunk.induct) (simp_all del: set_map add: clearjunk_keys_set delete_keys) lemma ran_clearjunk: "ran (map_of (clearjunk al)) = ran (map_of al)" by (simp add: map_of_clearjunk) lemma ran_map_of: "ran (map_of al) = snd ` set (clearjunk al)" proof - have "ran (map_of al) = ran (map_of (clearjunk al))" by (simp add: ran_clearjunk) also have "\ = snd ` set (clearjunk al)" by (simp add: ran_distinct) finally show ?thesis . qed +lemma graph_map_of: "Map.graph (map_of al) = set (clearjunk al)" + by (metis distinct_clearjunk graph_map_of_if_distinct_ran map_of_clearjunk) + lemma clearjunk_update: "clearjunk (update k v al) = update k v (clearjunk al)" by (induct al rule: clearjunk.induct) (simp_all add: delete_update) lemma clearjunk_updates: "clearjunk (updates ks vs al) = updates ks vs (clearjunk al)" proof - have "clearjunk \ fold (case_prod update) (zip ks vs) = fold (case_prod update) (zip ks vs) \ clearjunk" by (rule fold_commute) (simp add: clearjunk_update case_prod_beta o_def) then show ?thesis by (simp add: updates_def fun_eq_iff) qed lemma clearjunk_delete: "clearjunk (delete x al) = delete x (clearjunk al)" by (induct al rule: clearjunk.induct) (auto simp add: delete_idem delete_twist) lemma clearjunk_restrict: "clearjunk (restrict A al) = restrict A (clearjunk al)" by (induct al rule: clearjunk.induct) (auto simp add: restr_delete_twist) lemma distinct_clearjunk_id [simp]: "distinct (map fst al) \ clearjunk al = al" by (induct al rule: clearjunk.induct) auto lemma clearjunk_idem: "clearjunk (clearjunk al) = clearjunk al" by simp lemma length_clearjunk: "length (clearjunk al) \ length al" proof (induct al rule: clearjunk.induct [case_names Nil Cons]) case Nil then show ?case by simp next case (Cons kv al) moreover have "length (delete (fst kv) al) \ length al" by (fact length_delete_le) ultimately have "length (clearjunk (delete (fst kv) al)) \ length al" by (rule order_trans) then show ?case by simp qed lemma delete_map: assumes "\kv. fst (f kv) = fst kv" shows "delete k (map f ps) = map f (delete k ps)" by (simp add: delete_eq filter_map comp_def split_def assms) lemma clearjunk_map: assumes "\kv. fst (f kv) = fst kv" shows "clearjunk (map f ps) = map f (clearjunk ps)" by (induct ps rule: clearjunk.induct [case_names Nil Cons]) (simp_all add: clearjunk_delete delete_map assms) subsection \\map_ran\\ definition map_ran :: "('key \ 'val1 \ 'val2) \ ('key \ 'val1) list \ ('key \ 'val2) list" where "map_ran f = map (\(k, v). (k, f k v))" lemma map_ran_simps [simp]: "map_ran f [] = []" "map_ran f ((k, v) # ps) = (k, f k v) # map_ran f ps" by (simp_all add: map_ran_def) lemma map_ran_Cons_sel: "map_ran f (p # ps) = (fst p, f (fst p) (snd p)) # map_ran f ps" by (simp add: map_ran_def case_prod_beta) lemma length_map_ran[simp]: "length (map_ran f al) = length al" by (simp add: map_ran_def) lemma map_fst_map_ran[simp]: "map fst (map_ran f al) = map fst al" by (simp add: map_ran_def case_prod_beta) lemma dom_map_ran: "fst ` set (map_ran f al) = fst ` set al" by (simp add: map_ran_def image_image split_def) lemma map_ran_conv: "map_of (map_ran f al) k = map_option (f k) (map_of al k)" by (induct al) auto lemma distinct_map_ran: "distinct (map fst al) \ distinct (map fst (map_ran f al))" by simp lemma map_ran_filter: "map_ran f [p\ps. fst p \ a] = [p\map_ran f ps. fst p \ a]" by (simp add: map_ran_def filter_map split_def comp_def) lemma clearjunk_map_ran: "clearjunk (map_ran f al) = map_ran f (clearjunk al)" by (simp add: map_ran_def split_def clearjunk_map) subsection \\merge\\ qualified definition merge :: "('key \ 'val) list \ ('key \ 'val) list \ ('key \ 'val) list" where "merge qs ps = foldr (\(k, v). update k v) ps qs" lemma merge_simps [simp]: "merge qs [] = qs" "merge qs (p#ps) = update (fst p) (snd p) (merge qs ps)" by (simp_all add: merge_def split_def) lemma merge_updates: "merge qs ps = updates (rev (map fst ps)) (rev (map snd ps)) qs" by (simp add: merge_def updates_def foldr_conv_fold zip_rev zip_map_fst_snd) lemma dom_merge: "fst ` set (merge xs ys) = fst ` set xs \ fst ` set ys" by (induct ys arbitrary: xs) (auto simp add: dom_update) lemma distinct_merge: "distinct (map fst xs) \ distinct (map fst (merge xs ys))" by (simp add: merge_updates distinct_updates) lemma clearjunk_merge: "clearjunk (merge xs ys) = merge (clearjunk xs) ys" by (simp add: merge_updates clearjunk_updates) lemma merge_conv': "map_of (merge xs ys) = map_of xs ++ map_of ys" proof - have "map_of \ fold (case_prod update) (rev ys) = fold (\(k, v) m. m(k \ v)) (rev ys) \ map_of" by (rule fold_commute) (simp add: update_conv' case_prod_beta split_def fun_eq_iff) then show ?thesis by (simp add: merge_def map_add_map_of_foldr foldr_conv_fold fun_eq_iff) qed corollary merge_conv: "map_of (merge xs ys) k = (map_of xs ++ map_of ys) k" by (simp add: merge_conv') lemma merge_empty: "map_of (merge [] ys) = map_of ys" by (simp add: merge_conv') lemma merge_assoc [simp]: "map_of (merge m1 (merge m2 m3)) = map_of (merge (merge m1 m2) m3)" by (simp add: merge_conv') lemma merge_Some_iff: "map_of (merge m n) k = Some x \ map_of n k = Some x \ map_of n k = None \ map_of m k = Some x" by (simp add: merge_conv' map_add_Some_iff) lemmas merge_SomeD [dest!] = merge_Some_iff [THEN iffD1] lemma merge_find_right [simp]: "map_of n k = Some v \ map_of (merge m n) k = Some v" by (simp add: merge_conv') lemma merge_None [iff]: "(map_of (merge m n) k = None) = (map_of n k = None \ map_of m k = None)" by (simp add: merge_conv') lemma merge_upd [simp]: "map_of (merge m (update k v n)) = map_of (update k v (merge m n))" by (simp add: update_conv' merge_conv') lemma merge_updatess [simp]: "map_of (merge m (updates xs ys n)) = map_of (updates xs ys (merge m n))" by (simp add: updates_conv' merge_conv') lemma merge_append: "map_of (xs @ ys) = map_of (merge ys xs)" by (simp add: merge_conv') subsection \\compose\\ qualified function compose :: "('key \ 'a) list \ ('a \ 'b) list \ ('key \ 'b) list" where "compose [] ys = []" | "compose (x # xs) ys = (case map_of ys (snd x) of None \ compose (delete (fst x) xs) ys | Some v \ (fst x, v) # compose xs ys)" by pat_completeness auto termination by (relation "measure (length \ fst)") (simp_all add: less_Suc_eq_le length_delete_le) lemma compose_first_None [simp]: "map_of xs k = None \ map_of (compose xs ys) k = None" by (induct xs ys rule: compose.induct) (auto split: option.splits if_split_asm) lemma compose_conv: "map_of (compose xs ys) k = (map_of ys \\<^sub>m map_of xs) k" proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases "map_of ys (snd x)") case None with 2 have hyp: "map_of (compose (delete (fst x) xs) ys) k = (map_of ys \\<^sub>m map_of (delete (fst x) xs)) k" by simp show ?thesis proof (cases "fst x = k") case True from True delete_notin_dom [of k xs] have "map_of (delete (fst x) xs) k = None" by (simp add: map_of_eq_None_iff) with hyp show ?thesis using True None by simp next case False from False have "map_of (delete (fst x) xs) k = map_of xs k" by simp with hyp show ?thesis using False None by (simp add: map_comp_def) qed next case (Some v) with 2 have "map_of (compose xs ys) k = (map_of ys \\<^sub>m map_of xs) k" by simp with Some show ?thesis by (auto simp add: map_comp_def) qed qed lemma compose_conv': "map_of (compose xs ys) = (map_of ys \\<^sub>m map_of xs)" by (rule ext) (rule compose_conv) lemma compose_first_Some [simp]: "map_of xs k = Some v \ map_of (compose xs ys) k = map_of ys v" by (simp add: compose_conv) lemma dom_compose: "fst ` set (compose xs ys) \ fst ` set xs" proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases "map_of ys (snd x)") case None with "2.hyps" have "fst ` set (compose (delete (fst x) xs) ys) \ fst ` set (delete (fst x) xs)" by simp also have "\ \ fst ` set xs" by (rule dom_delete_subset) finally show ?thesis using None by auto next case (Some v) with "2.hyps" have "fst ` set (compose xs ys) \ fst ` set xs" by simp with Some show ?thesis by auto qed qed lemma distinct_compose: assumes "distinct (map fst xs)" shows "distinct (map fst (compose xs ys))" using assms proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases "map_of ys (snd x)") case None with 2 show ?thesis by simp next case (Some v) with 2 dom_compose [of xs ys] show ?thesis by auto qed qed lemma compose_delete_twist: "compose (delete k xs) ys = delete k (compose xs ys)" proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases "map_of ys (snd x)") case None with 2 have hyp: "compose (delete k (delete (fst x) xs)) ys = delete k (compose (delete (fst x) xs) ys)" by simp show ?thesis proof (cases "fst x = k") case True with None hyp show ?thesis by (simp add: delete_idem) next case False from None False hyp show ?thesis by (simp add: delete_twist) qed next case (Some v) with 2 have hyp: "compose (delete k xs) ys = delete k (compose xs ys)" by simp with Some show ?thesis by simp qed qed lemma compose_clearjunk: "compose xs (clearjunk ys) = compose xs ys" by (induct xs ys rule: compose.induct) (auto simp add: map_of_clearjunk split: option.splits) lemma clearjunk_compose: "clearjunk (compose xs ys) = compose (clearjunk xs) ys" by (induct xs rule: clearjunk.induct) (auto split: option.splits simp add: clearjunk_delete delete_idem compose_delete_twist) lemma compose_empty [simp]: "compose xs [] = []" by (induct xs) (auto simp add: compose_delete_twist) lemma compose_Some_iff: "(map_of (compose xs ys) k = Some v) \ (\k'. map_of xs k = Some k' \ map_of ys k' = Some v)" by (simp add: compose_conv map_comp_Some_iff) lemma map_comp_None_iff: "map_of (compose xs ys) k = None \ (map_of xs k = None \ (\k'. map_of xs k = Some k' \ map_of ys k' = None))" by (simp add: compose_conv map_comp_None_iff) subsection \\map_entry\\ qualified fun map_entry :: "'key \ ('val \ 'val) \ ('key \ 'val) list \ ('key \ 'val) list" where "map_entry k f [] = []" | "map_entry k f (p # ps) = (if fst p = k then (k, f (snd p)) # ps else p # map_entry k f ps)" lemma map_of_map_entry: "map_of (map_entry k f xs) = (map_of xs)(k := case map_of xs k of None \ None | Some v' \ Some (f v'))" by (induct xs) auto lemma dom_map_entry: "fst ` set (map_entry k f xs) = fst ` set xs" by (induct xs) auto lemma distinct_map_entry: assumes "distinct (map fst xs)" shows "distinct (map fst (map_entry k f xs))" using assms by (induct xs) (auto simp add: dom_map_entry) subsection \\map_default\\ fun map_default :: "'key \ 'val \ ('val \ 'val) \ ('key \ 'val) list \ ('key \ 'val) list" where "map_default k v f [] = [(k, v)]" | "map_default k v f (p # ps) = (if fst p = k then (k, f (snd p)) # ps else p # map_default k v f ps)" lemma map_of_map_default: "map_of (map_default k v f xs) = (map_of xs)(k := case map_of xs k of None \ Some v | Some v' \ Some (f v'))" by (induct xs) auto lemma dom_map_default: "fst ` set (map_default k v f xs) = insert k (fst ` set xs)" by (induct xs) auto lemma distinct_map_default: assumes "distinct (map fst xs)" shows "distinct (map fst (map_default k v f xs))" using assms by (induct xs) (auto simp add: dom_map_default) end end diff --git a/src/HOL/Library/AList_Mapping.thy b/src/HOL/Library/AList_Mapping.thy --- a/src/HOL/Library/AList_Mapping.thy +++ b/src/HOL/Library/AList_Mapping.thy @@ -1,118 +1,137 @@ (* Title: HOL/Library/AList_Mapping.thy Author: Florian Haftmann, TU Muenchen *) section \Implementation of mappings with Association Lists\ theory AList_Mapping imports AList Mapping begin lift_definition Mapping :: "('a \ 'b) list \ ('a, 'b) mapping" is map_of . code_datatype Mapping lemma lookup_Mapping [simp, code]: "Mapping.lookup (Mapping xs) = map_of xs" by transfer rule lemma keys_Mapping [simp, code]: "Mapping.keys (Mapping xs) = set (map fst xs)" by transfer (simp add: dom_map_of_conv_image_fst) lemma empty_Mapping [code]: "Mapping.empty = Mapping []" by transfer simp lemma is_empty_Mapping [code]: "Mapping.is_empty (Mapping xs) \ List.null xs" by (cases xs) (simp_all add: is_empty_def null_def) lemma update_Mapping [code]: "Mapping.update k v (Mapping xs) = Mapping (AList.update k v xs)" by transfer (simp add: update_conv') lemma delete_Mapping [code]: "Mapping.delete k (Mapping xs) = Mapping (AList.delete k xs)" by transfer (simp add: delete_conv') lemma ordered_keys_Mapping [code]: "Mapping.ordered_keys (Mapping xs) = sort (remdups (map fst xs))" by (simp only: ordered_keys_def keys_Mapping sorted_list_of_set_sort_remdups) simp +lemma entries_Mapping [code]: + "Mapping.entries (Mapping xs) = set (AList.clearjunk xs)" + by transfer (fact graph_map_of) + +lemma ordered_entries_Mapping [code]: + "Mapping.ordered_entries (Mapping xs) = sort_key fst (AList.clearjunk xs)" +proof - + have distinct: "distinct (sort_key fst (AList.clearjunk xs))" + using distinct_clearjunk distinct_map distinct_sort by blast + note folding_Map_graph.idem_if_sorted_distinct[where ?m="map_of xs", OF _ sorted_sort_key distinct] + then show ?thesis + unfolding ordered_entries_def + by (transfer fixing: xs) (auto simp: graph_map_of) +qed + +lemma fold_Mapping [code]: + "Mapping.fold f (Mapping xs) a = List.fold (case_prod f) (sort_key fst (AList.clearjunk xs)) a" + by (simp add: Mapping.fold_def ordered_entries_Mapping) + lemma size_Mapping [code]: "Mapping.size (Mapping xs) = length (remdups (map fst xs))" by (simp add: size_def length_remdups_card_conv dom_map_of_conv_image_fst) lemma tabulate_Mapping [code]: "Mapping.tabulate ks f = Mapping (map (\k. (k, f k)) ks)" by transfer (simp add: map_of_map_restrict) lemma bulkload_Mapping [code]: "Mapping.bulkload vs = Mapping (map (\n. (n, vs ! n)) [0.. (let ks = map fst xs; ls = map fst ys in (\l\set ls. l \ set ks) \ (\k\set ks. k \ set ls \ map_of xs k = map_of ys k))" proof - have *: "(a, b) \ set xs \ a \ fst ` set xs" for a b xs by (auto simp add: image_def intro!: bexI) show ?thesis apply transfer apply (auto intro!: map_of_eqI) apply (auto dest!: map_of_eq_dom intro: *) done qed lemma map_values_Mapping [code]: "Mapping.map_values f (Mapping xs) = Mapping (map (\(x,y). (x, f x y)) xs)" for f :: "'c \ 'a \ 'b" and xs :: "('c \ 'a) list" apply transfer apply (rule ext) subgoal for f xs x by (induct xs) auto done lemma combine_with_key_code [code]: "Mapping.combine_with_key f (Mapping xs) (Mapping ys) = Mapping.tabulate (remdups (map fst xs @ map fst ys)) (\x. the (combine_options (f x) (map_of xs x) (map_of ys x)))" apply transfer apply (rule ext) apply (rule sym) subgoal for f xs ys x apply (cases "map_of xs x"; cases "map_of ys x"; simp) apply (force simp: map_of_eq_None_iff combine_options_def option.the_def o_def image_iff dest: map_of_SomeD split: option.splits)+ done done lemma combine_code [code]: "Mapping.combine f (Mapping xs) (Mapping ys) = Mapping.tabulate (remdups (map fst xs @ map fst ys)) (\x. the (combine_options f (map_of xs x) (map_of ys x)))" apply transfer apply (rule ext) apply (rule sym) subgoal for f xs ys x apply (cases "map_of xs x"; cases "map_of ys x"; simp) apply (force simp: map_of_eq_None_iff combine_options_def option.the_def o_def image_iff dest: map_of_SomeD split: option.splits)+ done done lemma map_of_filter_distinct: (* TODO: move? *) assumes "distinct (map fst xs)" shows "map_of (filter P xs) x = (case map_of xs x of None \ None | Some y \ if P (x,y) then Some y else None)" using assms by (auto simp: map_of_eq_None_iff filter_map distinct_map_filter dest: map_of_SomeD simp del: map_of_eq_Some_iff intro!: map_of_is_SomeI split: option.splits) lemma filter_Mapping [code]: "Mapping.filter P (Mapping xs) = Mapping (filter (\(k,v). P k v) (AList.clearjunk xs))" apply transfer apply (rule ext) apply (subst map_of_filter_distinct) apply (simp_all add: map_of_clearjunk split: option.split) done lemma [code nbe]: "HOL.equal (x :: ('a, 'b) mapping) x \ True" by (fact equal_refl) end diff --git a/src/HOL/Library/FSet.thy b/src/HOL/Library/FSet.thy --- a/src/HOL/Library/FSet.thy +++ b/src/HOL/Library/FSet.thy @@ -1,1386 +1,1387 @@ (* Title: HOL/Library/FSet.thy Author: Ondrej Kuncar, TU Muenchen Author: Cezary Kaliszyk and Christian Urban Author: Andrei Popescu, TU Muenchen *) section \Type of finite sets defined as a subtype of sets\ theory FSet imports Main Countable begin subsection \Definition of the type\ typedef 'a fset = "{A :: 'a set. finite A}" morphisms fset Abs_fset by auto setup_lifting type_definition_fset subsection \Basic operations and type class instantiations\ (* FIXME transfer and right_total vs. bi_total *) instantiation fset :: (finite) finite begin instance by (standard; transfer; simp) end instantiation fset :: (type) "{bounded_lattice_bot, distrib_lattice, minus}" begin lift_definition bot_fset :: "'a fset" is "{}" parametric empty_transfer by simp lift_definition less_eq_fset :: "'a fset \ 'a fset \ bool" is subset_eq parametric subset_transfer . definition less_fset :: "'a fset \ 'a fset \ bool" where "xs < ys \ xs \ ys \ xs \ (ys::'a fset)" lemma less_fset_transfer[transfer_rule]: includes lifting_syntax assumes [transfer_rule]: "bi_unique A" shows "((pcr_fset A) ===> (pcr_fset A) ===> (=)) (\) (<)" unfolding less_fset_def[abs_def] psubset_eq[abs_def] by transfer_prover lift_definition sup_fset :: "'a fset \ 'a fset \ 'a fset" is union parametric union_transfer by simp lift_definition inf_fset :: "'a fset \ 'a fset \ 'a fset" is inter parametric inter_transfer by simp lift_definition minus_fset :: "'a fset \ 'a fset \ 'a fset" is minus parametric Diff_transfer by simp instance by (standard; transfer; auto)+ end abbreviation fempty :: "'a fset" ("{||}") where "{||} \ bot" abbreviation fsubset_eq :: "'a fset \ 'a fset \ bool" (infix "|\|" 50) where "xs |\| ys \ xs \ ys" abbreviation fsubset :: "'a fset \ 'a fset \ bool" (infix "|\|" 50) where "xs |\| ys \ xs < ys" abbreviation funion :: "'a fset \ 'a fset \ 'a fset" (infixl "|\|" 65) where "xs |\| ys \ sup xs ys" abbreviation finter :: "'a fset \ 'a fset \ 'a fset" (infixl "|\|" 65) where "xs |\| ys \ inf xs ys" abbreviation fminus :: "'a fset \ 'a fset \ 'a fset" (infixl "|-|" 65) where "xs |-| ys \ minus xs ys" instantiation fset :: (equal) equal begin definition "HOL.equal A B \ A |\| B \ B |\| A" instance by intro_classes (auto simp add: equal_fset_def) end instantiation fset :: (type) conditionally_complete_lattice begin context includes lifting_syntax begin lemma right_total_Inf_fset_transfer: assumes [transfer_rule]: "bi_unique A" and [transfer_rule]: "right_total A" shows "(rel_set (rel_set A) ===> rel_set A) (\S. if finite (\S \ Collect (Domainp A)) then \S \ Collect (Domainp A) else {}) (\S. if finite (Inf S) then Inf S else {})" by transfer_prover lemma Inf_fset_transfer: assumes [transfer_rule]: "bi_unique A" and [transfer_rule]: "bi_total A" shows "(rel_set (rel_set A) ===> rel_set A) (\A. if finite (Inf A) then Inf A else {}) (\A. if finite (Inf A) then Inf A else {})" by transfer_prover lift_definition Inf_fset :: "'a fset set \ 'a fset" is "\A. if finite (Inf A) then Inf A else {}" parametric right_total_Inf_fset_transfer Inf_fset_transfer by simp lemma Sup_fset_transfer: assumes [transfer_rule]: "bi_unique A" shows "(rel_set (rel_set A) ===> rel_set A) (\A. if finite (Sup A) then Sup A else {}) (\A. if finite (Sup A) then Sup A else {})" by transfer_prover lift_definition Sup_fset :: "'a fset set \ 'a fset" is "\A. if finite (Sup A) then Sup A else {}" parametric Sup_fset_transfer by simp lemma finite_Sup: "\z. finite z \ (\a. a \ X \ a \ z) \ finite (Sup X)" by (auto intro: finite_subset) lemma transfer_bdd_below[transfer_rule]: "(rel_set (pcr_fset (=)) ===> (=)) bdd_below bdd_below" by auto end instance proof fix x z :: "'a fset" fix X :: "'a fset set" { assume "x \ X" "bdd_below X" then show "Inf X |\| x" by transfer auto next assume "X \ {}" "(\x. x \ X \ z |\| x)" then show "z |\| Inf X" by transfer (clarsimp, blast) next assume "x \ X" "bdd_above X" then obtain z where "x \ X" "(\x. x \ X \ x |\| z)" by (auto simp: bdd_above_def) then show "x |\| Sup X" by transfer (auto intro!: finite_Sup) next assume "X \ {}" "(\x. x \ X \ x |\| z)" then show "Sup X |\| z" by transfer (clarsimp, blast) } qed end instantiation fset :: (finite) complete_lattice begin lift_definition top_fset :: "'a fset" is UNIV parametric right_total_UNIV_transfer UNIV_transfer by simp instance by (standard; transfer; auto) end instantiation fset :: (finite) complete_boolean_algebra begin lift_definition uminus_fset :: "'a fset \ 'a fset" is uminus parametric right_total_Compl_transfer Compl_transfer by simp instance by (standard; transfer) (simp_all add: Inf_Sup Diff_eq) end abbreviation fUNIV :: "'a::finite fset" where "fUNIV \ top" abbreviation fuminus :: "'a::finite fset \ 'a fset" ("|-| _" [81] 80) where "|-| x \ uminus x" declare top_fset.rep_eq[simp] subsection \Other operations\ lift_definition finsert :: "'a \ 'a fset \ 'a fset" is insert parametric Lifting_Set.insert_transfer by simp syntax "_insert_fset" :: "args => 'a fset" ("{|(_)|}") translations "{|x, xs|}" == "CONST finsert x {|xs|}" "{|x|}" == "CONST finsert x {||}" lift_definition fmember :: "'a \ 'a fset \ bool" (infix "|\|" 50) is Set.member parametric member_transfer . abbreviation notin_fset :: "'a \ 'a fset \ bool" (infix "|\|" 50) where "x |\| S \ \ (x |\| S)" context includes lifting_syntax begin lift_definition ffilter :: "('a \ bool) \ 'a fset \ 'a fset" is Set.filter parametric Lifting_Set.filter_transfer unfolding Set.filter_def by simp lift_definition fPow :: "'a fset \ 'a fset fset" is Pow parametric Pow_transfer by (simp add: finite_subset) lift_definition fcard :: "'a fset \ nat" is card parametric card_transfer . lift_definition fimage :: "('a \ 'b) \ 'a fset \ 'b fset" (infixr "|`|" 90) is image parametric image_transfer by simp lift_definition fthe_elem :: "'a fset \ 'a" is the_elem . lift_definition fbind :: "'a fset \ ('a \ 'b fset) \ 'b fset" is Set.bind parametric bind_transfer by (simp add: Set.bind_def) lift_definition ffUnion :: "'a fset fset \ 'a fset" is Union parametric Union_transfer by simp lift_definition fBall :: "'a fset \ ('a \ bool) \ bool" is Ball parametric Ball_transfer . lift_definition fBex :: "'a fset \ ('a \ bool) \ bool" is Bex parametric Bex_transfer . lift_definition ffold :: "('a \ 'b \ 'b) \ 'b \ 'a fset \ 'b" is Finite_Set.fold . lift_definition fset_of_list :: "'a list \ 'a fset" is set by (rule finite_set) lift_definition sorted_list_of_fset :: "'a::linorder fset \ 'a list" is sorted_list_of_set . subsection \Transferred lemmas from Set.thy\ lemmas fset_eqI = set_eqI[Transfer.transferred] lemmas fset_eq_iff[no_atp] = set_eq_iff[Transfer.transferred] lemmas fBallI[intro!] = ballI[Transfer.transferred] lemmas fbspec[dest?] = bspec[Transfer.transferred] lemmas fBallE[elim] = ballE[Transfer.transferred] lemmas fBexI[intro] = bexI[Transfer.transferred] lemmas rev_fBexI[intro?] = rev_bexI[Transfer.transferred] lemmas fBexCI = bexCI[Transfer.transferred] lemmas fBexE[elim!] = bexE[Transfer.transferred] lemmas fBall_triv[simp] = ball_triv[Transfer.transferred] lemmas fBex_triv[simp] = bex_triv[Transfer.transferred] lemmas fBex_triv_one_point1[simp] = bex_triv_one_point1[Transfer.transferred] lemmas fBex_triv_one_point2[simp] = bex_triv_one_point2[Transfer.transferred] lemmas fBex_one_point1[simp] = bex_one_point1[Transfer.transferred] lemmas fBex_one_point2[simp] = bex_one_point2[Transfer.transferred] lemmas fBall_one_point1[simp] = ball_one_point1[Transfer.transferred] lemmas fBall_one_point2[simp] = ball_one_point2[Transfer.transferred] lemmas fBall_conj_distrib = ball_conj_distrib[Transfer.transferred] lemmas fBex_disj_distrib = bex_disj_distrib[Transfer.transferred] lemmas fBall_cong[fundef_cong] = ball_cong[Transfer.transferred] lemmas fBex_cong[fundef_cong] = bex_cong[Transfer.transferred] lemmas fsubsetI[intro!] = subsetI[Transfer.transferred] lemmas fsubsetD[elim, intro?] = subsetD[Transfer.transferred] lemmas rev_fsubsetD[no_atp,intro?] = rev_subsetD[Transfer.transferred] lemmas fsubsetCE[no_atp,elim] = subsetCE[Transfer.transferred] lemmas fsubset_eq[no_atp] = subset_eq[Transfer.transferred] lemmas contra_fsubsetD[no_atp] = contra_subsetD[Transfer.transferred] lemmas fsubset_refl = subset_refl[Transfer.transferred] lemmas fsubset_trans = subset_trans[Transfer.transferred] lemmas fset_rev_mp = rev_subsetD[Transfer.transferred] lemmas fset_mp = subsetD[Transfer.transferred] lemmas fsubset_not_fsubset_eq[code] = subset_not_subset_eq[Transfer.transferred] lemmas eq_fmem_trans = eq_mem_trans[Transfer.transferred] lemmas fsubset_antisym[intro!] = subset_antisym[Transfer.transferred] lemmas fequalityD1 = equalityD1[Transfer.transferred] lemmas fequalityD2 = equalityD2[Transfer.transferred] lemmas fequalityE = equalityE[Transfer.transferred] lemmas fequalityCE[elim] = equalityCE[Transfer.transferred] lemmas eqfset_imp_iff = eqset_imp_iff[Transfer.transferred] lemmas eqfelem_imp_iff = eqelem_imp_iff[Transfer.transferred] lemmas fempty_iff[simp] = empty_iff[Transfer.transferred] lemmas fempty_fsubsetI[iff] = empty_subsetI[Transfer.transferred] lemmas equalsffemptyI = equals0I[Transfer.transferred] lemmas equalsffemptyD = equals0D[Transfer.transferred] lemmas fBall_fempty[simp] = ball_empty[Transfer.transferred] lemmas fBex_fempty[simp] = bex_empty[Transfer.transferred] lemmas fPow_iff[iff] = Pow_iff[Transfer.transferred] lemmas fPowI = PowI[Transfer.transferred] lemmas fPowD = PowD[Transfer.transferred] lemmas fPow_bottom = Pow_bottom[Transfer.transferred] lemmas fPow_top = Pow_top[Transfer.transferred] lemmas fPow_not_fempty = Pow_not_empty[Transfer.transferred] lemmas finter_iff[simp] = Int_iff[Transfer.transferred] lemmas finterI[intro!] = IntI[Transfer.transferred] lemmas finterD1 = IntD1[Transfer.transferred] lemmas finterD2 = IntD2[Transfer.transferred] lemmas finterE[elim!] = IntE[Transfer.transferred] lemmas funion_iff[simp] = Un_iff[Transfer.transferred] lemmas funionI1[elim?] = UnI1[Transfer.transferred] lemmas funionI2[elim?] = UnI2[Transfer.transferred] lemmas funionCI[intro!] = UnCI[Transfer.transferred] lemmas funionE[elim!] = UnE[Transfer.transferred] lemmas fminus_iff[simp] = Diff_iff[Transfer.transferred] lemmas fminusI[intro!] = DiffI[Transfer.transferred] lemmas fminusD1 = DiffD1[Transfer.transferred] lemmas fminusD2 = DiffD2[Transfer.transferred] lemmas fminusE[elim!] = DiffE[Transfer.transferred] lemmas finsert_iff[simp] = insert_iff[Transfer.transferred] lemmas finsertI1 = insertI1[Transfer.transferred] lemmas finsertI2 = insertI2[Transfer.transferred] lemmas finsertE[elim!] = insertE[Transfer.transferred] lemmas finsertCI[intro!] = insertCI[Transfer.transferred] lemmas fsubset_finsert_iff = subset_insert_iff[Transfer.transferred] lemmas finsert_ident = insert_ident[Transfer.transferred] lemmas fsingletonI[intro!,no_atp] = singletonI[Transfer.transferred] lemmas fsingletonD[dest!,no_atp] = singletonD[Transfer.transferred] lemmas fsingleton_iff = singleton_iff[Transfer.transferred] lemmas fsingleton_inject[dest!] = singleton_inject[Transfer.transferred] lemmas fsingleton_finsert_inj_eq[iff,no_atp] = singleton_insert_inj_eq[Transfer.transferred] lemmas fsingleton_finsert_inj_eq'[iff,no_atp] = singleton_insert_inj_eq'[Transfer.transferred] lemmas fsubset_fsingletonD = subset_singletonD[Transfer.transferred] lemmas fminus_single_finsert = Diff_single_insert[Transfer.transferred] lemmas fdoubleton_eq_iff = doubleton_eq_iff[Transfer.transferred] lemmas funion_fsingleton_iff = Un_singleton_iff[Transfer.transferred] lemmas fsingleton_funion_iff = singleton_Un_iff[Transfer.transferred] lemmas fimage_eqI[simp, intro] = image_eqI[Transfer.transferred] lemmas fimageI = imageI[Transfer.transferred] lemmas rev_fimage_eqI = rev_image_eqI[Transfer.transferred] lemmas fimageE[elim!] = imageE[Transfer.transferred] lemmas Compr_fimage_eq = Compr_image_eq[Transfer.transferred] lemmas fimage_funion = image_Un[Transfer.transferred] lemmas fimage_iff = image_iff[Transfer.transferred] lemmas fimage_fsubset_iff[no_atp] = image_subset_iff[Transfer.transferred] lemmas fimage_fsubsetI = image_subsetI[Transfer.transferred] lemmas fimage_ident[simp] = image_ident[Transfer.transferred] lemmas if_split_fmem1 = if_split_mem1[Transfer.transferred] lemmas if_split_fmem2 = if_split_mem2[Transfer.transferred] lemmas pfsubsetI[intro!,no_atp] = psubsetI[Transfer.transferred] lemmas pfsubsetE[elim!,no_atp] = psubsetE[Transfer.transferred] lemmas pfsubset_finsert_iff = psubset_insert_iff[Transfer.transferred] lemmas pfsubset_eq = psubset_eq[Transfer.transferred] lemmas pfsubset_imp_fsubset = psubset_imp_subset[Transfer.transferred] lemmas pfsubset_trans = psubset_trans[Transfer.transferred] lemmas pfsubsetD = psubsetD[Transfer.transferred] lemmas pfsubset_fsubset_trans = psubset_subset_trans[Transfer.transferred] lemmas fsubset_pfsubset_trans = subset_psubset_trans[Transfer.transferred] lemmas pfsubset_imp_ex_fmem = psubset_imp_ex_mem[Transfer.transferred] lemmas fimage_fPow_mono = image_Pow_mono[Transfer.transferred] lemmas fimage_fPow_surj = image_Pow_surj[Transfer.transferred] lemmas fsubset_finsertI = subset_insertI[Transfer.transferred] lemmas fsubset_finsertI2 = subset_insertI2[Transfer.transferred] lemmas fsubset_finsert = subset_insert[Transfer.transferred] lemmas funion_upper1 = Un_upper1[Transfer.transferred] lemmas funion_upper2 = Un_upper2[Transfer.transferred] lemmas funion_least = Un_least[Transfer.transferred] lemmas finter_lower1 = Int_lower1[Transfer.transferred] lemmas finter_lower2 = Int_lower2[Transfer.transferred] lemmas finter_greatest = Int_greatest[Transfer.transferred] lemmas fminus_fsubset = Diff_subset[Transfer.transferred] lemmas fminus_fsubset_conv = Diff_subset_conv[Transfer.transferred] lemmas fsubset_fempty[simp] = subset_empty[Transfer.transferred] lemmas not_pfsubset_fempty[iff] = not_psubset_empty[Transfer.transferred] lemmas finsert_is_funion = insert_is_Un[Transfer.transferred] lemmas finsert_not_fempty[simp] = insert_not_empty[Transfer.transferred] lemmas fempty_not_finsert = empty_not_insert[Transfer.transferred] lemmas finsert_absorb = insert_absorb[Transfer.transferred] lemmas finsert_absorb2[simp] = insert_absorb2[Transfer.transferred] lemmas finsert_commute = insert_commute[Transfer.transferred] lemmas finsert_fsubset[simp] = insert_subset[Transfer.transferred] lemmas finsert_inter_finsert[simp] = insert_inter_insert[Transfer.transferred] lemmas finsert_disjoint[simp,no_atp] = insert_disjoint[Transfer.transferred] lemmas disjoint_finsert[simp,no_atp] = disjoint_insert[Transfer.transferred] lemmas fimage_fempty[simp] = image_empty[Transfer.transferred] lemmas fimage_finsert[simp] = image_insert[Transfer.transferred] lemmas fimage_constant = image_constant[Transfer.transferred] lemmas fimage_constant_conv = image_constant_conv[Transfer.transferred] lemmas fimage_fimage = image_image[Transfer.transferred] lemmas finsert_fimage[simp] = insert_image[Transfer.transferred] lemmas fimage_is_fempty[iff] = image_is_empty[Transfer.transferred] lemmas fempty_is_fimage[iff] = empty_is_image[Transfer.transferred] lemmas fimage_cong = image_cong[Transfer.transferred] lemmas fimage_finter_fsubset = image_Int_subset[Transfer.transferred] lemmas fimage_fminus_fsubset = image_diff_subset[Transfer.transferred] lemmas finter_absorb = Int_absorb[Transfer.transferred] lemmas finter_left_absorb = Int_left_absorb[Transfer.transferred] lemmas finter_commute = Int_commute[Transfer.transferred] lemmas finter_left_commute = Int_left_commute[Transfer.transferred] lemmas finter_assoc = Int_assoc[Transfer.transferred] lemmas finter_ac = Int_ac[Transfer.transferred] lemmas finter_absorb1 = Int_absorb1[Transfer.transferred] lemmas finter_absorb2 = Int_absorb2[Transfer.transferred] lemmas finter_fempty_left = Int_empty_left[Transfer.transferred] lemmas finter_fempty_right = Int_empty_right[Transfer.transferred] lemmas disjoint_iff_fnot_equal = disjoint_iff_not_equal[Transfer.transferred] lemmas finter_funion_distrib = Int_Un_distrib[Transfer.transferred] lemmas finter_funion_distrib2 = Int_Un_distrib2[Transfer.transferred] lemmas finter_fsubset_iff[no_atp, simp] = Int_subset_iff[Transfer.transferred] lemmas funion_absorb = Un_absorb[Transfer.transferred] lemmas funion_left_absorb = Un_left_absorb[Transfer.transferred] lemmas funion_commute = Un_commute[Transfer.transferred] lemmas funion_left_commute = Un_left_commute[Transfer.transferred] lemmas funion_assoc = Un_assoc[Transfer.transferred] lemmas funion_ac = Un_ac[Transfer.transferred] lemmas funion_absorb1 = Un_absorb1[Transfer.transferred] lemmas funion_absorb2 = Un_absorb2[Transfer.transferred] lemmas funion_fempty_left = Un_empty_left[Transfer.transferred] lemmas funion_fempty_right = Un_empty_right[Transfer.transferred] lemmas funion_finsert_left[simp] = Un_insert_left[Transfer.transferred] lemmas funion_finsert_right[simp] = Un_insert_right[Transfer.transferred] lemmas finter_finsert_left = Int_insert_left[Transfer.transferred] lemmas finter_finsert_left_ifffempty[simp] = Int_insert_left_if0[Transfer.transferred] lemmas finter_finsert_left_if1[simp] = Int_insert_left_if1[Transfer.transferred] lemmas finter_finsert_right = Int_insert_right[Transfer.transferred] lemmas finter_finsert_right_ifffempty[simp] = Int_insert_right_if0[Transfer.transferred] lemmas finter_finsert_right_if1[simp] = Int_insert_right_if1[Transfer.transferred] lemmas funion_finter_distrib = Un_Int_distrib[Transfer.transferred] lemmas funion_finter_distrib2 = Un_Int_distrib2[Transfer.transferred] lemmas funion_finter_crazy = Un_Int_crazy[Transfer.transferred] lemmas fsubset_funion_eq = subset_Un_eq[Transfer.transferred] lemmas funion_fempty[iff] = Un_empty[Transfer.transferred] lemmas funion_fsubset_iff[no_atp, simp] = Un_subset_iff[Transfer.transferred] lemmas funion_fminus_finter = Un_Diff_Int[Transfer.transferred] lemmas ffunion_empty[simp] = Union_empty[Transfer.transferred] lemmas ffunion_mono = Union_mono[Transfer.transferred] lemmas ffunion_insert[simp] = Union_insert[Transfer.transferred] lemmas fminus_finter2 = Diff_Int2[Transfer.transferred] lemmas funion_finter_assoc_eq = Un_Int_assoc_eq[Transfer.transferred] lemmas fBall_funion = ball_Un[Transfer.transferred] lemmas fBex_funion = bex_Un[Transfer.transferred] lemmas fminus_eq_fempty_iff[simp,no_atp] = Diff_eq_empty_iff[Transfer.transferred] lemmas fminus_cancel[simp] = Diff_cancel[Transfer.transferred] lemmas fminus_idemp[simp] = Diff_idemp[Transfer.transferred] lemmas fminus_triv = Diff_triv[Transfer.transferred] lemmas fempty_fminus[simp] = empty_Diff[Transfer.transferred] lemmas fminus_fempty[simp] = Diff_empty[Transfer.transferred] lemmas fminus_finsertffempty[simp,no_atp] = Diff_insert0[Transfer.transferred] lemmas fminus_finsert = Diff_insert[Transfer.transferred] lemmas fminus_finsert2 = Diff_insert2[Transfer.transferred] lemmas finsert_fminus_if = insert_Diff_if[Transfer.transferred] lemmas finsert_fminus1[simp] = insert_Diff1[Transfer.transferred] lemmas finsert_fminus_single[simp] = insert_Diff_single[Transfer.transferred] lemmas finsert_fminus = insert_Diff[Transfer.transferred] lemmas fminus_finsert_absorb = Diff_insert_absorb[Transfer.transferred] lemmas fminus_disjoint[simp] = Diff_disjoint[Transfer.transferred] lemmas fminus_partition = Diff_partition[Transfer.transferred] lemmas double_fminus = double_diff[Transfer.transferred] lemmas funion_fminus_cancel[simp] = Un_Diff_cancel[Transfer.transferred] lemmas funion_fminus_cancel2[simp] = Un_Diff_cancel2[Transfer.transferred] lemmas fminus_funion = Diff_Un[Transfer.transferred] lemmas fminus_finter = Diff_Int[Transfer.transferred] lemmas funion_fminus = Un_Diff[Transfer.transferred] lemmas finter_fminus = Int_Diff[Transfer.transferred] lemmas fminus_finter_distrib = Diff_Int_distrib[Transfer.transferred] lemmas fminus_finter_distrib2 = Diff_Int_distrib2[Transfer.transferred] lemmas fUNIV_bool[no_atp] = UNIV_bool[Transfer.transferred] lemmas fPow_fempty[simp] = Pow_empty[Transfer.transferred] lemmas fPow_finsert = Pow_insert[Transfer.transferred] lemmas funion_fPow_fsubset = Un_Pow_subset[Transfer.transferred] lemmas fPow_finter_eq[simp] = Pow_Int_eq[Transfer.transferred] lemmas fset_eq_fsubset = set_eq_subset[Transfer.transferred] lemmas fsubset_iff[no_atp] = subset_iff[Transfer.transferred] lemmas fsubset_iff_pfsubset_eq = subset_iff_psubset_eq[Transfer.transferred] lemmas all_not_fin_conv[simp] = all_not_in_conv[Transfer.transferred] lemmas ex_fin_conv = ex_in_conv[Transfer.transferred] lemmas fimage_mono = image_mono[Transfer.transferred] lemmas fPow_mono = Pow_mono[Transfer.transferred] lemmas finsert_mono = insert_mono[Transfer.transferred] lemmas funion_mono = Un_mono[Transfer.transferred] lemmas finter_mono = Int_mono[Transfer.transferred] lemmas fminus_mono = Diff_mono[Transfer.transferred] lemmas fin_mono = in_mono[Transfer.transferred] lemmas fthe_felem_eq[simp] = the_elem_eq[Transfer.transferred] lemmas fLeast_mono = Least_mono[Transfer.transferred] lemmas fbind_fbind = bind_bind[Transfer.transferred] lemmas fempty_fbind[simp] = empty_bind[Transfer.transferred] lemmas nonfempty_fbind_const = nonempty_bind_const[Transfer.transferred] lemmas fbind_const = bind_const[Transfer.transferred] lemmas ffmember_filter[simp] = member_filter[Transfer.transferred] lemmas fequalityI = equalityI[Transfer.transferred] lemmas fset_of_list_simps[simp] = set_simps[Transfer.transferred] lemmas fset_of_list_append[simp] = set_append[Transfer.transferred] lemmas fset_of_list_rev[simp] = set_rev[Transfer.transferred] lemmas fset_of_list_map[simp] = set_map[Transfer.transferred] subsection \Additional lemmas\ subsubsection \\ffUnion\\ lemmas ffUnion_funion_distrib[simp] = Union_Un_distrib[Transfer.transferred] subsubsection \\fbind\\ lemma fbind_cong[fundef_cong]: "A = B \ (\x. x |\| B \ f x = g x) \ fbind A f = fbind B g" by transfer force subsubsection \\fsingleton\\ lemmas fsingletonE = fsingletonD [elim_format] subsubsection \\femepty\\ lemma fempty_ffilter[simp]: "ffilter (\_. False) A = {||}" by transfer auto (* FIXME, transferred doesn't work here *) lemma femptyE [elim!]: "a |\| {||} \ P" by simp subsubsection \\fset\\ lemmas fset_simps[simp] = bot_fset.rep_eq finsert.rep_eq lemma finite_fset [simp]: shows "finite (fset S)" by transfer simp lemmas fset_cong = fset_inject lemma filter_fset [simp]: shows "fset (ffilter P xs) = Collect P \ fset xs" by transfer auto lemma notin_fset: "x |\| S \ x \ fset S" by (simp add: fmember.rep_eq) lemmas inter_fset[simp] = inf_fset.rep_eq lemmas union_fset[simp] = sup_fset.rep_eq lemmas minus_fset[simp] = minus_fset.rep_eq subsubsection \\ffilter\\ lemma subset_ffilter: "ffilter P A |\| ffilter Q A = (\ x. x |\| A \ P x \ Q x)" by transfer auto lemma eq_ffilter: "(ffilter P A = ffilter Q A) = (\x. x |\| A \ P x = Q x)" by transfer auto lemma pfsubset_ffilter: "(\x. x |\| A \ P x \ Q x) \ (x |\| A \ \ P x \ Q x) \ ffilter P A |\| ffilter Q A" unfolding less_fset_def by (auto simp add: subset_ffilter eq_ffilter) subsubsection \\fset_of_list\\ lemma fset_of_list_filter[simp]: "fset_of_list (filter P xs) = ffilter P (fset_of_list xs)" by transfer (auto simp: Set.filter_def) lemma fset_of_list_subset[intro]: "set xs \ set ys \ fset_of_list xs |\| fset_of_list ys" by transfer simp lemma fset_of_list_elem: "(x |\| fset_of_list xs) \ (x \ set xs)" by transfer simp subsubsection \\finsert\\ (* FIXME, transferred doesn't work here *) lemma set_finsert: assumes "x |\| A" obtains B where "A = finsert x B" and "x |\| B" using assms by transfer (metis Set.set_insert finite_insert) lemma mk_disjoint_finsert: "a |\| A \ \B. A = finsert a B \ a |\| B" by (rule exI [where x = "A |-| {|a|}"]) blast lemma finsert_eq_iff: assumes "a |\| A" and "b |\| B" shows "(finsert a A = finsert b B) = (if a = b then A = B else \C. A = finsert b C \ b |\| C \ B = finsert a C \ a |\| C)" using assms by transfer (force simp: insert_eq_iff) subsubsection \\fimage\\ lemma subset_fimage_iff: "(B |\| f|`|A) = (\ AA. AA |\| A \ B = f|`|AA)" by transfer (metis mem_Collect_eq rev_finite_subset subset_image_iff) subsubsection \bounded quantification\ lemma bex_simps [simp, no_atp]: "\A P Q. fBex A (\x. P x \ Q) = (fBex A P \ Q)" "\A P Q. fBex A (\x. P \ Q x) = (P \ fBex A Q)" "\P. fBex {||} P = False" "\a B P. fBex (finsert a B) P = (P a \ fBex B P)" "\A P f. fBex (f |`| A) P = fBex A (\x. P (f x))" "\A P. (\ fBex A P) = fBall A (\x. \ P x)" by auto lemma ball_simps [simp, no_atp]: "\A P Q. fBall A (\x. P x \ Q) = (fBall A P \ Q)" "\A P Q. fBall A (\x. P \ Q x) = (P \ fBall A Q)" "\A P Q. fBall A (\x. P \ Q x) = (P \ fBall A Q)" "\A P Q. fBall A (\x. P x \ Q) = (fBex A P \ Q)" "\P. fBall {||} P = True" "\a B P. fBall (finsert a B) P = (P a \ fBall B P)" "\A P f. fBall (f |`| A) P = fBall A (\x. P (f x))" "\A P. (\ fBall A P) = fBex A (\x. \ P x)" by auto lemma atomize_fBall: "(\x. x |\| A ==> P x) == Trueprop (fBall A (\x. P x))" apply (simp only: atomize_all atomize_imp) apply (rule equal_intr_rule) by (transfer, simp)+ lemma fBall_mono[mono]: "P \ Q \ fBall S P \ fBall S Q" by auto lemma fBex_mono[mono]: "P \ Q \ fBex S P \ fBex S Q" by auto end subsubsection \\fcard\\ (* FIXME: improve transferred to handle bounded meta quantification *) lemma fcard_fempty: "fcard {||} = 0" by transfer (rule card.empty) lemma fcard_finsert_disjoint: "x |\| A \ fcard (finsert x A) = Suc (fcard A)" by transfer (rule card_insert_disjoint) lemma fcard_finsert_if: "fcard (finsert x A) = (if x |\| A then fcard A else Suc (fcard A))" by transfer (rule card_insert_if) lemma fcard_0_eq [simp, no_atp]: "fcard A = 0 \ A = {||}" by transfer (rule card_0_eq) lemma fcard_Suc_fminus1: "x |\| A \ Suc (fcard (A |-| {|x|})) = fcard A" by transfer (rule card_Suc_Diff1) lemma fcard_fminus_fsingleton: "x |\| A \ fcard (A |-| {|x|}) = fcard A - 1" by transfer (rule card_Diff_singleton) lemma fcard_fminus_fsingleton_if: "fcard (A |-| {|x|}) = (if x |\| A then fcard A - 1 else fcard A)" by transfer (rule card_Diff_singleton_if) lemma fcard_fminus_finsert[simp]: assumes "a |\| A" and "a |\| B" shows "fcard (A |-| finsert a B) = fcard (A |-| B) - 1" using assms by transfer (rule card_Diff_insert) lemma fcard_finsert: "fcard (finsert x A) = Suc (fcard (A |-| {|x|}))" by transfer (rule card.insert_remove) lemma fcard_finsert_le: "fcard A \ fcard (finsert x A)" by transfer (rule card_insert_le) lemma fcard_mono: "A |\| B \ fcard A \ fcard B" by transfer (rule card_mono) lemma fcard_seteq: "A |\| B \ fcard B \ fcard A \ A = B" by transfer (rule card_seteq) lemma pfsubset_fcard_mono: "A |\| B \ fcard A < fcard B" by transfer (rule psubset_card_mono) lemma fcard_funion_finter: "fcard A + fcard B = fcard (A |\| B) + fcard (A |\| B)" by transfer (rule card_Un_Int) lemma fcard_funion_disjoint: "A |\| B = {||} \ fcard (A |\| B) = fcard A + fcard B" by transfer (rule card_Un_disjoint) lemma fcard_funion_fsubset: "B |\| A \ fcard (A |-| B) = fcard A - fcard B" by transfer (rule card_Diff_subset) lemma diff_fcard_le_fcard_fminus: "fcard A - fcard B \ fcard(A |-| B)" by transfer (rule diff_card_le_card_Diff) lemma fcard_fminus1_less: "x |\| A \ fcard (A |-| {|x|}) < fcard A" by transfer (rule card_Diff1_less) lemma fcard_fminus2_less: "x |\| A \ y |\| A \ fcard (A |-| {|x|} |-| {|y|}) < fcard A" by transfer (rule card_Diff2_less) lemma fcard_fminus1_le: "fcard (A |-| {|x|}) \ fcard A" by transfer (rule card_Diff1_le) lemma fcard_pfsubset: "A |\| B \ fcard A < fcard B \ A < B" by transfer (rule card_psubset) subsubsection \\sorted_list_of_fset\\ lemma sorted_list_of_fset_simps[simp]: "set (sorted_list_of_fset S) = fset S" "fset_of_list (sorted_list_of_fset S) = S" by (transfer, simp)+ subsubsection \\ffold\\ (* FIXME: improve transferred to handle bounded meta quantification *) context comp_fun_commute begin lemmas ffold_empty[simp] = fold_empty[Transfer.transferred] lemma ffold_finsert [simp]: assumes "x |\| A" shows "ffold f z (finsert x A) = f x (ffold f z A)" using assms by (transfer fixing: f) (rule fold_insert) lemma ffold_fun_left_comm: "f x (ffold f z A) = ffold f (f x z) A" by (transfer fixing: f) (rule fold_fun_left_comm) lemma ffold_finsert2: "x |\| A \ ffold f z (finsert x A) = ffold f (f x z) A" by (transfer fixing: f) (rule fold_insert2) lemma ffold_rec: assumes "x |\| A" shows "ffold f z A = f x (ffold f z (A |-| {|x|}))" using assms by (transfer fixing: f) (rule fold_rec) lemma ffold_finsert_fremove: "ffold f z (finsert x A) = f x (ffold f z (A |-| {|x|}))" by (transfer fixing: f) (rule fold_insert_remove) end lemma ffold_fimage: assumes "inj_on g (fset A)" shows "ffold f z (g |`| A) = ffold (f \ g) z A" using assms by transfer' (rule fold_image) lemma ffold_cong: assumes "comp_fun_commute f" "comp_fun_commute g" "\x. x |\| A \ f x = g x" and "s = t" and "A = B" shows "ffold f s A = ffold g t B" -using assms by transfer (metis Finite_Set.fold_cong) + using assms[unfolded comp_fun_commute_def'] + by transfer (meson Finite_Set.fold_cong subset_UNIV) context comp_fun_idem begin lemma ffold_finsert_idem: "ffold f z (finsert x A) = f x (ffold f z A)" by (transfer fixing: f) (rule fold_insert_idem) declare ffold_finsert [simp del] ffold_finsert_idem [simp] lemma ffold_finsert_idem2: "ffold f z (finsert x A) = ffold f (f x z) A" by (transfer fixing: f) (rule fold_insert_idem2) end subsubsection \Group operations\ locale comm_monoid_fset = comm_monoid begin sublocale set: comm_monoid_set .. lift_definition F :: "('b \ 'a) \ 'b fset \ 'a" is set.F . lemmas cong[fundef_cong] = set.cong[Transfer.transferred] lemma cong_simp[cong]: "\ A = B; \x. x |\| B =simp=> g x = h x \ \ F g A = F h B" unfolding simp_implies_def by (auto cong: cong) end context comm_monoid_add begin sublocale fsum: comm_monoid_fset plus 0 rewrites "comm_monoid_set.F plus 0 = sum" defines fsum = fsum.F proof - show "comm_monoid_fset (+) 0" by standard show "comm_monoid_set.F (+) 0 = sum" unfolding sum_def .. qed end subsubsection \Semilattice operations\ locale semilattice_fset = semilattice begin sublocale set: semilattice_set .. lift_definition F :: "'a fset \ 'a" is set.F . lemma eq_fold: "F (finsert x A) = ffold f x A" by transfer (rule set.eq_fold) lemma singleton [simp]: "F {|x|} = x" by transfer (rule set.singleton) lemma insert_not_elem: "x |\| A \ A \ {||} \ F (finsert x A) = x \<^bold>* F A" by transfer (rule set.insert_not_elem) lemma in_idem: "x |\| A \ x \<^bold>* F A = F A" by transfer (rule set.in_idem) lemma insert [simp]: "A \ {||} \ F (finsert x A) = x \<^bold>* F A" by transfer (rule set.insert) end locale semilattice_order_fset = binary?: semilattice_order + semilattice_fset begin end context linorder begin sublocale fMin: semilattice_order_fset min less_eq less rewrites "semilattice_set.F min = Min" defines fMin = fMin.F proof - show "semilattice_order_fset min (\) (<)" by standard show "semilattice_set.F min = Min" unfolding Min_def .. qed sublocale fMax: semilattice_order_fset max greater_eq greater rewrites "semilattice_set.F max = Max" defines fMax = fMax.F proof - show "semilattice_order_fset max (\) (>)" by standard show "semilattice_set.F max = Max" unfolding Max_def .. qed end lemma mono_fMax_commute: "mono f \ A \ {||} \ f (fMax A) = fMax (f |`| A)" by transfer (rule mono_Max_commute) lemma mono_fMin_commute: "mono f \ A \ {||} \ f (fMin A) = fMin (f |`| A)" by transfer (rule mono_Min_commute) lemma fMax_in[simp]: "A \ {||} \ fMax A |\| A" by transfer (rule Max_in) lemma fMin_in[simp]: "A \ {||} \ fMin A |\| A" by transfer (rule Min_in) lemma fMax_ge[simp]: "x |\| A \ x \ fMax A" by transfer (rule Max_ge) lemma fMin_le[simp]: "x |\| A \ fMin A \ x" by transfer (rule Min_le) lemma fMax_eqI: "(\y. y |\| A \ y \ x) \ x |\| A \ fMax A = x" by transfer (rule Max_eqI) lemma fMin_eqI: "(\y. y |\| A \ x \ y) \ x |\| A \ fMin A = x" by transfer (rule Min_eqI) lemma fMax_finsert[simp]: "fMax (finsert x A) = (if A = {||} then x else max x (fMax A))" by transfer simp lemma fMin_finsert[simp]: "fMin (finsert x A) = (if A = {||} then x else min x (fMin A))" by transfer simp context linorder begin lemma fset_linorder_max_induct[case_names fempty finsert]: assumes "P {||}" and "\x S. \\y. y |\| S \ y < x; P S\ \ P (finsert x S)" shows "P S" proof - (* FIXME transfer and right_total vs. bi_total *) note Domainp_forall_transfer[transfer_rule] show ?thesis using assms by (transfer fixing: less) (auto intro: finite_linorder_max_induct) qed lemma fset_linorder_min_induct[case_names fempty finsert]: assumes "P {||}" and "\x S. \\y. y |\| S \ y > x; P S\ \ P (finsert x S)" shows "P S" proof - (* FIXME transfer and right_total vs. bi_total *) note Domainp_forall_transfer[transfer_rule] show ?thesis using assms by (transfer fixing: less) (auto intro: finite_linorder_min_induct) qed end subsection \Choice in fsets\ lemma fset_choice: assumes "\x. x |\| A \ (\y. P x y)" shows "\f. \x. x |\| A \ P x (f x)" using assms by transfer metis subsection \Induction and Cases rules for fsets\ lemma fset_exhaust [case_names empty insert, cases type: fset]: assumes fempty_case: "S = {||} \ P" and finsert_case: "\x S'. S = finsert x S' \ P" shows "P" using assms by transfer blast lemma fset_induct [case_names empty insert]: assumes fempty_case: "P {||}" and finsert_case: "\x S. P S \ P (finsert x S)" shows "P S" proof - (* FIXME transfer and right_total vs. bi_total *) note Domainp_forall_transfer[transfer_rule] show ?thesis using assms by transfer (auto intro: finite_induct) qed lemma fset_induct_stronger [case_names empty insert, induct type: fset]: assumes empty_fset_case: "P {||}" and insert_fset_case: "\x S. \x |\| S; P S\ \ P (finsert x S)" shows "P S" proof - (* FIXME transfer and right_total vs. bi_total *) note Domainp_forall_transfer[transfer_rule] show ?thesis using assms by transfer (auto intro: finite_induct) qed lemma fset_card_induct: assumes empty_fset_case: "P {||}" and card_fset_Suc_case: "\S T. Suc (fcard S) = (fcard T) \ P S \ P T" shows "P S" proof (induct S) case empty show "P {||}" by (rule empty_fset_case) next case (insert x S) have h: "P S" by fact have "x |\| S" by fact then have "Suc (fcard S) = fcard (finsert x S)" by transfer auto then show "P (finsert x S)" using h card_fset_Suc_case by simp qed lemma fset_strong_cases: obtains "xs = {||}" | ys x where "x |\| ys" and "xs = finsert x ys" by transfer blast lemma fset_induct2: "P {||} {||} \ (\x xs. x |\| xs \ P (finsert x xs) {||}) \ (\y ys. y |\| ys \ P {||} (finsert y ys)) \ (\x xs y ys. \P xs ys; x |\| xs; y |\| ys\ \ P (finsert x xs) (finsert y ys)) \ P xsa ysa" apply (induct xsa arbitrary: ysa) apply (induct_tac x rule: fset_induct_stronger) apply simp_all apply (induct_tac xa rule: fset_induct_stronger) apply simp_all done subsection \Setup for Lifting/Transfer\ subsubsection \Relator and predicator properties\ lift_definition rel_fset :: "('a \ 'b \ bool) \ 'a fset \ 'b fset \ bool" is rel_set parametric rel_set_transfer . lemma rel_fset_alt_def: "rel_fset R = (\A B. (\x.\y. x|\|A \ y|\|B \ R x y) \ (\y. \x. y|\|B \ x|\|A \ R x y))" apply (rule ext)+ apply transfer' apply (subst rel_set_def[unfolded fun_eq_iff]) by blast lemma finite_rel_set: assumes fin: "finite X" "finite Z" assumes R_S: "rel_set (R OO S) X Z" shows "\Y. finite Y \ rel_set R X Y \ rel_set S Y Z" proof - obtain f where f: "\x\X. R x (f x) \ (\z\Z. S (f x) z)" apply atomize_elim apply (subst bchoice_iff[symmetric]) using R_S[unfolded rel_set_def OO_def] by blast obtain g where g: "\z\Z. S (g z) z \ (\x\X. R x (g z))" apply atomize_elim apply (subst bchoice_iff[symmetric]) using R_S[unfolded rel_set_def OO_def] by blast let ?Y = "f ` X \ g ` Z" have "finite ?Y" by (simp add: fin) moreover have "rel_set R X ?Y" unfolding rel_set_def using f g by clarsimp blast moreover have "rel_set S ?Y Z" unfolding rel_set_def using f g by clarsimp blast ultimately show ?thesis by metis qed subsubsection \Transfer rules for the Transfer package\ text \Unconditional transfer rules\ context includes lifting_syntax begin lemmas fempty_transfer [transfer_rule] = empty_transfer[Transfer.transferred] lemma finsert_transfer [transfer_rule]: "(A ===> rel_fset A ===> rel_fset A) finsert finsert" unfolding rel_fun_def rel_fset_alt_def by blast lemma funion_transfer [transfer_rule]: "(rel_fset A ===> rel_fset A ===> rel_fset A) funion funion" unfolding rel_fun_def rel_fset_alt_def by blast lemma ffUnion_transfer [transfer_rule]: "(rel_fset (rel_fset A) ===> rel_fset A) ffUnion ffUnion" unfolding rel_fun_def rel_fset_alt_def by transfer (simp, fast) lemma fimage_transfer [transfer_rule]: "((A ===> B) ===> rel_fset A ===> rel_fset B) fimage fimage" unfolding rel_fun_def rel_fset_alt_def by simp blast lemma fBall_transfer [transfer_rule]: "(rel_fset A ===> (A ===> (=)) ===> (=)) fBall fBall" unfolding rel_fset_alt_def rel_fun_def by blast lemma fBex_transfer [transfer_rule]: "(rel_fset A ===> (A ===> (=)) ===> (=)) fBex fBex" unfolding rel_fset_alt_def rel_fun_def by blast (* FIXME transfer doesn't work here *) lemma fPow_transfer [transfer_rule]: "(rel_fset A ===> rel_fset (rel_fset A)) fPow fPow" unfolding rel_fun_def using Pow_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast lemma rel_fset_transfer [transfer_rule]: "((A ===> B ===> (=)) ===> rel_fset A ===> rel_fset B ===> (=)) rel_fset rel_fset" unfolding rel_fun_def using rel_set_transfer[unfolded rel_fun_def,rule_format, Transfer.transferred, where A = A and B = B] by simp lemma bind_transfer [transfer_rule]: "(rel_fset A ===> (A ===> rel_fset B) ===> rel_fset B) fbind fbind" unfolding rel_fun_def using bind_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast text \Rules requiring bi-unique, bi-total or right-total relations\ lemma fmember_transfer [transfer_rule]: assumes "bi_unique A" shows "(A ===> rel_fset A ===> (=)) (|\|) (|\|)" using assms unfolding rel_fun_def rel_fset_alt_def bi_unique_def by metis lemma finter_transfer [transfer_rule]: assumes "bi_unique A" shows "(rel_fset A ===> rel_fset A ===> rel_fset A) finter finter" using assms unfolding rel_fun_def using inter_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast lemma fminus_transfer [transfer_rule]: assumes "bi_unique A" shows "(rel_fset A ===> rel_fset A ===> rel_fset A) (|-|) (|-|)" using assms unfolding rel_fun_def using Diff_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast lemma fsubset_transfer [transfer_rule]: assumes "bi_unique A" shows "(rel_fset A ===> rel_fset A ===> (=)) (|\|) (|\|)" using assms unfolding rel_fun_def using subset_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast lemma fSup_transfer [transfer_rule]: "bi_unique A \ (rel_set (rel_fset A) ===> rel_fset A) Sup Sup" unfolding rel_fun_def apply clarify apply transfer' using Sup_fset_transfer[unfolded rel_fun_def] by blast (* FIXME: add right_total_fInf_transfer *) lemma fInf_transfer [transfer_rule]: assumes "bi_unique A" and "bi_total A" shows "(rel_set (rel_fset A) ===> rel_fset A) Inf Inf" using assms unfolding rel_fun_def apply clarify apply transfer' using Inf_fset_transfer[unfolded rel_fun_def] by blast lemma ffilter_transfer [transfer_rule]: assumes "bi_unique A" shows "((A ===> (=)) ===> rel_fset A ===> rel_fset A) ffilter ffilter" using assms unfolding rel_fun_def using Lifting_Set.filter_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast lemma card_transfer [transfer_rule]: "bi_unique A \ (rel_fset A ===> (=)) fcard fcard" unfolding rel_fun_def using card_transfer[unfolded rel_fun_def, rule_format, Transfer.transferred] by blast end lifting_update fset.lifting lifting_forget fset.lifting subsection \BNF setup\ context includes fset.lifting begin lemma rel_fset_alt: "rel_fset R a b \ (\t \ fset a. \u \ fset b. R t u) \ (\t \ fset b. \u \ fset a. R u t)" by transfer (simp add: rel_set_def) lemma fset_to_fset: "finite A \ fset (the_inv fset A) = A" apply (rule f_the_inv_into_f[unfolded inj_on_def]) apply (simp add: fset_inject) apply (rule range_eqI Abs_fset_inverse[symmetric] CollectI)+ . lemma rel_fset_aux: "(\t \ fset a. \u \ fset b. R t u) \ (\u \ fset b. \t \ fset a. R t u) \ ((BNF_Def.Grp {a. fset a \ {(a, b). R a b}} (fimage fst))\\ OO BNF_Def.Grp {a. fset a \ {(a, b). R a b}} (fimage snd)) a b" (is "?L = ?R") proof assume ?L define R' where "R' = the_inv fset (Collect (case_prod R) \ (fset a \ fset b))" (is "_ = the_inv fset ?L'") have "finite ?L'" by (intro finite_Int[OF disjI2] finite_cartesian_product) (transfer, simp)+ hence *: "fset R' = ?L'" unfolding R'_def by (intro fset_to_fset) show ?R unfolding Grp_def relcompp.simps conversep.simps proof (intro CollectI case_prodI exI[of _ a] exI[of _ b] exI[of _ R'] conjI refl) from * show "a = fimage fst R'" using conjunct1[OF \?L\] by (transfer, auto simp add: image_def Int_def split: prod.splits) from * show "b = fimage snd R'" using conjunct2[OF \?L\] by (transfer, auto simp add: image_def Int_def split: prod.splits) qed (auto simp add: *) next assume ?R thus ?L unfolding Grp_def relcompp.simps conversep.simps apply (simp add: subset_eq Ball_def) apply (rule conjI) apply (transfer, clarsimp, metis snd_conv) by (transfer, clarsimp, metis fst_conv) qed bnf "'a fset" map: fimage sets: fset bd: natLeq wits: "{||}" rel: rel_fset apply - apply transfer' apply simp apply transfer' apply force apply transfer apply force apply transfer' apply force apply (rule natLeq_card_order) apply (rule natLeq_cinfinite) apply transfer apply (metis ordLess_imp_ordLeq finite_iff_ordLess_natLeq) apply (fastforce simp: rel_fset_alt) apply (simp add: Grp_def relcompp.simps conversep.simps fun_eq_iff rel_fset_alt rel_fset_aux[unfolded OO_Grp_alt]) apply transfer apply simp done lemma rel_fset_fset: "rel_set \ (fset A1) (fset A2) = rel_fset \ A1 A2" by transfer (rule refl) end lemmas [simp] = fset.map_comp fset.map_id fset.set_map subsection \Size setup\ context includes fset.lifting begin lift_definition size_fset :: "('a \ nat) \ 'a fset \ nat" is "\f. sum (Suc \ f)" . end instantiation fset :: (type) size begin definition size_fset where size_fset_overloaded_def: "size_fset = FSet.size_fset (\_. 0)" instance .. end lemmas size_fset_simps[simp] = size_fset_def[THEN meta_eq_to_obj_eq, THEN fun_cong, THEN fun_cong, unfolded map_fun_def comp_def id_apply] lemmas size_fset_overloaded_simps[simp] = size_fset_simps[of "\_. 0", unfolded add_0_left add_0_right, folded size_fset_overloaded_def] lemma fset_size_o_map: "inj f \ size_fset g \ fimage f = size_fset (g \ f)" apply (subst fun_eq_iff) including fset.lifting by transfer (auto intro: sum.reindex_cong subset_inj_on) setup \ BNF_LFP_Size.register_size_global \<^type_name>\fset\ \<^const_name>\size_fset\ @{thm size_fset_overloaded_def} @{thms size_fset_simps size_fset_overloaded_simps} @{thms fset_size_o_map} \ lifting_update fset.lifting lifting_forget fset.lifting subsection \Advanced relator customization\ text \Set vs. sum relators:\ lemma rel_set_rel_sum[simp]: "rel_set (rel_sum \ \) A1 A2 \ rel_set \ (Inl -` A1) (Inl -` A2) \ rel_set \ (Inr -` A1) (Inr -` A2)" (is "?L \ ?Rl \ ?Rr") proof safe assume L: "?L" show ?Rl unfolding rel_set_def Bex_def vimage_eq proof safe fix l1 assume "Inl l1 \ A1" then obtain a2 where a2: "a2 \ A2" and "rel_sum \ \ (Inl l1) a2" using L unfolding rel_set_def by auto then obtain l2 where "a2 = Inl l2 \ \ l1 l2" by (cases a2, auto) thus "\ l2. Inl l2 \ A2 \ \ l1 l2" using a2 by auto next fix l2 assume "Inl l2 \ A2" then obtain a1 where a1: "a1 \ A1" and "rel_sum \ \ a1 (Inl l2)" using L unfolding rel_set_def by auto then obtain l1 where "a1 = Inl l1 \ \ l1 l2" by (cases a1, auto) thus "\ l1. Inl l1 \ A1 \ \ l1 l2" using a1 by auto qed show ?Rr unfolding rel_set_def Bex_def vimage_eq proof safe fix r1 assume "Inr r1 \ A1" then obtain a2 where a2: "a2 \ A2" and "rel_sum \ \ (Inr r1) a2" using L unfolding rel_set_def by auto then obtain r2 where "a2 = Inr r2 \ \ r1 r2" by (cases a2, auto) thus "\ r2. Inr r2 \ A2 \ \ r1 r2" using a2 by auto next fix r2 assume "Inr r2 \ A2" then obtain a1 where a1: "a1 \ A1" and "rel_sum \ \ a1 (Inr r2)" using L unfolding rel_set_def by auto then obtain r1 where "a1 = Inr r1 \ \ r1 r2" by (cases a1, auto) thus "\ r1. Inr r1 \ A1 \ \ r1 r2" using a1 by auto qed next assume Rl: "?Rl" and Rr: "?Rr" show ?L unfolding rel_set_def Bex_def vimage_eq proof safe fix a1 assume a1: "a1 \ A1" show "\ a2. a2 \ A2 \ rel_sum \ \ a1 a2" proof(cases a1) case (Inl l1) then obtain l2 where "Inl l2 \ A2 \ \ l1 l2" using Rl a1 unfolding rel_set_def by blast thus ?thesis unfolding Inl by auto next case (Inr r1) then obtain r2 where "Inr r2 \ A2 \ \ r1 r2" using Rr a1 unfolding rel_set_def by blast thus ?thesis unfolding Inr by auto qed next fix a2 assume a2: "a2 \ A2" show "\ a1. a1 \ A1 \ rel_sum \ \ a1 a2" proof(cases a2) case (Inl l2) then obtain l1 where "Inl l1 \ A1 \ \ l1 l2" using Rl a2 unfolding rel_set_def by blast thus ?thesis unfolding Inl by auto next case (Inr r2) then obtain r1 where "Inr r1 \ A1 \ \ r1 r2" using Rr a2 unfolding rel_set_def by blast thus ?thesis unfolding Inr by auto qed qed qed subsubsection \Countability\ lemma exists_fset_of_list: "\xs. fset_of_list xs = S" including fset.lifting by transfer (rule finite_list) lemma fset_of_list_surj[simp, intro]: "surj fset_of_list" proof - have "x \ range fset_of_list" for x :: "'a fset" unfolding image_iff using exists_fset_of_list by fastforce thus ?thesis by auto qed instance fset :: (countable) countable proof obtain to_nat :: "'a list \ nat" where "inj to_nat" by (metis ex_inj) moreover have "inj (inv fset_of_list)" using fset_of_list_surj by (rule surj_imp_inj_inv) ultimately have "inj (to_nat \ inv fset_of_list)" by (rule inj_compose) thus "\to_nat::'a fset \ nat. inj to_nat" by auto qed subsection \Quickcheck setup\ text \Setup adapted from sets.\ notation Quickcheck_Exhaustive.orelse (infixr "orelse" 55) context includes term_syntax begin definition [code_unfold]: "valterm_femptyset = Code_Evaluation.valtermify ({||} :: ('a :: typerep) fset)" definition [code_unfold]: "valtermify_finsert x s = Code_Evaluation.valtermify finsert {\} (x :: ('a :: typerep * _)) {\} s" end instantiation fset :: (exhaustive) exhaustive begin fun exhaustive_fset where "exhaustive_fset f i = (if i = 0 then None else (f {||} orelse exhaustive_fset (\A. f A orelse Quickcheck_Exhaustive.exhaustive (\x. if x |\| A then None else f (finsert x A)) (i - 1)) (i - 1)))" instance .. end instantiation fset :: (full_exhaustive) full_exhaustive begin fun full_exhaustive_fset where "full_exhaustive_fset f i = (if i = 0 then None else (f valterm_femptyset orelse full_exhaustive_fset (\A. f A orelse Quickcheck_Exhaustive.full_exhaustive (\x. if fst x |\| fst A then None else f (valtermify_finsert x A)) (i - 1)) (i - 1)))" instance .. end no_notation Quickcheck_Exhaustive.orelse (infixr "orelse" 55) instantiation fset :: (random) random begin context includes state_combinator_syntax begin fun random_aux_fset :: "natural \ natural \ natural \ natural \ ('a fset \ (unit \ term)) \ natural \ natural" where "random_aux_fset 0 j = Quickcheck_Random.collapse (Random.select_weight [(1, Pair valterm_femptyset)])" | "random_aux_fset (Code_Numeral.Suc i) j = Quickcheck_Random.collapse (Random.select_weight [(1, Pair valterm_femptyset), (Code_Numeral.Suc i, Quickcheck_Random.random j \\ (\x. random_aux_fset i j \\ (\s. Pair (valtermify_finsert x s))))])" lemma [code]: "random_aux_fset i j = Quickcheck_Random.collapse (Random.select_weight [(1, Pair valterm_femptyset), (i, Quickcheck_Random.random j \\ (\x. random_aux_fset (i - 1) j \\ (\s. Pair (valtermify_finsert x s))))])" proof (induct i rule: natural.induct) case zero show ?case by (subst select_weight_drop_zero[symmetric]) (simp add: less_natural_def) next case (Suc i) show ?case by (simp only: random_aux_fset.simps Suc_natural_minus_one) qed definition "random_fset i = random_aux_fset i i" instance .. end end end diff --git a/src/HOL/Library/Finite_Lattice.thy b/src/HOL/Library/Finite_Lattice.thy --- a/src/HOL/Library/Finite_Lattice.thy +++ b/src/HOL/Library/Finite_Lattice.thy @@ -1,273 +1,294 @@ (* Title: HOL/Library/Finite_Lattice.thy Author: Alessandro Coglio *) theory Finite_Lattice imports Product_Order begin text \A non-empty finite lattice is a complete lattice. Since types are never empty in Isabelle/HOL, a type of classes \<^class>\finite\ and \<^class>\lattice\ should also have class \<^class>\complete_lattice\. A type class is defined that extends classes \<^class>\finite\ and \<^class>\lattice\ with the operators \<^const>\bot\, \<^const>\top\, \<^const>\Inf\, and \<^const>\Sup\, along with assumptions that define these operators in terms of the ones of classes \<^class>\finite\ and \<^class>\lattice\. The resulting class is a subclass of \<^class>\complete_lattice\.\ class finite_lattice_complete = finite + lattice + bot + top + Inf + Sup + assumes bot_def: "bot = Inf_fin UNIV" assumes top_def: "top = Sup_fin UNIV" assumes Inf_def: "Inf A = Finite_Set.fold inf top A" assumes Sup_def: "Sup A = Finite_Set.fold sup bot A" text \The definitional assumptions on the operators \<^const>\bot\ and \<^const>\top\ of class \<^class>\finite_lattice_complete\ ensure that they yield bottom and top.\ lemma finite_lattice_complete_bot_least: "(bot::'a::finite_lattice_complete) \ x" by (auto simp: bot_def intro: Inf_fin.coboundedI) instance finite_lattice_complete \ order_bot by standard (auto simp: finite_lattice_complete_bot_least) lemma finite_lattice_complete_top_greatest: "(top::'a::finite_lattice_complete) \ x" by (auto simp: top_def Sup_fin.coboundedI) instance finite_lattice_complete \ order_top by standard (auto simp: finite_lattice_complete_top_greatest) instance finite_lattice_complete \ bounded_lattice .. text \The definitional assumptions on the operators \<^const>\Inf\ and \<^const>\Sup\ of class \<^class>\finite_lattice_complete\ ensure that they yield infimum and supremum.\ lemma finite_lattice_complete_Inf_empty: "Inf {} = (top :: 'a::finite_lattice_complete)" by (simp add: Inf_def) lemma finite_lattice_complete_Sup_empty: "Sup {} = (bot :: 'a::finite_lattice_complete)" by (simp add: Sup_def) lemma finite_lattice_complete_Inf_insert: fixes A :: "'a::finite_lattice_complete set" shows "Inf (insert x A) = inf x (Inf A)" proof - interpret comp_fun_idem "inf :: 'a \ _" by (fact comp_fun_idem_inf) show ?thesis by (simp add: Inf_def) qed lemma finite_lattice_complete_Sup_insert: fixes A :: "'a::finite_lattice_complete set" shows "Sup (insert x A) = sup x (Sup A)" proof - interpret comp_fun_idem "sup :: 'a \ _" by (fact comp_fun_idem_sup) show ?thesis by (simp add: Sup_def) qed lemma finite_lattice_complete_Inf_lower: "(x::'a::finite_lattice_complete) \ A \ Inf A \ x" using finite [of A] by (induct A) (auto simp add: finite_lattice_complete_Inf_insert intro: le_infI2) lemma finite_lattice_complete_Inf_greatest: "\x::'a::finite_lattice_complete \ A. z \ x \ z \ Inf A" using finite [of A] by (induct A) (auto simp add: finite_lattice_complete_Inf_empty finite_lattice_complete_Inf_insert) lemma finite_lattice_complete_Sup_upper: "(x::'a::finite_lattice_complete) \ A \ Sup A \ x" using finite [of A] by (induct A) (auto simp add: finite_lattice_complete_Sup_insert intro: le_supI2) lemma finite_lattice_complete_Sup_least: "\x::'a::finite_lattice_complete \ A. z \ x \ z \ Sup A" using finite [of A] by (induct A) (auto simp add: finite_lattice_complete_Sup_empty finite_lattice_complete_Sup_insert) instance finite_lattice_complete \ complete_lattice proof qed (auto simp: finite_lattice_complete_Inf_lower finite_lattice_complete_Inf_greatest finite_lattice_complete_Sup_upper finite_lattice_complete_Sup_least finite_lattice_complete_Inf_empty finite_lattice_complete_Sup_empty) text \The product of two finite lattices is already a finite lattice.\ lemma finite_bot_prod: "(bot :: ('a::finite_lattice_complete \ 'b::finite_lattice_complete)) = Inf_fin UNIV" by (metis Inf_fin.coboundedI UNIV_I bot.extremum_uniqueI finite_UNIV) lemma finite_top_prod: "(top :: ('a::finite_lattice_complete \ 'b::finite_lattice_complete)) = Sup_fin UNIV" by (metis Sup_fin.coboundedI UNIV_I top.extremum_uniqueI finite_UNIV) lemma finite_Inf_prod: "Inf(A :: ('a::finite_lattice_complete \ 'b::finite_lattice_complete) set) = Finite_Set.fold inf top A" by (metis Inf_fold_inf finite) lemma finite_Sup_prod: "Sup (A :: ('a::finite_lattice_complete \ 'b::finite_lattice_complete) set) = Finite_Set.fold sup bot A" by (metis Sup_fold_sup finite) instance prod :: (finite_lattice_complete, finite_lattice_complete) finite_lattice_complete by standard (auto simp: finite_bot_prod finite_top_prod finite_Inf_prod finite_Sup_prod) text \Functions with a finite domain and with a finite lattice as codomain already form a finite lattice.\ lemma finite_bot_fun: "(bot :: ('a::finite \ 'b::finite_lattice_complete)) = Inf_fin UNIV" by (metis Inf_UNIV Inf_fin_Inf empty_not_UNIV finite) lemma finite_top_fun: "(top :: ('a::finite \ 'b::finite_lattice_complete)) = Sup_fin UNIV" by (metis Sup_UNIV Sup_fin_Sup empty_not_UNIV finite) lemma finite_Inf_fun: "Inf (A::('a::finite \ 'b::finite_lattice_complete) set) = Finite_Set.fold inf top A" by (metis Inf_fold_inf finite) lemma finite_Sup_fun: "Sup (A::('a::finite \ 'b::finite_lattice_complete) set) = Finite_Set.fold sup bot A" by (metis Sup_fold_sup finite) instance "fun" :: (finite, finite_lattice_complete) finite_lattice_complete by standard (auto simp: finite_bot_fun finite_top_fun finite_Inf_fun finite_Sup_fun) subsection \Finite Distributive Lattices\ text \A finite distributive lattice is a complete lattice whose \<^const>\inf\ and \<^const>\sup\ operators distribute over \<^const>\Sup\ and \<^const>\Inf\.\ class finite_distrib_lattice_complete = distrib_lattice + finite_lattice_complete lemma finite_distrib_lattice_complete_sup_Inf: "sup (x::'a::finite_distrib_lattice_complete) (Inf A) = (INF y\A. sup x y)" using finite by (induct A rule: finite_induct) (simp_all add: sup_inf_distrib1) lemma finite_distrib_lattice_complete_inf_Sup: "inf (x::'a::finite_distrib_lattice_complete) (Sup A) = (SUP y\A. inf x y)" using finite [of A] by induct (simp_all add: inf_sup_distrib1) context finite_distrib_lattice_complete begin subclass finite_distrib_lattice - apply standard - apply (simp_all add: Inf_def Sup_def bot_def top_def) - apply (metis (mono_tags) insert_UNIV local.Sup_fin.eq_fold local.bot_def local.finite_UNIV local.top_def) - apply (simp add: comp_fun_idem.fold_insert_idem local.comp_fun_idem_inf) - apply (metis (mono_tags) insert_UNIV local.Inf_fin.eq_fold local.finite_UNIV) - apply (simp add: comp_fun_idem.fold_insert_idem local.comp_fun_idem_sup) - apply (metis (mono_tags) insert_UNIV local.Inf_fin.eq_fold local.finite_UNIV) - apply (metis (mono_tags) insert_UNIV local.Sup_fin.eq_fold local.finite_UNIV) - done +proof - + show "class.finite_distrib_lattice Inf Sup inf (\) (<) sup bot top" + proof + show "bot = Inf UNIV" + unfolding bot_def top_def Inf_def + using Inf_fin.eq_fold Inf_fin.insert inf.absorb2 by force + next + show "top = Sup UNIV" + unfolding bot_def top_def Sup_def + using Sup_fin.eq_fold Sup_fin.insert by force + next + show "Inf {} = Sup UNIV" + unfolding Inf_def Sup_def bot_def top_def + using Sup_fin.eq_fold Sup_fin.insert by force + next + show "Sup {} = Inf UNIV" + unfolding Inf_def Sup_def bot_def top_def + using Inf_fin.eq_fold Inf_fin.insert inf.absorb2 by force + next + interpret comp_fun_idem_inf: comp_fun_idem inf + by (fact comp_fun_idem_inf) + show "Inf (insert a A) = inf a (Inf A)" for a A + using comp_fun_idem_inf.fold_insert_idem Inf_def finite by simp + next + interpret comp_fun_idem_sup: comp_fun_idem sup + by (fact comp_fun_idem_sup) + show "Sup (insert a A) = sup a (Sup A)" for a A + using comp_fun_idem_sup.fold_insert_idem Sup_def finite by simp + qed +qed end instance finite_distrib_lattice_complete \ complete_distrib_lattice .. text \The product of two finite distributive lattices is already a finite distributive lattice.\ instance prod :: (finite_distrib_lattice_complete, finite_distrib_lattice_complete) finite_distrib_lattice_complete .. text \Functions with a finite domain and with a finite distributive lattice as codomain already form a finite distributive lattice.\ instance "fun" :: (finite, finite_distrib_lattice_complete) finite_distrib_lattice_complete .. subsection \Linear Orders\ text \A linear order is a distributive lattice. A type class is defined that extends class \<^class>\linorder\ with the operators \<^const>\inf\ and \<^const>\sup\, along with assumptions that define these operators in terms of the ones of class \<^class>\linorder\. The resulting class is a subclass of \<^class>\distrib_lattice\.\ class linorder_lattice = linorder + inf + sup + assumes inf_def: "inf x y = (if x \ y then x else y)" assumes sup_def: "sup x y = (if x \ y then x else y)" text \The definitional assumptions on the operators \<^const>\inf\ and \<^const>\sup\ of class \<^class>\linorder_lattice\ ensure that they yield infimum and supremum and that they distribute over each other.\ lemma linorder_lattice_inf_le1: "inf (x::'a::linorder_lattice) y \ x" unfolding inf_def by (metis (full_types) linorder_linear) lemma linorder_lattice_inf_le2: "inf (x::'a::linorder_lattice) y \ y" unfolding inf_def by (metis (full_types) linorder_linear) lemma linorder_lattice_inf_greatest: "(x::'a::linorder_lattice) \ y \ x \ z \ x \ inf y z" unfolding inf_def by (metis (full_types)) lemma linorder_lattice_sup_ge1: "sup (x::'a::linorder_lattice) y \ x" unfolding sup_def by (metis (full_types) linorder_linear) lemma linorder_lattice_sup_ge2: "sup (x::'a::linorder_lattice) y \ y" unfolding sup_def by (metis (full_types) linorder_linear) lemma linorder_lattice_sup_least: "(x::'a::linorder_lattice) \ y \ x \ z \ x \ sup y z" by (auto simp: sup_def) lemma linorder_lattice_sup_inf_distrib1: "sup (x::'a::linorder_lattice) (inf y z) = inf (sup x y) (sup x z)" by (auto simp: inf_def sup_def) instance linorder_lattice \ distrib_lattice proof qed (auto simp: linorder_lattice_inf_le1 linorder_lattice_inf_le2 linorder_lattice_inf_greatest linorder_lattice_sup_ge1 linorder_lattice_sup_ge2 linorder_lattice_sup_least linorder_lattice_sup_inf_distrib1) subsection \Finite Linear Orders\ text \A (non-empty) finite linear order is a complete linear order.\ class finite_linorder_complete = linorder_lattice + finite_lattice_complete instance finite_linorder_complete \ complete_linorder .. text \A (non-empty) finite linear order is a complete lattice whose \<^const>\inf\ and \<^const>\sup\ operators distribute over \<^const>\Sup\ and \<^const>\Inf\.\ instance finite_linorder_complete \ finite_distrib_lattice_complete .. end diff --git a/src/HOL/Library/Mapping.thy b/src/HOL/Library/Mapping.thy --- a/src/HOL/Library/Mapping.thy +++ b/src/HOL/Library/Mapping.thy @@ -1,656 +1,934 @@ (* Title: HOL/Library/Mapping.thy Author: Florian Haftmann and Ondrej Kuncar *) section \An abstract view on maps for code generation.\ theory Mapping -imports Main +imports Main AList begin subsection \Parametricity transfer rules\ lemma map_of_foldr: "map_of xs = foldr (\(k, v) m. m(k \ v)) xs Map.empty" (* FIXME move *) using map_add_map_of_foldr [of Map.empty] by auto context includes lifting_syntax begin lemma empty_parametric: "(A ===> rel_option B) Map.empty Map.empty" by transfer_prover lemma lookup_parametric: "((A ===> B) ===> A ===> B) (\m k. m k) (\m k. m k)" by transfer_prover lemma update_parametric: assumes [transfer_rule]: "bi_unique A" shows "(A ===> B ===> (A ===> rel_option B) ===> A ===> rel_option B) (\k v m. m(k \ v)) (\k v m. m(k \ v))" by transfer_prover lemma delete_parametric: assumes [transfer_rule]: "bi_unique A" shows "(A ===> (A ===> rel_option B) ===> A ===> rel_option B) (\k m. m(k := None)) (\k m. m(k := None))" by transfer_prover lemma is_none_parametric [transfer_rule]: "(rel_option A ===> HOL.eq) Option.is_none Option.is_none" by (auto simp add: Option.is_none_def rel_fun_def rel_option_iff split: option.split) lemma dom_parametric: assumes [transfer_rule]: "bi_total A" shows "((A ===> rel_option B) ===> rel_set A) dom dom" unfolding dom_def [abs_def] Option.is_none_def [symmetric] by transfer_prover +lemma graph_parametric: + assumes "bi_total A" + shows "((A ===> rel_option B) ===> rel_set (rel_prod A B)) Map.graph Map.graph" +proof + fix f g assume "(A ===> rel_option B) f g" + with assms[unfolded bi_total_def] show "rel_set (rel_prod A B) (Map.graph f) (Map.graph g)" + unfolding graph_def rel_set_def rel_fun_def + by auto (metis option_rel_Some1 option_rel_Some2)+ +qed + lemma map_of_parametric [transfer_rule]: assumes [transfer_rule]: "bi_unique R1" shows "(list_all2 (rel_prod R1 R2) ===> R1 ===> rel_option R2) map_of map_of" unfolding map_of_def by transfer_prover lemma map_entry_parametric [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(A ===> (B ===> B) ===> (A ===> rel_option B) ===> A ===> rel_option B) (\k f m. (case m k of None \ m | Some v \ m (k \ (f v)))) (\k f m. (case m k of None \ m | Some v \ m (k \ (f v))))" by transfer_prover lemma tabulate_parametric: assumes [transfer_rule]: "bi_unique A" shows "(list_all2 A ===> (A ===> B) ===> A ===> rel_option B) (\ks f. (map_of (map (\k. (k, f k)) ks))) (\ks f. (map_of (map (\k. (k, f k)) ks)))" by transfer_prover lemma bulkload_parametric: "(list_all2 A ===> HOL.eq ===> rel_option A) (\xs k. if k < length xs then Some (xs ! k) else None) (\xs k. if k < length xs then Some (xs ! k) else None)" proof fix xs ys assume "list_all2 A xs ys" then show "(HOL.eq ===> rel_option A) (\k. if k < length xs then Some (xs ! k) else None) (\k. if k < length ys then Some (ys ! k) else None)" apply induct apply auto unfolding rel_fun_def apply clarsimp apply (case_tac xa) apply (auto dest: list_all2_lengthD list_all2_nthD) done qed lemma map_parametric: "((A ===> B) ===> (C ===> D) ===> (B ===> rel_option C) ===> A ===> rel_option D) (\f g m. (map_option g \ m \ f)) (\f g m. (map_option g \ m \ f))" by transfer_prover lemma combine_with_key_parametric: "((A ===> B ===> B ===> B) ===> (A ===> rel_option B) ===> (A ===> rel_option B) ===> (A ===> rel_option B)) (\f m1 m2 x. combine_options (f x) (m1 x) (m2 x)) (\f m1 m2 x. combine_options (f x) (m1 x) (m2 x))" unfolding combine_options_def by transfer_prover lemma combine_parametric: "((B ===> B ===> B) ===> (A ===> rel_option B) ===> (A ===> rel_option B) ===> (A ===> rel_option B)) (\f m1 m2 x. combine_options f (m1 x) (m2 x)) (\f m1 m2 x. combine_options f (m1 x) (m2 x))" unfolding combine_options_def by transfer_prover end subsection \Type definition and primitive operations\ typedef ('a, 'b) mapping = "UNIV :: ('a \ 'b) set" morphisms rep Mapping .. setup_lifting type_definition_mapping lift_definition empty :: "('a, 'b) mapping" is Map.empty parametric empty_parametric . lift_definition lookup :: "('a, 'b) mapping \ 'a \ 'b option" is "\m k. m k" parametric lookup_parametric . definition "lookup_default d m k = (case Mapping.lookup m k of None \ d | Some v \ v)" lift_definition update :: "'a \ 'b \ ('a, 'b) mapping \ ('a, 'b) mapping" is "\k v m. m(k \ v)" parametric update_parametric . lift_definition delete :: "'a \ ('a, 'b) mapping \ ('a, 'b) mapping" is "\k m. m(k := None)" parametric delete_parametric . lift_definition filter :: "('a \ 'b \ bool) \ ('a, 'b) mapping \ ('a, 'b) mapping" is "\P m k. case m k of None \ None | Some v \ if P k v then Some v else None" . lift_definition keys :: "('a, 'b) mapping \ 'a set" is dom parametric dom_parametric . +lift_definition entries :: "('a, 'b) mapping \ ('a \ 'b) set" + is Map.graph parametric graph_parametric . + lift_definition tabulate :: "'a list \ ('a \ 'b) \ ('a, 'b) mapping" is "\ks f. (map_of (List.map (\k. (k, f k)) ks))" parametric tabulate_parametric . lift_definition bulkload :: "'a list \ (nat, 'a) mapping" is "\xs k. if k < length xs then Some (xs ! k) else None" parametric bulkload_parametric . lift_definition map :: "('c \ 'a) \ ('b \ 'd) \ ('a, 'b) mapping \ ('c, 'd) mapping" is "\f g m. (map_option g \ m \ f)" parametric map_parametric . lift_definition map_values :: "('c \ 'a \ 'b) \ ('c, 'a) mapping \ ('c, 'b) mapping" is "\f m x. map_option (f x) (m x)" . lift_definition combine_with_key :: "('a \ 'b \ 'b \ 'b) \ ('a,'b) mapping \ ('a,'b) mapping \ ('a,'b) mapping" is "\f m1 m2 x. combine_options (f x) (m1 x) (m2 x)" parametric combine_with_key_parametric . lift_definition combine :: "('b \ 'b \ 'b) \ ('a,'b) mapping \ ('a,'b) mapping \ ('a,'b) mapping" is "\f m1 m2 x. combine_options f (m1 x) (m2 x)" parametric combine_parametric . definition "All_mapping m P \ (\x. case Mapping.lookup m x of None \ True | Some y \ P x y)" declare [[code drop: map]] subsection \Functorial structure\ functor map: map by (transfer, auto simp add: fun_eq_iff option.map_comp option.map_id)+ subsection \Derived operations\ definition ordered_keys :: "('a::linorder, 'b) mapping \ 'a list" where "ordered_keys m = (if finite (keys m) then sorted_list_of_set (keys m) else [])" +definition ordered_entries :: "('a::linorder, 'b) mapping \ ('a \ 'b) list" + where "ordered_entries m = (if finite (entries m) then sorted_key_list_of_set fst (entries m) + else [])" + +definition fold :: "('a::linorder \ 'b \ 'c \ 'c) \ ('a, 'b) mapping \ 'c \ 'c" + where "fold f m a = List.fold (case_prod f) (ordered_entries m) a" + definition is_empty :: "('a, 'b) mapping \ bool" where "is_empty m \ keys m = {}" definition size :: "('a, 'b) mapping \ nat" where "size m = (if finite (keys m) then card (keys m) else 0)" definition replace :: "'a \ 'b \ ('a, 'b) mapping \ ('a, 'b) mapping" where "replace k v m = (if k \ keys m then update k v m else m)" definition default :: "'a \ 'b \ ('a, 'b) mapping \ ('a, 'b) mapping" where "default k v m = (if k \ keys m then m else update k v m)" text \Manual derivation of transfer rule is non-trivial\ lift_definition map_entry :: "'a \ ('b \ 'b) \ ('a, 'b) mapping \ ('a, 'b) mapping" is "\k f m. (case m k of None \ m | Some v \ m (k \ (f v)))" parametric map_entry_parametric . lemma map_entry_code [code]: "map_entry k f m = (case lookup m k of None \ m | Some v \ update k (f v) m)" by transfer rule definition map_default :: "'a \ 'b \ ('b \ 'b) \ ('a, 'b) mapping \ ('a, 'b) mapping" where "map_default k v f m = map_entry k f (default k v m)" definition of_alist :: "('k \ 'v) list \ ('k, 'v) mapping" where "of_alist xs = foldr (\(k, v) m. update k v m) xs empty" instantiation mapping :: (type, type) equal begin definition "HOL.equal m1 m2 \ (\k. lookup m1 k = lookup m2 k)" instance apply standard unfolding equal_mapping_def apply transfer apply auto done end context includes lifting_syntax begin lemma [transfer_rule]: assumes [transfer_rule]: "bi_total A" and [transfer_rule]: "bi_unique B" shows "(pcr_mapping A B ===> pcr_mapping A B ===> (=)) HOL.eq HOL.equal" unfolding equal by transfer_prover lemma of_alist_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique R1" shows "(list_all2 (rel_prod R1 R2) ===> pcr_mapping R1 R2) map_of of_alist" unfolding of_alist_def [abs_def] map_of_foldr [abs_def] by transfer_prover end subsection \Properties\ lemma mapping_eqI: "(\x. lookup m x = lookup m' x) \ m = m'" by transfer (simp add: fun_eq_iff) lemma mapping_eqI': assumes "\x. x \ Mapping.keys m \ Mapping.lookup_default d m x = Mapping.lookup_default d m' x" and "Mapping.keys m = Mapping.keys m'" shows "m = m'" proof (intro mapping_eqI) show "Mapping.lookup m x = Mapping.lookup m' x" for x proof (cases "Mapping.lookup m x") case None then have "x \ Mapping.keys m" by transfer (simp add: dom_def) then have "x \ Mapping.keys m'" by (simp add: assms) then have "Mapping.lookup m' x = None" by transfer (simp add: dom_def) with None show ?thesis by simp next case (Some y) then have A: "x \ Mapping.keys m" by transfer (simp add: dom_def) then have "x \ Mapping.keys m'" by (simp add: assms) then have "\y'. Mapping.lookup m' x = Some y'" by transfer (simp add: dom_def) with Some assms(1)[OF A] show ?thesis by (auto simp add: lookup_default_def) qed qed lemma lookup_update: "lookup (update k v m) k = Some v" by transfer simp lemma lookup_update_neq: "k \ k' \ lookup (update k v m) k' = lookup m k'" by transfer simp lemma lookup_update': "Mapping.lookup (update k v m) k' = (if k = k' then Some v else lookup m k')" by (auto simp: lookup_update lookup_update_neq) lemma lookup_empty: "lookup empty k = None" by transfer simp lemma lookup_filter: "lookup (filter P m) k = (case lookup m k of None \ None | Some v \ if P k v then Some v else None)" by transfer simp_all lemma lookup_map_values: "lookup (map_values f m) k = map_option (f k) (lookup m k)" by transfer simp_all lemma lookup_default_empty: "lookup_default d empty k = d" by (simp add: lookup_default_def lookup_empty) lemma lookup_default_update: "lookup_default d (update k v m) k = v" by (simp add: lookup_default_def lookup_update) lemma lookup_default_update_neq: "k \ k' \ lookup_default d (update k v m) k' = lookup_default d m k'" by (simp add: lookup_default_def lookup_update_neq) lemma lookup_default_update': "lookup_default d (update k v m) k' = (if k = k' then v else lookup_default d m k')" by (auto simp: lookup_default_update lookup_default_update_neq) lemma lookup_default_filter: "lookup_default d (filter P m) k = (if P k (lookup_default d m k) then lookup_default d m k else d)" by (simp add: lookup_default_def lookup_filter split: option.splits) lemma lookup_default_map_values: "lookup_default (f k d) (map_values f m) k = f k (lookup_default d m k)" by (simp add: lookup_default_def lookup_map_values split: option.splits) lemma lookup_combine_with_key: "Mapping.lookup (combine_with_key f m1 m2) x = combine_options (f x) (Mapping.lookup m1 x) (Mapping.lookup m2 x)" by transfer (auto split: option.splits) lemma combine_altdef: "combine f m1 m2 = combine_with_key (\_. f) m1 m2" by transfer' (rule refl) lemma lookup_combine: "Mapping.lookup (combine f m1 m2) x = combine_options f (Mapping.lookup m1 x) (Mapping.lookup m2 x)" by transfer (auto split: option.splits) lemma lookup_default_neutral_combine_with_key: assumes "\x. f k d x = x" "\x. f k x d = x" shows "Mapping.lookup_default d (combine_with_key f m1 m2) k = f k (Mapping.lookup_default d m1 k) (Mapping.lookup_default d m2 k)" by (auto simp: lookup_default_def lookup_combine_with_key assms split: option.splits) lemma lookup_default_neutral_combine: assumes "\x. f d x = x" "\x. f x d = x" shows "Mapping.lookup_default d (combine f m1 m2) x = f (Mapping.lookup_default d m1 x) (Mapping.lookup_default d m2 x)" by (auto simp: lookup_default_def lookup_combine assms split: option.splits) lemma lookup_map_entry: "lookup (map_entry x f m) x = map_option f (lookup m x)" by transfer (auto split: option.splits) lemma lookup_map_entry_neq: "x \ y \ lookup (map_entry x f m) y = lookup m y" by transfer (auto split: option.splits) lemma lookup_map_entry': "lookup (map_entry x f m) y = (if x = y then map_option f (lookup m y) else lookup m y)" by transfer (auto split: option.splits) lemma lookup_default: "lookup (default x d m) x = Some (lookup_default d m x)" unfolding lookup_default_def default_def by transfer (auto split: option.splits) lemma lookup_default_neq: "x \ y \ lookup (default x d m) y = lookup m y" unfolding lookup_default_def default_def by transfer (auto split: option.splits) lemma lookup_default': "lookup (default x d m) y = (if x = y then Some (lookup_default d m x) else lookup m y)" unfolding lookup_default_def default_def by transfer (auto split: option.splits) lemma lookup_map_default: "lookup (map_default x d f m) x = Some (f (lookup_default d m x))" unfolding lookup_default_def default_def by (simp add: map_default_def lookup_map_entry lookup_default lookup_default_def) lemma lookup_map_default_neq: "x \ y \ lookup (map_default x d f m) y = lookup m y" unfolding lookup_default_def default_def by (simp add: map_default_def lookup_map_entry_neq lookup_default_neq) lemma lookup_map_default': "lookup (map_default x d f m) y = (if x = y then Some (f (lookup_default d m x)) else lookup m y)" unfolding lookup_default_def default_def by (simp add: map_default_def lookup_map_entry' lookup_default' lookup_default_def) lemma lookup_tabulate: assumes "distinct xs" shows "Mapping.lookup (Mapping.tabulate xs f) x = (if x \ set xs then Some (f x) else None)" using assms by transfer (auto simp: map_of_eq_None_iff o_def dest!: map_of_SomeD) lemma lookup_of_alist: "Mapping.lookup (Mapping.of_alist xs) k = map_of xs k" by transfer simp_all lemma keys_is_none_rep [code_unfold]: "k \ keys m \ \ (Option.is_none (lookup m k))" by transfer (auto simp add: Option.is_none_def) lemma update_update: "update k v (update k w m) = update k v m" "k \ l \ update k v (update l w m) = update l w (update k v m)" by (transfer; simp add: fun_upd_twist)+ lemma update_delete [simp]: "update k v (delete k m) = update k v m" by transfer simp lemma delete_update: "delete k (update k v m) = delete k m" "k \ l \ delete k (update l v m) = update l v (delete k m)" by (transfer; simp add: fun_upd_twist)+ lemma delete_empty [simp]: "delete k empty = empty" by transfer simp lemma replace_update: "k \ keys m \ replace k v m = m" "k \ keys m \ replace k v m = update k v m" by (transfer; auto simp add: replace_def fun_upd_twist)+ lemma map_values_update: "map_values f (update k v m) = update k (f k v) (map_values f m)" by transfer (simp_all add: fun_eq_iff) lemma size_mono: "finite (keys m') \ keys m \ keys m' \ size m \ size m'" unfolding size_def by (auto intro: card_mono) lemma size_empty [simp]: "size empty = 0" unfolding size_def by transfer simp lemma size_update: "finite (keys m) \ size (update k v m) = (if k \ keys m then size m else Suc (size m))" unfolding size_def by transfer (auto simp add: insert_dom) lemma size_delete: "size (delete k m) = (if k \ keys m then size m - 1 else size m)" unfolding size_def by transfer simp lemma size_tabulate [simp]: "size (tabulate ks f) = length (remdups ks)" unfolding size_def by transfer (auto simp add: map_of_map_restrict card_set comp_def) lemma keys_filter: "keys (filter P m) \ keys m" by transfer (auto split: option.splits) lemma size_filter: "finite (keys m) \ size (filter P m) \ size m" by (intro size_mono keys_filter) lemma bulkload_tabulate: "bulkload xs = tabulate [0.. is_empty (update k v m)" unfolding is_empty_def by transfer simp lemma is_empty_delete: "is_empty (delete k m) \ is_empty m \ keys m = {k}" unfolding is_empty_def by transfer (auto simp del: dom_eq_empty_conv) lemma is_empty_replace [simp]: "is_empty (replace k v m) \ is_empty m" unfolding is_empty_def replace_def by transfer auto lemma is_empty_default [simp]: "\ is_empty (default k v m)" unfolding is_empty_def default_def by transfer auto lemma is_empty_map_entry [simp]: "is_empty (map_entry k f m) \ is_empty m" unfolding is_empty_def by transfer (auto split: option.split) lemma is_empty_map_values [simp]: "is_empty (map_values f m) \ is_empty m" unfolding is_empty_def by transfer (auto simp: fun_eq_iff) lemma is_empty_map_default [simp]: "\ is_empty (map_default k v f m)" by (simp add: map_default_def) lemma keys_dom_lookup: "keys m = dom (Mapping.lookup m)" by transfer rule lemma keys_empty [simp]: "keys empty = {}" - by transfer simp + by transfer (fact dom_empty) + +lemma in_keysD: "k \ keys m \ \v. lookup m k = Some v" + by transfer (fact domD) + +lemma in_entriesI: "lookup m k = Some v \ (k, v) \ entries m" + by transfer (fact in_graphI) lemma keys_update [simp]: "keys (update k v m) = insert k (keys m)" by transfer simp lemma keys_delete [simp]: "keys (delete k m) = keys m - {k}" by transfer simp lemma keys_replace [simp]: "keys (replace k v m) = keys m" unfolding replace_def by transfer (simp add: insert_absorb) lemma keys_default [simp]: "keys (default k v m) = insert k (keys m)" unfolding default_def by transfer (simp add: insert_absorb) lemma keys_map_entry [simp]: "keys (map_entry k f m) = keys m" by transfer (auto split: option.split) lemma keys_map_default [simp]: "keys (map_default k v f m) = insert k (keys m)" by (simp add: map_default_def) lemma keys_map_values [simp]: "keys (map_values f m) = keys m" by transfer (simp_all add: dom_def) lemma keys_combine_with_key [simp]: "Mapping.keys (combine_with_key f m1 m2) = Mapping.keys m1 \ Mapping.keys m2" by transfer (auto simp: dom_def combine_options_def split: option.splits) lemma keys_combine [simp]: "Mapping.keys (combine f m1 m2) = Mapping.keys m1 \ Mapping.keys m2" by (simp add: combine_altdef) lemma keys_tabulate [simp]: "keys (tabulate ks f) = set ks" by transfer (simp add: map_of_map_restrict o_def) lemma keys_of_alist [simp]: "keys (of_alist xs) = set (List.map fst xs)" by transfer (simp_all add: dom_map_of_conv_image_fst) lemma keys_bulkload [simp]: "keys (bulkload xs) = {0.. finite (keys m) \ ordered_keys m = []" by (simp add: ordered_keys_def) lemma ordered_keys_empty [simp]: "ordered_keys empty = []" by (simp add: ordered_keys_def) lemma ordered_keys_update [simp]: "k \ keys m \ ordered_keys (update k v m) = ordered_keys m" "finite (keys m) \ k \ keys m \ ordered_keys (update k v m) = insort k (ordered_keys m)" by (simp_all add: ordered_keys_def) - (auto simp only: sorted_list_of_set_insert [symmetric] insert_absorb) + (auto simp only: sorted_list_of_set_insert_remove[symmetric] insert_absorb) lemma ordered_keys_delete [simp]: "ordered_keys (delete k m) = remove1 k (ordered_keys m)" proof (cases "finite (keys m)") case False then show ?thesis by simp next case fin: True show ?thesis proof (cases "k \ keys m") case False with fin have "k \ set (sorted_list_of_set (keys m))" by simp with False show ?thesis by (simp add: ordered_keys_def remove1_idem) next case True with fin show ?thesis by (simp add: ordered_keys_def sorted_list_of_set_remove) qed qed lemma ordered_keys_replace [simp]: "ordered_keys (replace k v m) = ordered_keys m" by (simp add: replace_def) lemma ordered_keys_default [simp]: "k \ keys m \ ordered_keys (default k v m) = ordered_keys m" "finite (keys m) \ k \ keys m \ ordered_keys (default k v m) = insort k (ordered_keys m)" by (simp_all add: default_def) lemma ordered_keys_map_entry [simp]: "ordered_keys (map_entry k f m) = ordered_keys m" by (simp add: ordered_keys_def) lemma ordered_keys_map_default [simp]: "k \ keys m \ ordered_keys (map_default k v f m) = ordered_keys m" "finite (keys m) \ k \ keys m \ ordered_keys (map_default k v f m) = insort k (ordered_keys m)" by (simp_all add: map_default_def) lemma ordered_keys_tabulate [simp]: "ordered_keys (tabulate ks f) = sort (remdups ks)" by (simp add: ordered_keys_def sorted_list_of_set_sort_remdups) lemma ordered_keys_bulkload [simp]: "ordered_keys (bulkload ks) = [0..k m. update k (f k) m) xs empty" +lemma tabulate_fold: "tabulate xs f = List.fold (\k m. update k (f k) m) xs empty" proof transfer fix f :: "'a \ 'b" and xs have "map_of (List.map (\k. (k, f k)) xs) = foldr (\k m. m(k \ f k)) xs Map.empty" by (simp add: foldr_map comp_def map_of_foldr) - also have "foldr (\k m. m(k \ f k)) xs = fold (\k m. m(k \ f k)) xs" + also have "foldr (\k m. m(k \ f k)) xs = List.fold (\k m. m(k \ f k)) xs" by (rule foldr_fold) (simp add: fun_eq_iff) - ultimately show "map_of (List.map (\k. (k, f k)) xs) = fold (\k m. m(k \ f k)) xs Map.empty" + ultimately show "map_of (List.map (\k. (k, f k)) xs) = List.fold (\k m. m(k \ f k)) xs Map.empty" by simp qed lemma All_mapping_mono: "(\k v. k \ keys m \ P k v \ Q k v) \ All_mapping m P \ All_mapping m Q" unfolding All_mapping_def by transfer (auto simp: All_mapping_def dom_def split: option.splits) lemma All_mapping_empty [simp]: "All_mapping Mapping.empty P" by (auto simp: All_mapping_def lookup_empty) lemma All_mapping_update_iff: "All_mapping (Mapping.update k v m) P \ P k v \ All_mapping m (\k' v'. k = k' \ P k' v')" unfolding All_mapping_def proof safe assume "\x. case Mapping.lookup (Mapping.update k v m) x of None \ True | Some y \ P x y" then have *: "case Mapping.lookup (Mapping.update k v m) x of None \ True | Some y \ P x y" for x by blast from *[of k] show "P k v" by (simp add: lookup_update) show "case Mapping.lookup m x of None \ True | Some v' \ k = x \ P x v'" for x using *[of x] by (auto simp add: lookup_update' split: if_splits option.splits) next assume "P k v" assume "\x. case Mapping.lookup m x of None \ True | Some v' \ k = x \ P x v'" then have A: "case Mapping.lookup m x of None \ True | Some v' \ k = x \ P x v'" for x by blast show "case Mapping.lookup (Mapping.update k v m) x of None \ True | Some xa \ P x xa" for x using \P k v\ A[of x] by (auto simp: lookup_update' split: option.splits) qed lemma All_mapping_update: "P k v \ All_mapping m (\k' v'. k = k' \ P k' v') \ All_mapping (Mapping.update k v m) P" by (simp add: All_mapping_update_iff) lemma All_mapping_filter_iff: "All_mapping (filter P m) Q \ All_mapping m (\k v. P k v \ Q k v)" by (auto simp: All_mapping_def lookup_filter split: option.splits) lemma All_mapping_filter: "All_mapping m Q \ All_mapping (filter P m) Q" by (auto simp: All_mapping_filter_iff intro: All_mapping_mono) lemma All_mapping_map_values: "All_mapping (map_values f m) P \ All_mapping m (\k v. P k (f k v))" by (auto simp: All_mapping_def lookup_map_values split: option.splits) lemma All_mapping_tabulate: "(\x\set xs. P x (f x)) \ All_mapping (Mapping.tabulate xs f) P" unfolding All_mapping_def apply (intro allI) apply transfer apply (auto split: option.split dest!: map_of_SomeD) done lemma All_mapping_alist: "(\k v. (k, v) \ set xs \ P k v) \ All_mapping (Mapping.of_alist xs) P" by (auto simp: All_mapping_def lookup_of_alist dest!: map_of_SomeD split: option.splits) lemma combine_empty [simp]: "combine f Mapping.empty y = y" "combine f y Mapping.empty = y" by (transfer; force)+ lemma (in abel_semigroup) comm_monoid_set_combine: "comm_monoid_set (combine f) Mapping.empty" by standard (transfer fixing: f, simp add: combine_options_ac[of f] ac_simps)+ locale combine_mapping_abel_semigroup = abel_semigroup begin sublocale combine: comm_monoid_set "combine f" Mapping.empty by (rule comm_monoid_set_combine) lemma fold_combine_code: "combine.F g (set xs) = foldr (\x. combine f (g x)) (remdups xs) Mapping.empty" proof - have "combine.F g (set xs) = foldr (\x. combine f (g x)) xs Mapping.empty" if "distinct xs" for xs using that by (induction xs) simp_all from this[of "remdups xs"] show ?thesis by simp qed lemma keys_fold_combine: "finite A \ Mapping.keys (combine.F g A) = (\x\A. Mapping.keys (g x))" by (induct A rule: finite_induct) simp_all end +subsubsection \@{term [source] entries}, @{term [source] ordered_entries}, + and @{term [source] fold}\ + +context linorder +begin + +sublocale folding_Map_graph: folding_insort_key "(\)" "(<)" "Map.graph m" fst for m + by unfold_locales (fact inj_on_fst_graph) + +end + +lemma sorted_fst_list_of_set_insort_Map_graph[simp]: + assumes "finite (dom m)" "fst x \ dom m" + shows "sorted_key_list_of_set fst (insert x (Map.graph m)) + = insort_key fst x (sorted_key_list_of_set fst (Map.graph m))" +proof(cases x) + case (Pair k v) + with \fst x \ dom m\ have "Map.graph m \ Map.graph (m(k \ v))" + by(auto simp: graph_def) + moreover from Pair \fst x \ dom m\ have "(k, v) \ Map.graph m" + using graph_domD by fastforce + ultimately show ?thesis + using Pair assms folding_Map_graph.sorted_key_list_of_set_insert[where ?m="m(k \ v)"] + by auto +qed + +lemma sorted_fst_list_of_set_insort_insert_Map_graph[simp]: + assumes "finite (dom m)" "fst x \ dom m" + shows "sorted_key_list_of_set fst (insert x (Map.graph m)) + = insort_insert_key fst x (sorted_key_list_of_set fst (Map.graph m))" +proof(cases x) + case (Pair k v) + with \fst x \ dom m\ have "Map.graph m \ Map.graph (m(k \ v))" + by(auto simp: graph_def) + with assms Pair show ?thesis + unfolding sorted_fst_list_of_set_insort_Map_graph[OF assms] insort_insert_key_def + using folding_Map_graph.set_sorted_key_list_of_set in_graphD by (fastforce split: if_splits) +qed + +lemma linorder_finite_Map_induct[consumes 1, case_names empty update]: + fixes m :: "'a::linorder \ 'b" + assumes "finite (dom m)" + assumes "P Map.empty" + assumes "\k v m. \ finite (dom m); k \ dom m; (\k'. k' \ dom m \ k' \ k); P m \ + \ P (m(k \ v))" + shows "P m" +proof - + let ?key_list = "\m. sorted_list_of_set (dom m)" + from assms(1,2) show ?thesis + proof(induction "length (?key_list m)" arbitrary: m) + case 0 + then have "sorted_list_of_set (dom m) = []" + by auto + with \finite (dom m)\ have "m = Map.empty" + by auto + with \P Map.empty\ show ?case by simp + next + case (Suc n) + then obtain x xs where x_xs: "sorted_list_of_set (dom m) = xs @ [x]" + by (metis append_butlast_last_id length_greater_0_conv zero_less_Suc) + have "sorted_list_of_set (dom (m(x := None))) = xs" + proof - + have "distinct (xs @ [x])" + by (metis sorted_list_of_set.distinct_sorted_key_list_of_set x_xs) + then have "remove1 x (xs @ [x]) = xs" + by (simp add: remove1_append) + with \finite (dom m)\ x_xs show ?thesis + by (simp add: sorted_list_of_set_remove) + qed + moreover have "k \ x" if "k \ dom (m(x := None))" for k + proof - + from x_xs have "sorted (xs @ [x])" + by (metis sorted_list_of_set.sorted_sorted_key_list_of_set) + moreover from \k \ dom (m(x := None))\ have "k \ set xs" + using \finite (dom m)\ \sorted_list_of_set (dom (m(x := None))) = xs\ + by auto + ultimately show "k \ x" + by (simp add: sorted_append) + qed + moreover from \finite (dom m)\ have "finite (dom (m(x := None)))" "x \ dom (m(x := None))" + by simp_all + moreover have "P (m(x := None))" + using Suc \sorted_list_of_set (dom (m(x := None))) = xs\ x_xs by auto + ultimately show ?case + using assms(3)[where ?m="m(x := None)"] by (metis fun_upd_triv fun_upd_upd not_Some_eq) + qed +qed + +lemma delete_insort_fst[simp]: "AList.delete k (insort_key fst (k, v) xs) = AList.delete k xs" + by (induction xs) simp_all + +lemma insort_fst_delete: "\ fst x \ k2; sorted (List.map fst xs) \ + \ insort_key fst x (AList.delete k2 xs) = AList.delete k2 (insort_key fst x xs)" + by (induction xs) (fastforce simp add: insort_is_Cons order_trans)+ + +lemma sorted_fst_list_of_set_Map_graph_fun_upd_None[simp]: + "sorted_key_list_of_set fst (Map.graph (m(k := None))) + = AList.delete k (sorted_key_list_of_set fst (Map.graph m))" +proof(cases "finite (Map.graph m)") + assume "finite (Map.graph m)" + from this[unfolded finite_graph_iff_finite_dom] show ?thesis + proof(induction rule: finite_Map_induct) + let ?list_of="sorted_key_list_of_set fst" + case (update k2 v2 m) + note [simp] = \k2 \ dom m\ \finite (dom m)\ + + have right_eq: "AList.delete k (?list_of (Map.graph (m(k2 \ v2)))) + = AList.delete k (insort_key fst (k2, v2) (?list_of (Map.graph m)))" + by simp + + show ?case + proof(cases "k = k2") + case True + then have "?list_of (Map.graph ((m(k2 \ v2))(k := None))) + = AList.delete k (insort_key fst (k2, v2) (?list_of (Map.graph m)))" + using fst_graph_eq_dom update.IH by auto + then show ?thesis + using right_eq by metis + next + case False + then have "AList.delete k (insort_key fst (k2, v2) (?list_of (Map.graph m))) + = insort_key fst (k2, v2) (?list_of (Map.graph (m(k := None))))" + by (auto simp add: insort_fst_delete update.IH + folding_Map_graph.sorted_sorted_key_list_of_set[OF subset_refl]) + also have "\ = ?list_of (insert (k2, v2) (Map.graph (m(k := None))))" + by auto + also from False \k2 \ dom m\ have "\ = ?list_of (Map.graph ((m(k2 \ v2))(k := None)))" + by (metis graph_map_upd domIff fun_upd_triv fun_upd_twist) + finally show ?thesis using right_eq by metis + qed + qed simp +qed simp + +lemma entries_lookup: "entries m = Map.graph (lookup m)" + by transfer rule + +lemma entries_empty[simp]: "entries empty = {}" + by transfer (fact graph_empty) + +lemma finite_entries_iff_finite_keys[simp]: + "finite (entries m) = finite (keys m)" + by transfer (fact finite_graph_iff_finite_dom) + +lemma entries_update[simp]: + "entries (update k v m) = insert (k, v) (entries (delete k m))" + by transfer (fact graph_map_upd) + +lemma Mapping_delete_if_notin_keys[simp]: + "k \ Mapping.keys m \ delete k m = m" + by transfer simp + +lemma entries_delete: + "entries (delete k m) = {e \ entries m. fst e \ k}" + by transfer (fact graph_fun_upd_None) + +lemma entries_of_alist[simp]: + "distinct (List.map fst xs) \ entries (of_alist xs) = set xs" + by transfer (fact graph_map_of_if_distinct_ran) + +lemma entries_keysD: + "x \ entries m \ fst x \ keys m" + by transfer (fact graph_domD) + +lemma finite_keys_entries[simp]: + "finite (keys (update k v m)) = finite (keys m)" + by transfer simp + +lemma set_ordered_entries[simp]: + "finite (Mapping.keys m) \ set (ordered_entries m) = entries m" + unfolding ordered_entries_def + by transfer (auto simp: folding_Map_graph.set_sorted_key_list_of_set[OF subset_refl]) + +lemma distinct_ordered_entries[simp]: "distinct (List.map fst (ordered_entries m))" + unfolding ordered_entries_def + by transfer (simp add: folding_Map_graph.distinct_sorted_key_list_of_set[OF subset_refl]) + +lemma sorted_ordered_entries[simp]: "sorted (List.map fst (ordered_entries m))" + unfolding ordered_entries_def + by transfer (auto intro: folding_Map_graph.sorted_sorted_key_list_of_set) + +lemma ordered_entries_infinite[simp]: + "\ finite (Mapping.keys m) \ ordered_entries m = []" + by (simp add: ordered_entries_def) + +lemma ordered_entries_empty[simp]: "ordered_entries empty = []" + by (simp add: ordered_entries_def) + +lemma ordered_entries_update[simp]: + assumes "finite (keys m)" + shows "ordered_entries (update k v m) + = insort_insert_key fst (k, v) (AList.delete k (ordered_entries m))" +proof - + let ?list_of="sorted_key_list_of_set fst" and ?insort="insort_insert_key fst" + + have *: "?list_of (insert (k, v) (Map.graph (m(k := None)))) + = ?insort (k, v) (AList.delete k (?list_of (Map.graph m)))" if "finite (dom m)" for m + proof - + from \finite (dom m)\ have "?list_of (insert (k, v) (Map.graph (m(k := None)))) + = ?insort (k, v) (?list_of (Map.graph (m(k := None))))" + by (intro sorted_fst_list_of_set_insort_insert_Map_graph) (simp_all add: subset_insertI) + then show ?thesis by simp + qed + from assms show ?thesis + unfolding ordered_entries_def + apply (transfer fixing: k v) using "*" by auto +qed + +lemma ordered_entries_delete[simp]: + "ordered_entries (delete k m) = AList.delete k (ordered_entries m)" + unfolding ordered_entries_def by transfer auto + +lemma fold_empty[simp]: "fold f empty a = a" + unfolding fold_def by simp + +lemma insort_key_is_snoc_if_sorted_and_distinct: + assumes "sorted (List.map f xs)" "f y \ f ` set xs" "\x \ set xs. f x \ f y" + shows "insort_key f y xs = xs @ [y]" + using assms by (induction xs) (auto dest!: insort_is_Cons) + +lemma fold_update: + assumes "finite (keys m)" + assumes "k \ keys m" "\k'. k' \ keys m \ k' \ k" + shows "fold f (update k v m) a = f k v (fold f m a)" +proof - + from assms have k_notin_entries: "k \ fst ` set (ordered_entries m)" + using entries_keysD by fastforce + with assms have "ordered_entries (update k v m) + = insort_insert_key fst (k, v) (ordered_entries m)" + by simp + also from k_notin_entries have "\ = ordered_entries m @ [(k, v)]" + proof - + from assms have "\x \ set (ordered_entries m). fst x \ fst (k, v)" + unfolding ordered_entries_def + by transfer (fastforce simp: folding_Map_graph.set_sorted_key_list_of_set[OF order_refl] + dest: graph_domD) + from insort_key_is_snoc_if_sorted_and_distinct[OF _ _ this] k_notin_entries show ?thesis + unfolding insort_insert_key_def by auto + qed + finally show ?thesis unfolding fold_def by simp +qed + +lemma linorder_finite_Mapping_induct[consumes 1, case_names empty update]: + fixes m :: "('a::linorder, 'b) mapping" + assumes "finite (keys m)" + assumes "P empty" + assumes "\k v m. + \ finite (keys m); k \ keys m; (\k'. k' \ keys m \ k' \ k); P m \ + \ P (update k v m)" + shows "P m" + using assms by transfer (simp add: linorder_finite_Map_induct) + subsection \Code generator setup\ hide_const (open) empty is_empty rep lookup lookup_default filter update delete ordered_keys keys size replace default map_entry map_default tabulate bulkload map map_values combine of_alist + entries ordered_entries fold end diff --git a/src/HOL/Library/Multiset.thy b/src/HOL/Library/Multiset.thy --- a/src/HOL/Library/Multiset.thy +++ b/src/HOL/Library/Multiset.thy @@ -1,4002 +1,4002 @@ (* Title: HOL/Library/Multiset.thy Author: Tobias Nipkow, Markus Wenzel, Lawrence C Paulson, Norbert Voelker Author: Andrei Popescu, TU Muenchen Author: Jasmin Blanchette, Inria, LORIA, MPII Author: Dmitriy Traytel, TU Muenchen Author: Mathias Fleury, MPII *) section \(Finite) Multisets\ theory Multiset imports Cancellation begin subsection \The type of multisets\ typedef 'a multiset = \{f :: 'a \ nat. finite {x. f x > 0}}\ morphisms count Abs_multiset proof show \(\x. 0::nat) \ {f. finite {x. f x > 0}}\ by simp qed setup_lifting type_definition_multiset lemma count_Abs_multiset: \count (Abs_multiset f) = f\ if \finite {x. f x > 0}\ by (rule Abs_multiset_inverse) (simp add: that) lemma multiset_eq_iff: "M = N \ (\a. count M a = count N a)" by (simp only: count_inject [symmetric] fun_eq_iff) lemma multiset_eqI: "(\x. count A x = count B x) \ A = B" using multiset_eq_iff by auto text \Preservation of the representing set \<^term>\multiset\.\ lemma diff_preserves_multiset: \finite {x. 0 < M x - N x}\ if \finite {x. 0 < M x}\ for M N :: \'a \ nat\ using that by (rule rev_finite_subset) auto lemma filter_preserves_multiset: \finite {x. 0 < (if P x then M x else 0)}\ if \finite {x. 0 < M x}\ for M N :: \'a \ nat\ using that by (rule rev_finite_subset) auto lemmas in_multiset = diff_preserves_multiset filter_preserves_multiset subsection \Representing multisets\ text \Multiset enumeration\ instantiation multiset :: (type) cancel_comm_monoid_add begin lift_definition zero_multiset :: \'a multiset\ is \\a. 0\ by simp abbreviation empty_mset :: \'a multiset\ (\{#}\) where \empty_mset \ 0\ lift_definition plus_multiset :: \'a multiset \ 'a multiset \ 'a multiset\ is \\M N a. M a + N a\ by simp lift_definition minus_multiset :: \'a multiset \ 'a multiset \ 'a multiset\ is \\M N a. M a - N a\ by (rule diff_preserves_multiset) instance by (standard; transfer) (simp_all add: fun_eq_iff) end context begin qualified definition is_empty :: "'a multiset \ bool" where [code_abbrev]: "is_empty A \ A = {#}" end lemma add_mset_in_multiset: \finite {x. 0 < (if x = a then Suc (M x) else M x)}\ if \finite {x. 0 < M x}\ using that by (simp add: flip: insert_Collect) lift_definition add_mset :: "'a \ 'a multiset \ 'a multiset" is "\a M b. if b = a then Suc (M b) else M b" by (rule add_mset_in_multiset) syntax "_multiset" :: "args \ 'a multiset" ("{#(_)#}") translations "{#x, xs#}" == "CONST add_mset x {#xs#}" "{#x#}" == "CONST add_mset x {#}" lemma count_empty [simp]: "count {#} a = 0" by (simp add: zero_multiset.rep_eq) lemma count_add_mset [simp]: "count (add_mset b A) a = (if b = a then Suc (count A a) else count A a)" by (simp add: add_mset.rep_eq) lemma count_single: "count {#b#} a = (if b = a then 1 else 0)" by simp lemma add_mset_not_empty [simp]: \add_mset a A \ {#}\ and empty_not_add_mset [simp]: "{#} \ add_mset a A" by (auto simp: multiset_eq_iff) lemma add_mset_add_mset_same_iff [simp]: "add_mset a A = add_mset a B \ A = B" by (auto simp: multiset_eq_iff) lemma add_mset_commute: "add_mset x (add_mset y M) = add_mset y (add_mset x M)" by (auto simp: multiset_eq_iff) subsection \Basic operations\ subsubsection \Conversion to set and membership\ definition set_mset :: \'a multiset \ 'a set\ where \set_mset M = {x. count M x > 0}\ abbreviation member_mset :: \'a \ 'a multiset \ bool\ where \member_mset a M \ a \ set_mset M\ notation member_mset (\'(\#')\) and member_mset (\(_/ \# _)\ [50, 51] 50) notation (ASCII) member_mset (\'(:#')\) and member_mset (\(_/ :# _)\ [50, 51] 50) abbreviation not_member_mset :: \'a \ 'a multiset \ bool\ where \not_member_mset a M \ a \ set_mset M\ notation not_member_mset (\'(\#')\) and not_member_mset (\(_/ \# _)\ [50, 51] 50) notation (ASCII) not_member_mset (\'(~:#')\) and not_member_mset (\(_/ ~:# _)\ [50, 51] 50) context begin qualified abbreviation Ball :: "'a multiset \ ('a \ bool) \ bool" where "Ball M \ Set.Ball (set_mset M)" qualified abbreviation Bex :: "'a multiset \ ('a \ bool) \ bool" where "Bex M \ Set.Bex (set_mset M)" end syntax "_MBall" :: "pttrn \ 'a set \ bool \ bool" ("(3\_\#_./ _)" [0, 0, 10] 10) "_MBex" :: "pttrn \ 'a set \ bool \ bool" ("(3\_\#_./ _)" [0, 0, 10] 10) syntax (ASCII) "_MBall" :: "pttrn \ 'a set \ bool \ bool" ("(3\_:#_./ _)" [0, 0, 10] 10) "_MBex" :: "pttrn \ 'a set \ bool \ bool" ("(3\_:#_./ _)" [0, 0, 10] 10) translations "\x\#A. P" \ "CONST Multiset.Ball A (\x. P)" "\x\#A. P" \ "CONST Multiset.Bex A (\x. P)" print_translation \ [Syntax_Trans.preserve_binder_abs2_tr' \<^const_syntax>\Multiset.Ball\ \<^syntax_const>\_MBall\, Syntax_Trans.preserve_binder_abs2_tr' \<^const_syntax>\Multiset.Bex\ \<^syntax_const>\_MBex\] \ \ \to avoid eta-contraction of body\ lemma count_eq_zero_iff: "count M x = 0 \ x \# M" by (auto simp add: set_mset_def) lemma not_in_iff: "x \# M \ count M x = 0" by (auto simp add: count_eq_zero_iff) lemma count_greater_zero_iff [simp]: "count M x > 0 \ x \# M" by (auto simp add: set_mset_def) lemma count_inI: assumes "count M x = 0 \ False" shows "x \# M" proof (rule ccontr) assume "x \# M" with assms show False by (simp add: not_in_iff) qed lemma in_countE: assumes "x \# M" obtains n where "count M x = Suc n" proof - from assms have "count M x > 0" by simp then obtain n where "count M x = Suc n" using gr0_conv_Suc by blast with that show thesis . qed lemma count_greater_eq_Suc_zero_iff [simp]: "count M x \ Suc 0 \ x \# M" by (simp add: Suc_le_eq) lemma count_greater_eq_one_iff [simp]: "count M x \ 1 \ x \# M" by simp lemma set_mset_empty [simp]: "set_mset {#} = {}" by (simp add: set_mset_def) lemma set_mset_single: "set_mset {#b#} = {b}" by (simp add: set_mset_def) lemma set_mset_eq_empty_iff [simp]: "set_mset M = {} \ M = {#}" by (auto simp add: multiset_eq_iff count_eq_zero_iff) lemma finite_set_mset [iff]: "finite (set_mset M)" using count [of M] by simp lemma set_mset_add_mset_insert [simp]: \set_mset (add_mset a A) = insert a (set_mset A)\ by (auto simp flip: count_greater_eq_Suc_zero_iff split: if_splits) lemma multiset_nonemptyE [elim]: assumes "A \ {#}" obtains x where "x \# A" proof - have "\x. x \# A" by (rule ccontr) (insert assms, auto) with that show ?thesis by blast qed subsubsection \Union\ lemma count_union [simp]: "count (M + N) a = count M a + count N a" by (simp add: plus_multiset.rep_eq) lemma set_mset_union [simp]: "set_mset (M + N) = set_mset M \ set_mset N" by (simp only: set_eq_iff count_greater_zero_iff [symmetric] count_union) simp lemma union_mset_add_mset_left [simp]: "add_mset a A + B = add_mset a (A + B)" by (auto simp: multiset_eq_iff) lemma union_mset_add_mset_right [simp]: "A + add_mset a B = add_mset a (A + B)" by (auto simp: multiset_eq_iff) lemma add_mset_add_single: \add_mset a A = A + {#a#}\ by (subst union_mset_add_mset_right, subst add.comm_neutral) standard subsubsection \Difference\ instance multiset :: (type) comm_monoid_diff by standard (transfer; simp add: fun_eq_iff) lemma count_diff [simp]: "count (M - N) a = count M a - count N a" by (simp add: minus_multiset.rep_eq) lemma add_mset_diff_bothsides: \add_mset a M - add_mset a A = M - A\ by (auto simp: multiset_eq_iff) lemma in_diff_count: "a \# M - N \ count N a < count M a" by (simp add: set_mset_def) lemma count_in_diffI: assumes "\n. count N x = n + count M x \ False" shows "x \# M - N" proof (rule ccontr) assume "x \# M - N" then have "count N x = (count N x - count M x) + count M x" by (simp add: in_diff_count not_less) with assms show False by auto qed lemma in_diff_countE: assumes "x \# M - N" obtains n where "count M x = Suc n + count N x" proof - from assms have "count M x - count N x > 0" by (simp add: in_diff_count) then have "count M x > count N x" by simp then obtain n where "count M x = Suc n + count N x" using less_iff_Suc_add by auto with that show thesis . qed lemma in_diffD: assumes "a \# M - N" shows "a \# M" proof - have "0 \ count N a" by simp also from assms have "count N a < count M a" by (simp add: in_diff_count) finally show ?thesis by simp qed lemma set_mset_diff: "set_mset (M - N) = {a. count N a < count M a}" by (simp add: set_mset_def) lemma diff_empty [simp]: "M - {#} = M \ {#} - M = {#}" by rule (fact Groups.diff_zero, fact Groups.zero_diff) lemma diff_cancel: "A - A = {#}" by (fact Groups.diff_cancel) lemma diff_union_cancelR: "M + N - N = (M::'a multiset)" by (fact add_diff_cancel_right') lemma diff_union_cancelL: "N + M - N = (M::'a multiset)" by (fact add_diff_cancel_left') lemma diff_right_commute: fixes M N Q :: "'a multiset" shows "M - N - Q = M - Q - N" by (fact diff_right_commute) lemma diff_add: fixes M N Q :: "'a multiset" shows "M - (N + Q) = M - N - Q" by (rule sym) (fact diff_diff_add) lemma insert_DiffM [simp]: "x \# M \ add_mset x (M - {#x#}) = M" by (clarsimp simp: multiset_eq_iff) lemma insert_DiffM2: "x \# M \ (M - {#x#}) + {#x#} = M" by simp lemma diff_union_swap: "a \ b \ add_mset b (M - {#a#}) = add_mset b M - {#a#}" by (auto simp add: multiset_eq_iff) lemma diff_add_mset_swap [simp]: "b \# A \ add_mset b M - A = add_mset b (M - A)" by (auto simp add: multiset_eq_iff simp: not_in_iff) lemma diff_union_swap2 [simp]: "y \# M \ add_mset x M - {#y#} = add_mset x (M - {#y#})" by (metis add_mset_diff_bothsides diff_union_swap diff_zero insert_DiffM) lemma diff_diff_add_mset [simp]: "(M::'a multiset) - N - P = M - (N + P)" by (rule diff_diff_add) lemma diff_union_single_conv: "a \# J \ I + J - {#a#} = I + (J - {#a#})" by (simp add: multiset_eq_iff Suc_le_eq) lemma mset_add [elim?]: assumes "a \# A" obtains B where "A = add_mset a B" proof - from assms have "A = add_mset a (A - {#a#})" by simp with that show thesis . qed lemma union_iff: "a \# A + B \ a \# A \ a \# B" by auto subsubsection \Min and Max\ abbreviation Min_mset :: "'a::linorder multiset \ 'a" where "Min_mset m \ Min (set_mset m)" abbreviation Max_mset :: "'a::linorder multiset \ 'a" where "Max_mset m \ Max (set_mset m)" subsubsection \Equality of multisets\ lemma single_eq_single [simp]: "{#a#} = {#b#} \ a = b" by (auto simp add: multiset_eq_iff) lemma union_eq_empty [iff]: "M + N = {#} \ M = {#} \ N = {#}" by (auto simp add: multiset_eq_iff) lemma empty_eq_union [iff]: "{#} = M + N \ M = {#} \ N = {#}" by (auto simp add: multiset_eq_iff) lemma multi_self_add_other_not_self [simp]: "M = add_mset x M \ False" by (auto simp add: multiset_eq_iff) lemma add_mset_remove_trivial [simp]: \add_mset x M - {#x#} = M\ by (auto simp: multiset_eq_iff) lemma diff_single_trivial: "\ x \# M \ M - {#x#} = M" by (auto simp add: multiset_eq_iff not_in_iff) lemma diff_single_eq_union: "x \# M \ M - {#x#} = N \ M = add_mset x N" by auto lemma union_single_eq_diff: "add_mset x M = N \ M = N - {#x#}" unfolding add_mset_add_single[of _ M] by (fact add_implies_diff) lemma union_single_eq_member: "add_mset x M = N \ x \# N" by auto lemma add_mset_remove_trivial_If: "add_mset a (N - {#a#}) = (if a \# N then N else add_mset a N)" by (simp add: diff_single_trivial) lemma add_mset_remove_trivial_eq: \N = add_mset a (N - {#a#}) \ a \# N\ by (auto simp: add_mset_remove_trivial_If) lemma union_is_single: "M + N = {#a#} \ M = {#a#} \ N = {#} \ M = {#} \ N = {#a#}" (is "?lhs = ?rhs") proof show ?lhs if ?rhs using that by auto show ?rhs if ?lhs by (metis Multiset.diff_cancel add.commute add_diff_cancel_left' diff_add_zero diff_single_trivial insert_DiffM that) qed lemma single_is_union: "{#a#} = M + N \ {#a#} = M \ N = {#} \ M = {#} \ {#a#} = N" by (auto simp add: eq_commute [of "{#a#}" "M + N"] union_is_single) lemma add_eq_conv_diff: "add_mset a M = add_mset b N \ M = N \ a = b \ M = add_mset b (N - {#a#}) \ N = add_mset a (M - {#b#})" (is "?lhs \ ?rhs") (* shorter: by (simp add: multiset_eq_iff) fastforce *) proof show ?lhs if ?rhs using that by (auto simp add: add_mset_commute[of a b]) show ?rhs if ?lhs proof (cases "a = b") case True with \?lhs\ show ?thesis by simp next case False from \?lhs\ have "a \# add_mset b N" by (rule union_single_eq_member) with False have "a \# N" by auto moreover from \?lhs\ have "M = add_mset b N - {#a#}" by (rule union_single_eq_diff) moreover note False ultimately show ?thesis by (auto simp add: diff_right_commute [of _ "{#a#}"]) qed qed lemma add_mset_eq_single [iff]: "add_mset b M = {#a#} \ b = a \ M = {#}" by (auto simp: add_eq_conv_diff) lemma single_eq_add_mset [iff]: "{#a#} = add_mset b M \ b = a \ M = {#}" by (auto simp: add_eq_conv_diff) lemma insert_noteq_member: assumes BC: "add_mset b B = add_mset c C" and bnotc: "b \ c" shows "c \# B" proof - have "c \# add_mset c C" by simp have nc: "\ c \# {#b#}" using bnotc by simp then have "c \# add_mset b B" using BC by simp then show "c \# B" using nc by simp qed lemma add_eq_conv_ex: "(add_mset a M = add_mset b N) = (M = N \ a = b \ (\K. M = add_mset b K \ N = add_mset a K))" by (auto simp add: add_eq_conv_diff) lemma multi_member_split: "x \# M \ \A. M = add_mset x A" by (rule exI [where x = "M - {#x#}"]) simp lemma multiset_add_sub_el_shuffle: assumes "c \# B" and "b \ c" shows "add_mset b (B - {#c#}) = add_mset b B - {#c#}" proof - from \c \# B\ obtain A where B: "B = add_mset c A" by (blast dest: multi_member_split) have "add_mset b A = add_mset c (add_mset b A) - {#c#}" by simp then have "add_mset b A = add_mset b (add_mset c A) - {#c#}" by (simp add: \b \ c\) then show ?thesis using B by simp qed lemma add_mset_eq_singleton_iff[iff]: "add_mset x M = {#y#} \ M = {#} \ x = y" by auto subsubsection \Pointwise ordering induced by count\ definition subseteq_mset :: "'a multiset \ 'a multiset \ bool" (infix "\#" 50) where "A \# B \ (\a. count A a \ count B a)" definition subset_mset :: "'a multiset \ 'a multiset \ bool" (infix "\#" 50) where "A \# B \ A \# B \ A \ B" abbreviation (input) supseteq_mset :: "'a multiset \ 'a multiset \ bool" (infix "\#" 50) where "supseteq_mset A B \ B \# A" abbreviation (input) supset_mset :: "'a multiset \ 'a multiset \ bool" (infix "\#" 50) where "supset_mset A B \ B \# A" notation (input) subseteq_mset (infix "\#" 50) and supseteq_mset (infix "\#" 50) notation (ASCII) subseteq_mset (infix "<=#" 50) and subset_mset (infix "<#" 50) and supseteq_mset (infix ">=#" 50) and supset_mset (infix ">#" 50) global_interpretation subset_mset: ordering \(\#)\ \(\#)\ by standard (auto simp add: subset_mset_def subseteq_mset_def multiset_eq_iff intro: order.trans order.antisym) interpretation subset_mset: ordered_ab_semigroup_add_imp_le \(+)\ \(-)\ \(\#)\ \(\#)\ by standard (auto simp add: subset_mset_def subseteq_mset_def multiset_eq_iff intro: order_trans antisym) \ \FIXME: avoid junk stemming from type class interpretation\ interpretation subset_mset: ordered_ab_semigroup_monoid_add_imp_le "(+)" 0 "(-)" "(\#)" "(\#)" by standard \ \FIXME: avoid junk stemming from type class interpretation\ lemma mset_subset_eqI: "(\a. count A a \ count B a) \ A \# B" by (simp add: subseteq_mset_def) lemma mset_subset_eq_count: "A \# B \ count A a \ count B a" by (simp add: subseteq_mset_def) lemma mset_subset_eq_exists_conv: "(A::'a multiset) \# B \ (\C. B = A + C)" unfolding subseteq_mset_def apply (rule iffI) apply (rule exI [where x = "B - A"]) apply (auto intro: multiset_eq_iff [THEN iffD2]) done interpretation subset_mset: ordered_cancel_comm_monoid_diff "(+)" 0 "(\#)" "(\#)" "(-)" by standard (simp, fact mset_subset_eq_exists_conv) \ \FIXME: avoid junk stemming from type class interpretation\ declare subset_mset.add_diff_assoc[simp] subset_mset.add_diff_assoc2[simp] lemma mset_subset_eq_mono_add_right_cancel: "(A::'a multiset) + C \# B + C \ A \# B" by (fact subset_mset.add_le_cancel_right) lemma mset_subset_eq_mono_add_left_cancel: "C + (A::'a multiset) \# C + B \ A \# B" by (fact subset_mset.add_le_cancel_left) lemma mset_subset_eq_mono_add: "(A::'a multiset) \# B \ C \# D \ A + C \# B + D" by (fact subset_mset.add_mono) lemma mset_subset_eq_add_left: "(A::'a multiset) \# A + B" by simp lemma mset_subset_eq_add_right: "B \# (A::'a multiset) + B" by simp lemma single_subset_iff [simp]: "{#a#} \# M \ a \# M" by (auto simp add: subseteq_mset_def Suc_le_eq) lemma mset_subset_eq_single: "a \# B \ {#a#} \# B" by simp lemma mset_subset_eq_add_mset_cancel: \add_mset a A \# add_mset a B \ A \# B\ unfolding add_mset_add_single[of _ A] add_mset_add_single[of _ B] by (rule mset_subset_eq_mono_add_right_cancel) lemma multiset_diff_union_assoc: fixes A B C D :: "'a multiset" shows "C \# B \ A + B - C = A + (B - C)" by (fact subset_mset.diff_add_assoc) lemma mset_subset_eq_multiset_union_diff_commute: fixes A B C D :: "'a multiset" shows "B \# A \ A - B + C = A + C - B" by (fact subset_mset.add_diff_assoc2) lemma diff_subset_eq_self[simp]: "(M::'a multiset) - N \# M" by (simp add: subseteq_mset_def) lemma mset_subset_eqD: assumes "A \# B" and "x \# A" shows "x \# B" proof - from \x \# A\ have "count A x > 0" by simp also from \A \# B\ have "count A x \ count B x" by (simp add: subseteq_mset_def) finally show ?thesis by simp qed lemma mset_subsetD: "A \# B \ x \# A \ x \# B" by (auto intro: mset_subset_eqD [of A]) lemma set_mset_mono: "A \# B \ set_mset A \ set_mset B" by (metis mset_subset_eqD subsetI) lemma mset_subset_eq_insertD: "add_mset x A \# B \ x \# B \ A \# B" apply (rule conjI) apply (simp add: mset_subset_eqD) apply (clarsimp simp: subset_mset_def subseteq_mset_def) apply safe apply (erule_tac x = a in allE) apply (auto split: if_split_asm) done lemma mset_subset_insertD: "add_mset x A \# B \ x \# B \ A \# B" by (rule mset_subset_eq_insertD) simp lemma mset_subset_of_empty[simp]: "A \# {#} \ False" by (simp only: subset_mset.not_less_zero) lemma empty_subset_add_mset[simp]: "{#} \# add_mset x M" by (auto intro: subset_mset.gr_zeroI) lemma empty_le: "{#} \# A" by (fact subset_mset.zero_le) lemma insert_subset_eq_iff: "add_mset a A \# B \ a \# B \ A \# B - {#a#}" using le_diff_conv2 [of "Suc 0" "count B a" "count A a"] apply (auto simp add: subseteq_mset_def not_in_iff Suc_le_eq) apply (rule ccontr) apply (auto simp add: not_in_iff) done lemma insert_union_subset_iff: "add_mset a A \# B \ a \# B \ A \# B - {#a#}" by (auto simp add: insert_subset_eq_iff subset_mset_def) lemma subset_eq_diff_conv: "A - C \# B \ A \# B + C" by (simp add: subseteq_mset_def le_diff_conv) lemma multi_psub_of_add_self [simp]: "A \# add_mset x A" by (auto simp: subset_mset_def subseteq_mset_def) lemma multi_psub_self: "A \# A = False" by simp lemma mset_subset_add_mset [simp]: "add_mset x N \# add_mset x M \ N \# M" unfolding add_mset_add_single[of _ N] add_mset_add_single[of _ M] by (fact subset_mset.add_less_cancel_right) lemma mset_subset_diff_self: "c \# B \ B - {#c#} \# B" by (auto simp: subset_mset_def elim: mset_add) lemma Diff_eq_empty_iff_mset: "A - B = {#} \ A \# B" by (auto simp: multiset_eq_iff subseteq_mset_def) lemma add_mset_subseteq_single_iff[iff]: "add_mset a M \# {#b#} \ M = {#} \ a = b" proof assume A: "add_mset a M \# {#b#}" then have \a = b\ by (auto dest: mset_subset_eq_insertD) then show "M={#} \ a=b" using A by (simp add: mset_subset_eq_add_mset_cancel) qed simp subsubsection \Intersection and bounded union\ definition inter_mset :: \'a multiset \ 'a multiset \ 'a multiset\ (infixl \\#\ 70) where \A \# B = A - (A - B)\ lemma count_inter_mset [simp]: \count (A \# B) x = min (count A x) (count B x)\ by (simp add: inter_mset_def) (*global_interpretation subset_mset: semilattice_order \(\#)\ \(\#)\ \(\#)\ by standard (simp_all add: multiset_eq_iff subseteq_mset_def subset_mset_def min_def)*) interpretation subset_mset: semilattice_inf \(\#)\ \(\#)\ \(\#)\ by standard (simp_all add: multiset_eq_iff subseteq_mset_def) \ \FIXME: avoid junk stemming from type class interpretation\ definition union_mset :: \'a multiset \ 'a multiset \ 'a multiset\ (infixl \\#\ 70) where \A \# B = A + (B - A)\ lemma count_union_mset [simp]: \count (A \# B) x = max (count A x) (count B x)\ by (simp add: union_mset_def) global_interpretation subset_mset: semilattice_neutr_order \(\#)\ \{#}\ \(\#)\ \(\#)\ apply standard apply (simp_all add: multiset_eq_iff subseteq_mset_def subset_mset_def max_def) apply (auto simp add: le_antisym dest: sym) apply (metis nat_le_linear)+ done interpretation subset_mset: semilattice_sup \(\#)\ \(\#)\ \(\#)\ proof - have [simp]: "m \ n \ q \ n \ m + (q - m) \ n" for m n q :: nat by arith show "class.semilattice_sup (\#) (\#) (\#)" by standard (auto simp add: union_mset_def subseteq_mset_def) qed \ \FIXME: avoid junk stemming from type class interpretation\ interpretation subset_mset: bounded_lattice_bot "(\#)" "(\#)" "(\#)" "(\#)" "{#}" by standard auto \ \FIXME: avoid junk stemming from type class interpretation\ subsubsection \Additional intersection facts\ lemma set_mset_inter [simp]: "set_mset (A \# B) = set_mset A \ set_mset B" by (simp only: set_mset_def) auto lemma diff_intersect_left_idem [simp]: "M - M \# N = M - N" by (simp add: multiset_eq_iff min_def) lemma diff_intersect_right_idem [simp]: "M - N \# M = M - N" by (simp add: multiset_eq_iff min_def) lemma multiset_inter_single[simp]: "a \ b \ {#a#} \# {#b#} = {#}" by (rule multiset_eqI) auto lemma multiset_union_diff_commute: assumes "B \# C = {#}" shows "A + B - C = A - C + B" proof (rule multiset_eqI) fix x from assms have "min (count B x) (count C x) = 0" by (auto simp add: multiset_eq_iff) then have "count B x = 0 \ count C x = 0" unfolding min_def by (auto split: if_splits) then show "count (A + B - C) x = count (A - C + B) x" by auto qed lemma disjunct_not_in: "A \# B = {#} \ (\a. a \# A \ a \# B)" (is "?P \ ?Q") proof assume ?P show ?Q proof fix a from \?P\ have "min (count A a) (count B a) = 0" by (simp add: multiset_eq_iff) then have "count A a = 0 \ count B a = 0" by (cases "count A a \ count B a") (simp_all add: min_def) then show "a \# A \ a \# B" by (simp add: not_in_iff) qed next assume ?Q show ?P proof (rule multiset_eqI) fix a from \?Q\ have "count A a = 0 \ count B a = 0" by (auto simp add: not_in_iff) then show "count (A \# B) a = count {#} a" by auto qed qed lemma inter_mset_empty_distrib_right: "A \# (B + C) = {#} \ A \# B = {#} \ A \# C = {#}" by (meson disjunct_not_in union_iff) lemma inter_mset_empty_distrib_left: "(A + B) \# C = {#} \ A \# C = {#} \ B \# C = {#}" by (meson disjunct_not_in union_iff) lemma add_mset_inter_add_mset [simp]: "add_mset a A \# add_mset a B = add_mset a (A \# B)" by (rule multiset_eqI) simp lemma add_mset_disjoint [simp]: "add_mset a A \# B = {#} \ a \# B \ A \# B = {#}" "{#} = add_mset a A \# B \ a \# B \ {#} = A \# B" by (auto simp: disjunct_not_in) lemma disjoint_add_mset [simp]: "B \# add_mset a A = {#} \ a \# B \ B \# A = {#}" "{#} = A \# add_mset b B \ b \# A \ {#} = A \# B" by (auto simp: disjunct_not_in) lemma inter_add_left1: "\ x \# N \ (add_mset x M) \# N = M \# N" by (simp add: multiset_eq_iff not_in_iff) lemma inter_add_left2: "x \# N \ (add_mset x M) \# N = add_mset x (M \# (N - {#x#}))" by (auto simp add: multiset_eq_iff elim: mset_add) lemma inter_add_right1: "\ x \# N \ N \# (add_mset x M) = N \# M" by (simp add: multiset_eq_iff not_in_iff) lemma inter_add_right2: "x \# N \ N \# (add_mset x M) = add_mset x ((N - {#x#}) \# M)" by (auto simp add: multiset_eq_iff elim: mset_add) lemma disjunct_set_mset_diff: assumes "M \# N = {#}" shows "set_mset (M - N) = set_mset M" proof (rule set_eqI) fix a from assms have "a \# M \ a \# N" by (simp add: disjunct_not_in) then show "a \# M - N \ a \# M" by (auto dest: in_diffD) (simp add: in_diff_count not_in_iff) qed lemma at_most_one_mset_mset_diff: assumes "a \# M - {#a#}" shows "set_mset (M - {#a#}) = set_mset M - {a}" using assms by (auto simp add: not_in_iff in_diff_count set_eq_iff) lemma more_than_one_mset_mset_diff: assumes "a \# M - {#a#}" shows "set_mset (M - {#a#}) = set_mset M" proof (rule set_eqI) fix b have "Suc 0 < count M b \ count M b > 0" by arith then show "b \# M - {#a#} \ b \# M" using assms by (auto simp add: in_diff_count) qed lemma inter_iff: "a \# A \# B \ a \# A \ a \# B" by simp lemma inter_union_distrib_left: "A \# B + C = (A + C) \# (B + C)" by (simp add: multiset_eq_iff min_add_distrib_left) lemma inter_union_distrib_right: "C + A \# B = (C + A) \# (C + B)" using inter_union_distrib_left [of A B C] by (simp add: ac_simps) lemma inter_subset_eq_union: "A \# B \# A + B" by (auto simp add: subseteq_mset_def) subsubsection \Additional bounded union facts\ lemma set_mset_sup [simp]: \set_mset (A \# B) = set_mset A \ set_mset B\ by (simp only: set_mset_def) (auto simp add: less_max_iff_disj) lemma sup_union_left1 [simp]: "\ x \# N \ (add_mset x M) \# N = add_mset x (M \# N)" by (simp add: multiset_eq_iff not_in_iff) lemma sup_union_left2: "x \# N \ (add_mset x M) \# N = add_mset x (M \# (N - {#x#}))" by (simp add: multiset_eq_iff) lemma sup_union_right1 [simp]: "\ x \# N \ N \# (add_mset x M) = add_mset x (N \# M)" by (simp add: multiset_eq_iff not_in_iff) lemma sup_union_right2: "x \# N \ N \# (add_mset x M) = add_mset x ((N - {#x#}) \# M)" by (simp add: multiset_eq_iff) lemma sup_union_distrib_left: "A \# B + C = (A + C) \# (B + C)" by (simp add: multiset_eq_iff max_add_distrib_left) lemma union_sup_distrib_right: "C + A \# B = (C + A) \# (C + B)" using sup_union_distrib_left [of A B C] by (simp add: ac_simps) lemma union_diff_inter_eq_sup: "A + B - A \# B = A \# B" by (auto simp add: multiset_eq_iff) lemma union_diff_sup_eq_inter: "A + B - A \# B = A \# B" by (auto simp add: multiset_eq_iff) lemma add_mset_union: \add_mset a A \# add_mset a B = add_mset a (A \# B)\ by (auto simp: multiset_eq_iff max_def) subsection \Replicate and repeat operations\ definition replicate_mset :: "nat \ 'a \ 'a multiset" where "replicate_mset n x = (add_mset x ^^ n) {#}" lemma replicate_mset_0[simp]: "replicate_mset 0 x = {#}" unfolding replicate_mset_def by simp lemma replicate_mset_Suc [simp]: "replicate_mset (Suc n) x = add_mset x (replicate_mset n x)" unfolding replicate_mset_def by (induct n) (auto intro: add.commute) lemma count_replicate_mset[simp]: "count (replicate_mset n x) y = (if y = x then n else 0)" unfolding replicate_mset_def by (induct n) auto lift_definition repeat_mset :: \nat \ 'a multiset \ 'a multiset\ is \\n M a. n * M a\ by simp lemma count_repeat_mset [simp]: "count (repeat_mset i A) a = i * count A a" by transfer rule lemma repeat_mset_0 [simp]: \repeat_mset 0 M = {#}\ by transfer simp lemma repeat_mset_Suc [simp]: \repeat_mset (Suc n) M = M + repeat_mset n M\ by transfer simp lemma repeat_mset_right [simp]: "repeat_mset a (repeat_mset b A) = repeat_mset (a * b) A" by (auto simp: multiset_eq_iff left_diff_distrib') lemma left_diff_repeat_mset_distrib': \repeat_mset (i - j) u = repeat_mset i u - repeat_mset j u\ by (auto simp: multiset_eq_iff left_diff_distrib') lemma left_add_mult_distrib_mset: "repeat_mset i u + (repeat_mset j u + k) = repeat_mset (i+j) u + k" by (auto simp: multiset_eq_iff add_mult_distrib) lemma repeat_mset_distrib: "repeat_mset (m + n) A = repeat_mset m A + repeat_mset n A" by (auto simp: multiset_eq_iff Nat.add_mult_distrib) lemma repeat_mset_distrib2[simp]: "repeat_mset n (A + B) = repeat_mset n A + repeat_mset n B" by (auto simp: multiset_eq_iff add_mult_distrib2) lemma repeat_mset_replicate_mset[simp]: "repeat_mset n {#a#} = replicate_mset n a" by (auto simp: multiset_eq_iff) lemma repeat_mset_distrib_add_mset[simp]: "repeat_mset n (add_mset a A) = replicate_mset n a + repeat_mset n A" by (auto simp: multiset_eq_iff) lemma repeat_mset_empty[simp]: "repeat_mset n {#} = {#}" by transfer simp subsubsection \Simprocs\ lemma repeat_mset_iterate_add: \repeat_mset n M = iterate_add n M\ unfolding iterate_add_def by (induction n) auto lemma mset_subseteq_add_iff1: "j \ (i::nat) \ (repeat_mset i u + m \# repeat_mset j u + n) = (repeat_mset (i-j) u + m \# n)" by (auto simp add: subseteq_mset_def nat_le_add_iff1) lemma mset_subseteq_add_iff2: "i \ (j::nat) \ (repeat_mset i u + m \# repeat_mset j u + n) = (m \# repeat_mset (j-i) u + n)" by (auto simp add: subseteq_mset_def nat_le_add_iff2) lemma mset_subset_add_iff1: "j \ (i::nat) \ (repeat_mset i u + m \# repeat_mset j u + n) = (repeat_mset (i-j) u + m \# n)" unfolding subset_mset_def repeat_mset_iterate_add by (simp add: iterate_add_eq_add_iff1 mset_subseteq_add_iff1[unfolded repeat_mset_iterate_add]) lemma mset_subset_add_iff2: "i \ (j::nat) \ (repeat_mset i u + m \# repeat_mset j u + n) = (m \# repeat_mset (j-i) u + n)" unfolding subset_mset_def repeat_mset_iterate_add by (simp add: iterate_add_eq_add_iff2 mset_subseteq_add_iff2[unfolded repeat_mset_iterate_add]) ML_file \multiset_simprocs.ML\ lemma add_mset_replicate_mset_safe[cancelation_simproc_pre]: \NO_MATCH {#} M \ add_mset a M = {#a#} + M\ by simp declare repeat_mset_iterate_add[cancelation_simproc_pre] declare iterate_add_distrib[cancelation_simproc_pre] declare repeat_mset_iterate_add[symmetric, cancelation_simproc_post] declare add_mset_not_empty[cancelation_simproc_eq_elim] empty_not_add_mset[cancelation_simproc_eq_elim] subset_mset.le_zero_eq[cancelation_simproc_eq_elim] empty_not_add_mset[cancelation_simproc_eq_elim] add_mset_not_empty[cancelation_simproc_eq_elim] subset_mset.le_zero_eq[cancelation_simproc_eq_elim] le_zero_eq[cancelation_simproc_eq_elim] simproc_setup mseteq_cancel ("(l::'a multiset) + m = n" | "(l::'a multiset) = m + n" | "add_mset a m = n" | "m = add_mset a n" | "replicate_mset p a = n" | "m = replicate_mset p a" | "repeat_mset p m = n" | "m = repeat_mset p m") = \fn phi => Cancel_Simprocs.eq_cancel\ simproc_setup msetsubset_cancel ("(l::'a multiset) + m \# n" | "(l::'a multiset) \# m + n" | "add_mset a m \# n" | "m \# add_mset a n" | "replicate_mset p r \# n" | "m \# replicate_mset p r" | "repeat_mset p m \# n" | "m \# repeat_mset p m") = \fn phi => Multiset_Simprocs.subset_cancel_msets\ simproc_setup msetsubset_eq_cancel ("(l::'a multiset) + m \# n" | "(l::'a multiset) \# m + n" | "add_mset a m \# n" | "m \# add_mset a n" | "replicate_mset p r \# n" | "m \# replicate_mset p r" | "repeat_mset p m \# n" | "m \# repeat_mset p m") = \fn phi => Multiset_Simprocs.subseteq_cancel_msets\ simproc_setup msetdiff_cancel ("((l::'a multiset) + m) - n" | "(l::'a multiset) - (m + n)" | "add_mset a m - n" | "m - add_mset a n" | "replicate_mset p r - n" | "m - replicate_mset p r" | "repeat_mset p m - n" | "m - repeat_mset p m") = \fn phi => Cancel_Simprocs.diff_cancel\ subsubsection \Conditionally complete lattice\ instantiation multiset :: (type) Inf begin lift_definition Inf_multiset :: "'a multiset set \ 'a multiset" is "\A i. if A = {} then 0 else Inf ((\f. f i) ` A)" proof - fix A :: "('a \ nat) set" assume *: "\f. f \ A \ finite {x. 0 < f x}" show \finite {i. 0 < (if A = {} then 0 else INF f\A. f i)}\ proof (cases "A = {}") case False then obtain f where "f \ A" by blast hence "{i. Inf ((\f. f i) ` A) > 0} \ {i. f i > 0}" by (auto intro: less_le_trans[OF _ cInf_lower]) moreover from \f \ A\ * have "finite \" by simp ultimately have "finite {i. Inf ((\f. f i) ` A) > 0}" by (rule finite_subset) with False show ?thesis by simp qed simp_all qed instance .. end lemma Inf_multiset_empty: "Inf {} = {#}" by transfer simp_all lemma count_Inf_multiset_nonempty: "A \ {} \ count (Inf A) x = Inf ((\X. count X x) ` A)" by transfer simp_all instantiation multiset :: (type) Sup begin definition Sup_multiset :: "'a multiset set \ 'a multiset" where "Sup_multiset A = (if A \ {} \ subset_mset.bdd_above A then Abs_multiset (\i. Sup ((\X. count X i) ` A)) else {#})" lemma Sup_multiset_empty: "Sup {} = {#}" by (simp add: Sup_multiset_def) lemma Sup_multiset_unbounded: "\ subset_mset.bdd_above A \ Sup A = {#}" by (simp add: Sup_multiset_def) instance .. end lemma bdd_above_multiset_imp_bdd_above_count: assumes "subset_mset.bdd_above (A :: 'a multiset set)" shows "bdd_above ((\X. count X x) ` A)" proof - from assms obtain Y where Y: "\X\A. X \# Y" by (meson subset_mset.bdd_above.E) hence "count X x \ count Y x" if "X \ A" for X using that by (auto intro: mset_subset_eq_count) thus ?thesis by (intro bdd_aboveI[of _ "count Y x"]) auto qed lemma bdd_above_multiset_imp_finite_support: assumes "A \ {}" "subset_mset.bdd_above (A :: 'a multiset set)" shows "finite (\X\A. {x. count X x > 0})" proof - from assms obtain Y where Y: "\X\A. X \# Y" by (meson subset_mset.bdd_above.E) hence "count X x \ count Y x" if "X \ A" for X x using that by (auto intro: mset_subset_eq_count) hence "(\X\A. {x. count X x > 0}) \ {x. count Y x > 0}" by safe (erule less_le_trans) moreover have "finite \" by simp ultimately show ?thesis by (rule finite_subset) qed lemma Sup_multiset_in_multiset: \finite {i. 0 < (SUP M\A. count M i)}\ if \A \ {}\ \subset_mset.bdd_above A\ proof - have "{i. Sup ((\X. count X i) ` A) > 0} \ (\X\A. {i. 0 < count X i})" proof safe fix i assume pos: "(SUP X\A. count X i) > 0" show "i \ (\X\A. {i. 0 < count X i})" proof (rule ccontr) assume "i \ (\X\A. {i. 0 < count X i})" hence "\X\A. count X i \ 0" by (auto simp: count_eq_zero_iff) with that have "(SUP X\A. count X i) \ 0" by (intro cSup_least bdd_above_multiset_imp_bdd_above_count) auto with pos show False by simp qed qed moreover from that have "finite \" by (rule bdd_above_multiset_imp_finite_support) ultimately show "finite {i. Sup ((\X. count X i) ` A) > 0}" by (rule finite_subset) qed lemma count_Sup_multiset_nonempty: \count (Sup A) x = (SUP X\A. count X x)\ if \A \ {}\ \subset_mset.bdd_above A\ using that by (simp add: Sup_multiset_def Sup_multiset_in_multiset count_Abs_multiset) interpretation subset_mset: conditionally_complete_lattice Inf Sup "(\#)" "(\#)" "(\#)" "(\#)" proof fix X :: "'a multiset" and A assume "X \ A" show "Inf A \# X" proof (rule mset_subset_eqI) fix x from \X \ A\ have "A \ {}" by auto hence "count (Inf A) x = (INF X\A. count X x)" by (simp add: count_Inf_multiset_nonempty) also from \X \ A\ have "\ \ count X x" by (intro cInf_lower) simp_all finally show "count (Inf A) x \ count X x" . qed next fix X :: "'a multiset" and A assume nonempty: "A \ {}" and le: "\Y. Y \ A \ X \# Y" show "X \# Inf A" proof (rule mset_subset_eqI) fix x from nonempty have "count X x \ (INF X\A. count X x)" by (intro cInf_greatest) (auto intro: mset_subset_eq_count le) also from nonempty have "\ = count (Inf A) x" by (simp add: count_Inf_multiset_nonempty) finally show "count X x \ count (Inf A) x" . qed next fix X :: "'a multiset" and A assume X: "X \ A" and bdd: "subset_mset.bdd_above A" show "X \# Sup A" proof (rule mset_subset_eqI) fix x from X have "A \ {}" by auto have "count X x \ (SUP X\A. count X x)" by (intro cSUP_upper X bdd_above_multiset_imp_bdd_above_count bdd) also from count_Sup_multiset_nonempty[OF \A \ {}\ bdd] have "(SUP X\A. count X x) = count (Sup A) x" by simp finally show "count X x \ count (Sup A) x" . qed next fix X :: "'a multiset" and A assume nonempty: "A \ {}" and ge: "\Y. Y \ A \ Y \# X" from ge have bdd: "subset_mset.bdd_above A" by blast show "Sup A \# X" proof (rule mset_subset_eqI) fix x from count_Sup_multiset_nonempty[OF \A \ {}\ bdd] have "count (Sup A) x = (SUP X\A. count X x)" . also from nonempty have "\ \ count X x" by (intro cSup_least) (auto intro: mset_subset_eq_count ge) finally show "count (Sup A) x \ count X x" . qed qed \ \FIXME: avoid junk stemming from type class interpretation\ lemma set_mset_Inf: assumes "A \ {}" shows "set_mset (Inf A) = (\X\A. set_mset X)" proof safe fix x X assume "x \# Inf A" "X \ A" hence nonempty: "A \ {}" by (auto simp: Inf_multiset_empty) from \x \# Inf A\ have "{#x#} \# Inf A" by auto also from \X \ A\ have "\ \# X" by (rule subset_mset.cInf_lower) simp_all finally show "x \# X" by simp next fix x assume x: "x \ (\X\A. set_mset X)" hence "{#x#} \# X" if "X \ A" for X using that by auto from assms and this have "{#x#} \# Inf A" by (rule subset_mset.cInf_greatest) thus "x \# Inf A" by simp qed lemma in_Inf_multiset_iff: assumes "A \ {}" shows "x \# Inf A \ (\X\A. x \# X)" proof - from assms have "set_mset (Inf A) = (\X\A. set_mset X)" by (rule set_mset_Inf) also have "x \ \ \ (\X\A. x \# X)" by simp finally show ?thesis . qed lemma in_Inf_multisetD: "x \# Inf A \ X \ A \ x \# X" by (subst (asm) in_Inf_multiset_iff) auto lemma set_mset_Sup: assumes "subset_mset.bdd_above A" shows "set_mset (Sup A) = (\X\A. set_mset X)" proof safe fix x assume "x \# Sup A" hence nonempty: "A \ {}" by (auto simp: Sup_multiset_empty) show "x \ (\X\A. set_mset X)" proof (rule ccontr) assume x: "x \ (\X\A. set_mset X)" have "count X x \ count (Sup A) x" if "X \ A" for X x using that by (intro mset_subset_eq_count subset_mset.cSup_upper assms) with x have "X \# Sup A - {#x#}" if "X \ A" for X using that by (auto simp: subseteq_mset_def algebra_simps not_in_iff) hence "Sup A \# Sup A - {#x#}" by (intro subset_mset.cSup_least nonempty) with \x \# Sup A\ show False by (auto simp: subseteq_mset_def simp flip: count_greater_zero_iff dest!: spec[of _ x]) qed next fix x X assume "x \ set_mset X" "X \ A" hence "{#x#} \# X" by auto also have "X \# Sup A" by (intro subset_mset.cSup_upper \X \ A\ assms) finally show "x \ set_mset (Sup A)" by simp qed lemma in_Sup_multiset_iff: assumes "subset_mset.bdd_above A" shows "x \# Sup A \ (\X\A. x \# X)" proof - from assms have "set_mset (Sup A) = (\X\A. set_mset X)" by (rule set_mset_Sup) also have "x \ \ \ (\X\A. x \# X)" by simp finally show ?thesis . qed lemma in_Sup_multisetD: assumes "x \# Sup A" shows "\X\A. x \# X" proof - have "subset_mset.bdd_above A" by (rule ccontr) (insert assms, simp_all add: Sup_multiset_unbounded) with assms show ?thesis by (simp add: in_Sup_multiset_iff) qed interpretation subset_mset: distrib_lattice "(\#)" "(\#)" "(\#)" "(\#)" proof fix A B C :: "'a multiset" show "A \# (B \# C) = A \# B \# (A \# C)" by (intro multiset_eqI) simp_all qed \ \FIXME: avoid junk stemming from type class interpretation\ subsubsection \Filter (with comprehension syntax)\ text \Multiset comprehension\ lift_definition filter_mset :: "('a \ bool) \ 'a multiset \ 'a multiset" is "\P M. \x. if P x then M x else 0" by (rule filter_preserves_multiset) syntax (ASCII) "_MCollect" :: "pttrn \ 'a multiset \ bool \ 'a multiset" ("(1{#_ :# _./ _#})") syntax "_MCollect" :: "pttrn \ 'a multiset \ bool \ 'a multiset" ("(1{#_ \# _./ _#})") translations "{#x \# M. P#}" == "CONST filter_mset (\x. P) M" lemma count_filter_mset [simp]: "count (filter_mset P M) a = (if P a then count M a else 0)" by (simp add: filter_mset.rep_eq) lemma set_mset_filter [simp]: "set_mset (filter_mset P M) = {a \ set_mset M. P a}" by (simp only: set_eq_iff count_greater_zero_iff [symmetric] count_filter_mset) simp lemma filter_empty_mset [simp]: "filter_mset P {#} = {#}" by (rule multiset_eqI) simp lemma filter_single_mset: "filter_mset P {#x#} = (if P x then {#x#} else {#})" by (rule multiset_eqI) simp lemma filter_union_mset [simp]: "filter_mset P (M + N) = filter_mset P M + filter_mset P N" by (rule multiset_eqI) simp lemma filter_diff_mset [simp]: "filter_mset P (M - N) = filter_mset P M - filter_mset P N" by (rule multiset_eqI) simp lemma filter_inter_mset [simp]: "filter_mset P (M \# N) = filter_mset P M \# filter_mset P N" by (rule multiset_eqI) simp lemma filter_sup_mset[simp]: "filter_mset P (A \# B) = filter_mset P A \# filter_mset P B" by (rule multiset_eqI) simp lemma filter_mset_add_mset [simp]: "filter_mset P (add_mset x A) = (if P x then add_mset x (filter_mset P A) else filter_mset P A)" by (auto simp: multiset_eq_iff) lemma multiset_filter_subset[simp]: "filter_mset f M \# M" by (simp add: mset_subset_eqI) lemma multiset_filter_mono: assumes "A \# B" shows "filter_mset f A \# filter_mset f B" proof - from assms[unfolded mset_subset_eq_exists_conv] obtain C where B: "B = A + C" by auto show ?thesis unfolding B by auto qed lemma filter_mset_eq_conv: "filter_mset P M = N \ N \# M \ (\b\#N. P b) \ (\a\#M - N. \ P a)" (is "?P \ ?Q") proof assume ?P then show ?Q by auto (simp add: multiset_eq_iff in_diff_count) next assume ?Q then obtain Q where M: "M = N + Q" by (auto simp add: mset_subset_eq_exists_conv) then have MN: "M - N = Q" by simp show ?P proof (rule multiset_eqI) fix a from \?Q\ MN have *: "\ P a \ a \# N" "P a \ a \# Q" by auto show "count (filter_mset P M) a = count N a" proof (cases "a \# M") case True with * show ?thesis by (simp add: not_in_iff M) next case False then have "count M a = 0" by (simp add: not_in_iff) with M show ?thesis by simp qed qed qed lemma filter_filter_mset: "filter_mset P (filter_mset Q M) = {#x \# M. Q x \ P x#}" by (auto simp: multiset_eq_iff) lemma filter_mset_True[simp]: "{#y \# M. True#} = M" and filter_mset_False[simp]: "{#y \# M. False#} = {#}" by (auto simp: multiset_eq_iff) subsubsection \Size\ definition wcount where "wcount f M = (\x. count M x * Suc (f x))" lemma wcount_union: "wcount f (M + N) a = wcount f M a + wcount f N a" by (auto simp: wcount_def add_mult_distrib) lemma wcount_add_mset: "wcount f (add_mset x M) a = (if x = a then Suc (f a) else 0) + wcount f M a" unfolding add_mset_add_single[of _ M] wcount_union by (auto simp: wcount_def) definition size_multiset :: "('a \ nat) \ 'a multiset \ nat" where "size_multiset f M = sum (wcount f M) (set_mset M)" lemmas size_multiset_eq = size_multiset_def[unfolded wcount_def] instantiation multiset :: (type) size begin definition size_multiset where size_multiset_overloaded_def: "size_multiset = Multiset.size_multiset (\_. 0)" instance .. end lemmas size_multiset_overloaded_eq = size_multiset_overloaded_def[THEN fun_cong, unfolded size_multiset_eq, simplified] lemma size_multiset_empty [simp]: "size_multiset f {#} = 0" by (simp add: size_multiset_def) lemma size_empty [simp]: "size {#} = 0" by (simp add: size_multiset_overloaded_def) lemma size_multiset_single : "size_multiset f {#b#} = Suc (f b)" by (simp add: size_multiset_eq) lemma size_single: "size {#b#} = 1" by (simp add: size_multiset_overloaded_def size_multiset_single) lemma sum_wcount_Int: "finite A \ sum (wcount f N) (A \ set_mset N) = sum (wcount f N) A" by (induct rule: finite_induct) (simp_all add: Int_insert_left wcount_def count_eq_zero_iff) lemma size_multiset_union [simp]: "size_multiset f (M + N::'a multiset) = size_multiset f M + size_multiset f N" apply (simp add: size_multiset_def sum_Un_nat sum.distrib sum_wcount_Int wcount_union) apply (subst Int_commute) apply (simp add: sum_wcount_Int) done lemma size_multiset_add_mset [simp]: "size_multiset f (add_mset a M) = Suc (f a) + size_multiset f M" unfolding add_mset_add_single[of _ M] size_multiset_union by (auto simp: size_multiset_single) lemma size_add_mset [simp]: "size (add_mset a A) = Suc (size A)" by (simp add: size_multiset_overloaded_def wcount_add_mset) lemma size_union [simp]: "size (M + N::'a multiset) = size M + size N" by (auto simp add: size_multiset_overloaded_def) lemma size_multiset_eq_0_iff_empty [iff]: "size_multiset f M = 0 \ M = {#}" by (auto simp add: size_multiset_eq count_eq_zero_iff) lemma size_eq_0_iff_empty [iff]: "(size M = 0) = (M = {#})" by (auto simp add: size_multiset_overloaded_def) lemma nonempty_has_size: "(S \ {#}) = (0 < size S)" by (metis gr0I gr_implies_not0 size_empty size_eq_0_iff_empty) lemma size_eq_Suc_imp_elem: "size M = Suc n \ \a. a \# M" apply (unfold size_multiset_overloaded_eq) apply (drule sum_SucD) apply auto done lemma size_eq_Suc_imp_eq_union: assumes "size M = Suc n" shows "\a N. M = add_mset a N" proof - from assms obtain a where "a \# M" by (erule size_eq_Suc_imp_elem [THEN exE]) then have "M = add_mset a (M - {#a#})" by simp then show ?thesis by blast qed lemma size_mset_mono: fixes A B :: "'a multiset" assumes "A \# B" shows "size A \ size B" proof - from assms[unfolded mset_subset_eq_exists_conv] obtain C where B: "B = A + C" by auto show ?thesis unfolding B by (induct C) auto qed lemma size_filter_mset_lesseq[simp]: "size (filter_mset f M) \ size M" by (rule size_mset_mono[OF multiset_filter_subset]) lemma size_Diff_submset: "M \# M' \ size (M' - M) = size M' - size(M::'a multiset)" by (metis add_diff_cancel_left' size_union mset_subset_eq_exists_conv) subsection \Induction and case splits\ theorem multiset_induct [case_names empty add, induct type: multiset]: assumes empty: "P {#}" assumes add: "\x M. P M \ P (add_mset x M)" shows "P M" proof (induct "size M" arbitrary: M) case 0 thus "P M" by (simp add: empty) next case (Suc k) obtain N x where "M = add_mset x N" using \Suc k = size M\ [symmetric] using size_eq_Suc_imp_eq_union by fast with Suc add show "P M" by simp qed lemma multiset_induct_min[case_names empty add]: fixes M :: "'a::linorder multiset" assumes empty: "P {#}" and add: "\x M. P M \ (\y \# M. y \ x) \ P (add_mset x M)" shows "P M" proof (induct "size M" arbitrary: M) case (Suc k) note ih = this(1) and Sk_eq_sz_M = this(2) let ?y = "Min_mset M" let ?N = "M - {#?y#}" have M: "M = add_mset ?y ?N" by (metis Min_in Sk_eq_sz_M finite_set_mset insert_DiffM lessI not_less_zero set_mset_eq_empty_iff size_empty) show ?case by (subst M, rule add, rule ih, metis M Sk_eq_sz_M nat.inject size_add_mset, meson Min_le finite_set_mset in_diffD) qed (simp add: empty) lemma multiset_induct_max[case_names empty add]: fixes M :: "'a::linorder multiset" assumes empty: "P {#}" and add: "\x M. P M \ (\y \# M. y \ x) \ P (add_mset x M)" shows "P M" proof (induct "size M" arbitrary: M) case (Suc k) note ih = this(1) and Sk_eq_sz_M = this(2) let ?y = "Max_mset M" let ?N = "M - {#?y#}" have M: "M = add_mset ?y ?N" by (metis Max_in Sk_eq_sz_M finite_set_mset insert_DiffM lessI not_less_zero set_mset_eq_empty_iff size_empty) show ?case by (subst M, rule add, rule ih, metis M Sk_eq_sz_M nat.inject size_add_mset, meson Max_ge finite_set_mset in_diffD) qed (simp add: empty) lemma multi_nonempty_split: "M \ {#} \ \A a. M = add_mset a A" by (induct M) auto lemma multiset_cases [cases type]: obtains (empty) "M = {#}" | (add) x N where "M = add_mset x N" by (induct M) simp_all lemma multi_drop_mem_not_eq: "c \# B \ B - {#c#} \ B" by (cases "B = {#}") (auto dest: multi_member_split) lemma union_filter_mset_complement[simp]: "\x. P x = (\ Q x) \ filter_mset P M + filter_mset Q M = M" by (subst multiset_eq_iff) auto lemma multiset_partition: "M = {#x \# M. P x#} + {#x \# M. \ P x#}" by simp lemma mset_subset_size: "A \# B \ size A < size B" proof (induct A arbitrary: B) case empty then show ?case using nonempty_has_size by auto next case (add x A) have "add_mset x A \# B" by (meson add.prems subset_mset_def) then show ?case by (metis (no_types) add.prems add.right_neutral add_diff_cancel_left' leD nat_neq_iff size_Diff_submset size_eq_0_iff_empty size_mset_mono subset_mset.le_iff_add subset_mset_def) qed lemma size_1_singleton_mset: "size M = 1 \ \a. M = {#a#}" by (cases M) auto subsubsection \Strong induction and subset induction for multisets\ text \Well-foundedness of strict subset relation\ lemma wf_subset_mset_rel: "wf {(M, N :: 'a multiset). M \# N}" apply (rule wf_measure [THEN wf_subset, where f1=size]) apply (clarsimp simp: measure_def inv_image_def mset_subset_size) done lemma full_multiset_induct [case_names less]: assumes ih: "\B. \(A::'a multiset). A \# B \ P A \ P B" shows "P B" apply (rule wf_subset_mset_rel [THEN wf_induct]) apply (rule ih, auto) done lemma multi_subset_induct [consumes 2, case_names empty add]: assumes "F \# A" and empty: "P {#}" and insert: "\a F. a \# A \ P F \ P (add_mset a F)" shows "P F" proof - from \F \# A\ show ?thesis proof (induct F) show "P {#}" by fact next fix x F assume P: "F \# A \ P F" and i: "add_mset x F \# A" show "P (add_mset x F)" proof (rule insert) from i show "x \# A" by (auto dest: mset_subset_eq_insertD) from i have "F \# A" by (auto dest: mset_subset_eq_insertD) with P show "P F" . qed qed qed subsection \The fold combinator\ definition fold_mset :: "('a \ 'b \ 'b) \ 'b \ 'a multiset \ 'b" where "fold_mset f s M = Finite_Set.fold (\x. f x ^^ count M x) s (set_mset M)" lemma fold_mset_empty [simp]: "fold_mset f s {#} = s" by (simp add: fold_mset_def) context comp_fun_commute begin lemma fold_mset_add_mset [simp]: "fold_mset f s (add_mset x M) = f x (fold_mset f s M)" proof - interpret mset: comp_fun_commute "\y. f y ^^ count M y" by (fact comp_fun_commute_funpow) interpret mset_union: comp_fun_commute "\y. f y ^^ count (add_mset x M) y" by (fact comp_fun_commute_funpow) show ?thesis proof (cases "x \ set_mset M") case False then have *: "count (add_mset x M) x = 1" by (simp add: not_in_iff) from False have "Finite_Set.fold (\y. f y ^^ count (add_mset x M) y) s (set_mset M) = Finite_Set.fold (\y. f y ^^ count M y) s (set_mset M)" - by (auto intro!: Finite_Set.fold_cong comp_fun_commute_funpow) + by (auto intro!: Finite_Set.fold_cong comp_fun_commute_on_funpow) with False * show ?thesis by (simp add: fold_mset_def del: count_add_mset) next case True define N where "N = set_mset M - {x}" from N_def True have *: "set_mset M = insert x N" "x \ N" "finite N" by auto then have "Finite_Set.fold (\y. f y ^^ count (add_mset x M) y) s N = Finite_Set.fold (\y. f y ^^ count M y) s N" - by (auto intro!: Finite_Set.fold_cong comp_fun_commute_funpow) + by (auto intro!: Finite_Set.fold_cong comp_fun_commute_on_funpow) with * show ?thesis by (simp add: fold_mset_def del: count_add_mset) simp qed qed corollary fold_mset_single: "fold_mset f s {#x#} = f x s" by simp lemma fold_mset_fun_left_comm: "f x (fold_mset f s M) = fold_mset f (f x s) M" by (induct M) (simp_all add: fun_left_comm) lemma fold_mset_union [simp]: "fold_mset f s (M + N) = fold_mset f (fold_mset f s M) N" by (induct M) (simp_all add: fold_mset_fun_left_comm) lemma fold_mset_fusion: assumes "comp_fun_commute g" and *: "\x y. h (g x y) = f x (h y)" shows "h (fold_mset g w A) = fold_mset f (h w) A" proof - interpret comp_fun_commute g by (fact assms) from * show ?thesis by (induct A) auto qed end lemma union_fold_mset_add_mset: "A + B = fold_mset add_mset A B" proof - interpret comp_fun_commute add_mset by standard auto show ?thesis by (induction B) auto qed text \ A note on code generation: When defining some function containing a subterm \<^term>\fold_mset F\, code generation is not automatic. When interpreting locale \left_commutative\ with \F\, the would be code thms for \<^const>\fold_mset\ become thms like \<^term>\fold_mset F z {#} = z\ where \F\ is not a pattern but contains defined symbols, i.e.\ is not a code thm. Hence a separate constant with its own code thms needs to be introduced for \F\. See the image operator below. \ subsection \Image\ definition image_mset :: "('a \ 'b) \ 'a multiset \ 'b multiset" where "image_mset f = fold_mset (add_mset \ f) {#}" lemma comp_fun_commute_mset_image: "comp_fun_commute (add_mset \ f)" by unfold_locales (simp add: fun_eq_iff) lemma image_mset_empty [simp]: "image_mset f {#} = {#}" by (simp add: image_mset_def) lemma image_mset_single: "image_mset f {#x#} = {#f x#}" by (simp add: comp_fun_commute.fold_mset_add_mset comp_fun_commute_mset_image image_mset_def) lemma image_mset_union [simp]: "image_mset f (M + N) = image_mset f M + image_mset f N" proof - interpret comp_fun_commute "add_mset \ f" by (fact comp_fun_commute_mset_image) show ?thesis by (induct N) (simp_all add: image_mset_def) qed corollary image_mset_add_mset [simp]: "image_mset f (add_mset a M) = add_mset (f a) (image_mset f M)" unfolding image_mset_union add_mset_add_single[of a M] by (simp add: image_mset_single) lemma set_image_mset [simp]: "set_mset (image_mset f M) = image f (set_mset M)" by (induct M) simp_all lemma size_image_mset [simp]: "size (image_mset f M) = size M" by (induct M) simp_all lemma image_mset_is_empty_iff [simp]: "image_mset f M = {#} \ M = {#}" by (cases M) auto lemma image_mset_If: "image_mset (\x. if P x then f x else g x) A = image_mset f (filter_mset P A) + image_mset g (filter_mset (\x. \P x) A)" by (induction A) auto lemma image_mset_Diff: assumes "B \# A" shows "image_mset f (A - B) = image_mset f A - image_mset f B" proof - have "image_mset f (A - B + B) = image_mset f (A - B) + image_mset f B" by simp also from assms have "A - B + B = A" by (simp add: subset_mset.diff_add) finally show ?thesis by simp qed lemma count_image_mset: \count (image_mset f A) x = (\y\f -` {x} \ set_mset A. count A y)\ proof (induction A) case empty then show ?case by simp next case (add x A) moreover have *: "(if x = y then Suc n else n) = n + (if x = y then 1 else 0)" for n y by simp ultimately show ?case by (auto simp: sum.distrib intro!: sum.mono_neutral_left) qed lemma count_image_mset': \count (image_mset f X) y = (\x | x \# X \ y = f x. count X x)\ by (auto simp add: count_image_mset simp flip: singleton_conv2 simp add: Collect_conj_eq ac_simps) lemma image_mset_subseteq_mono: "A \# B \ image_mset f A \# image_mset f B" by (metis image_mset_union subset_mset.le_iff_add) lemma image_mset_subset_mono: "M \# N \ image_mset f M \# image_mset f N" by (metis (no_types) Diff_eq_empty_iff_mset image_mset_Diff image_mset_is_empty_iff image_mset_subseteq_mono subset_mset.less_le_not_le) syntax (ASCII) "_comprehension_mset" :: "'a \ 'b \ 'b multiset \ 'a multiset" ("({#_/. _ :# _#})") syntax "_comprehension_mset" :: "'a \ 'b \ 'b multiset \ 'a multiset" ("({#_/. _ \# _#})") translations "{#e. x \# M#}" \ "CONST image_mset (\x. e) M" syntax (ASCII) "_comprehension_mset'" :: "'a \ 'b \ 'b multiset \ bool \ 'a multiset" ("({#_/ | _ :# _./ _#})") syntax "_comprehension_mset'" :: "'a \ 'b \ 'b multiset \ bool \ 'a multiset" ("({#_/ | _ \# _./ _#})") translations "{#e | x\#M. P#}" \ "{#e. x \# {# x\#M. P#}#}" text \ This allows to write not just filters like \<^term>\{#x\#M. x but also images like \<^term>\{#x+x. x\#M #}\ and @{term [source] "{#x+x|x\#M. x\{#x+x|x\#M. x. \ lemma in_image_mset: "y \# {#f x. x \# M#} \ y \ f ` set_mset M" by simp functor image_mset: image_mset proof - fix f g show "image_mset f \ image_mset g = image_mset (f \ g)" proof fix A show "(image_mset f \ image_mset g) A = image_mset (f \ g) A" by (induct A) simp_all qed show "image_mset id = id" proof fix A show "image_mset id A = id A" by (induct A) simp_all qed qed declare image_mset.id [simp] image_mset.identity [simp] lemma image_mset_id[simp]: "image_mset id x = x" unfolding id_def by auto lemma image_mset_cong: "(\x. x \# M \ f x = g x) \ {#f x. x \# M#} = {#g x. x \# M#}" by (induct M) auto lemma image_mset_cong_pair: "(\x y. (x, y) \# M \ f x y = g x y) \ {#f x y. (x, y) \# M#} = {#g x y. (x, y) \# M#}" by (metis image_mset_cong split_cong) lemma image_mset_const_eq: "{#c. a \# M#} = replicate_mset (size M) c" by (induct M) simp_all subsection \Further conversions\ primrec mset :: "'a list \ 'a multiset" where "mset [] = {#}" | "mset (a # x) = add_mset a (mset x)" lemma in_multiset_in_set: "x \# mset xs \ x \ set xs" by (induct xs) simp_all lemma count_mset: "count (mset xs) x = length (filter (\y. x = y) xs)" by (induct xs) simp_all lemma mset_zero_iff[simp]: "(mset x = {#}) = (x = [])" by (induct x) auto lemma mset_zero_iff_right[simp]: "({#} = mset x) = (x = [])" by (induct x) auto lemma count_mset_gt_0: "x \ set xs \ count (mset xs) x > 0" by (induction xs) auto lemma count_mset_0_iff [simp]: "count (mset xs) x = 0 \ x \ set xs" by (induction xs) auto lemma mset_single_iff[iff]: "mset xs = {#x#} \ xs = [x]" by (cases xs) auto lemma mset_single_iff_right[iff]: "{#x#} = mset xs \ xs = [x]" by (cases xs) auto lemma set_mset_mset[simp]: "set_mset (mset xs) = set xs" by (induct xs) auto lemma set_mset_comp_mset [simp]: "set_mset \ mset = set" by (simp add: fun_eq_iff) lemma size_mset [simp]: "size (mset xs) = length xs" by (induct xs) simp_all lemma mset_append [simp]: "mset (xs @ ys) = mset xs + mset ys" by (induct xs arbitrary: ys) auto lemma mset_filter[simp]: "mset (filter P xs) = {#x \# mset xs. P x #}" by (induct xs) simp_all lemma mset_rev [simp]: "mset (rev xs) = mset xs" by (induct xs) simp_all lemma surj_mset: "surj mset" apply (unfold surj_def) apply (rule allI) apply (rule_tac M = y in multiset_induct) apply auto apply (rule_tac x = "x # xa" in exI) apply auto done lemma distinct_count_atmost_1: "distinct x = (\a. count (mset x) a = (if a \ set x then 1 else 0))" proof (induct x) case Nil then show ?case by simp next case (Cons x xs) show ?case (is "?lhs \ ?rhs") proof assume ?lhs then show ?rhs using Cons by simp next assume ?rhs then have "x \ set xs" by (simp split: if_splits) moreover from \?rhs\ have "(\a. count (mset xs) a = (if a \ set xs then 1 else 0))" by (auto split: if_splits simp add: count_eq_zero_iff) ultimately show ?lhs using Cons by simp qed qed lemma mset_eq_setD: assumes "mset xs = mset ys" shows "set xs = set ys" proof - from assms have "set_mset (mset xs) = set_mset (mset ys)" by simp then show ?thesis by simp qed lemma set_eq_iff_mset_eq_distinct: \distinct x \ distinct y \ set x = set y \ mset x = mset y\ by (auto simp: multiset_eq_iff distinct_count_atmost_1) lemma set_eq_iff_mset_remdups_eq: \set x = set y \ mset (remdups x) = mset (remdups y)\ apply (rule iffI) apply (simp add: set_eq_iff_mset_eq_distinct[THEN iffD1]) apply (drule distinct_remdups [THEN distinct_remdups [THEN set_eq_iff_mset_eq_distinct [THEN iffD2]]]) apply simp done lemma mset_eq_imp_distinct_iff: \distinct xs \ distinct ys\ if \mset xs = mset ys\ using that by (auto simp add: distinct_count_atmost_1 dest: mset_eq_setD) lemma nth_mem_mset: "i < length ls \ (ls ! i) \# mset ls" proof (induct ls arbitrary: i) case Nil then show ?case by simp next case Cons then show ?case by (cases i) auto qed lemma mset_remove1[simp]: "mset (remove1 a xs) = mset xs - {#a#}" by (induct xs) (auto simp add: multiset_eq_iff) lemma mset_eq_length: assumes "mset xs = mset ys" shows "length xs = length ys" using assms by (metis size_mset) lemma mset_eq_length_filter: assumes "mset xs = mset ys" shows "length (filter (\x. z = x) xs) = length (filter (\y. z = y) ys)" using assms by (metis count_mset) lemma fold_multiset_equiv: \List.fold f xs = List.fold f ys\ if f: \\x y. x \ set xs \ y \ set xs \ f x \ f y = f y \ f x\ and \mset xs = mset ys\ using f \mset xs = mset ys\ [symmetric] proof (induction xs arbitrary: ys) case Nil then show ?case by simp next case (Cons x xs) then have *: \set ys = set (x # xs)\ by (blast dest: mset_eq_setD) have \\x y. x \ set ys \ y \ set ys \ f x \ f y = f y \ f x\ by (rule Cons.prems(1)) (simp_all add: *) moreover from * have \x \ set ys\ by simp ultimately have \List.fold f ys = List.fold f (remove1 x ys) \ f x\ by (fact fold_remove1_split) moreover from Cons.prems have \List.fold f xs = List.fold f (remove1 x ys)\ by (auto intro: Cons.IH) ultimately show ?case by simp qed lemma fold_permuted_eq: \List.fold (\) xs z = List.fold (\) ys z\ if \mset xs = mset ys\ and \P z\ and P: \\x z. x \ set xs \ P z \ P (x \ z)\ and f: \\x y z. x \ set xs \ y \ set xs \ P z \ x \ (y \ z) = y \ (x \ z)\ for f (infixl \\\ 70) using \P z\ P f \mset xs = mset ys\ [symmetric] proof (induction xs arbitrary: ys z) case Nil then show ?case by simp next case (Cons x xs) then have *: \set ys = set (x # xs)\ by (blast dest: mset_eq_setD) have \P z\ by (fact Cons.prems(1)) moreover have \\x z. x \ set ys \ P z \ P (x \ z)\ by (rule Cons.prems(2)) (simp_all add: *) moreover have \\x y z. x \ set ys \ y \ set ys \ P z \ x \ (y \ z) = y \ (x \ z)\ by (rule Cons.prems(3)) (simp_all add: *) moreover from * have \x \ set ys\ by simp ultimately have \fold (\) ys z = fold (\) (remove1 x ys) (x \ z)\ by (induction ys arbitrary: z) auto moreover from Cons.prems have \fold (\) xs (x \ z) = fold (\) (remove1 x ys) (x \ z)\ by (auto intro: Cons.IH) ultimately show ?case by simp qed lemma mset_shuffles: "zs \ shuffles xs ys \ mset zs = mset xs + mset ys" by (induction xs ys arbitrary: zs rule: shuffles.induct) auto lemma mset_insort [simp]: "mset (insort x xs) = add_mset x (mset xs)" by (induct xs) simp_all lemma mset_map[simp]: "mset (map f xs) = image_mset f (mset xs)" by (induct xs) simp_all global_interpretation mset_set: folding add_mset "{#}" - defines mset_set = "folding.F add_mset {#}" + defines mset_set = "folding_on.F add_mset {#}" by standard (simp add: fun_eq_iff) lemma sum_multiset_singleton [simp]: "sum (\n. {#n#}) A = mset_set A" by (induction A rule: infinite_finite_induct) auto lemma count_mset_set [simp]: "finite A \ x \ A \ count (mset_set A) x = 1" (is "PROP ?P") "\ finite A \ count (mset_set A) x = 0" (is "PROP ?Q") "x \ A \ count (mset_set A) x = 0" (is "PROP ?R") proof - have *: "count (mset_set A) x = 0" if "x \ A" for A proof (cases "finite A") case False then show ?thesis by simp next case True from True \x \ A\ show ?thesis by (induct A) auto qed then show "PROP ?P" "PROP ?Q" "PROP ?R" by (auto elim!: Set.set_insert) qed \ \TODO: maybe define \<^const>\mset_set\ also in terms of \<^const>\Abs_multiset\\ lemma elem_mset_set[simp, intro]: "finite A \ x \# mset_set A \ x \ A" by (induct A rule: finite_induct) simp_all lemma mset_set_Union: "finite A \ finite B \ A \ B = {} \ mset_set (A \ B) = mset_set A + mset_set B" by (induction A rule: finite_induct) auto lemma filter_mset_mset_set [simp]: "finite A \ filter_mset P (mset_set A) = mset_set {x\A. P x}" proof (induction A rule: finite_induct) case (insert x A) from insert.hyps have "filter_mset P (mset_set (insert x A)) = filter_mset P (mset_set A) + mset_set (if P x then {x} else {})" by simp also have "filter_mset P (mset_set A) = mset_set {x\A. P x}" by (rule insert.IH) also from insert.hyps have "\ + mset_set (if P x then {x} else {}) = mset_set ({x \ A. P x} \ (if P x then {x} else {}))" (is "_ = mset_set ?A") by (intro mset_set_Union [symmetric]) simp_all also from insert.hyps have "?A = {y\insert x A. P y}" by auto finally show ?case . qed simp_all lemma mset_set_Diff: assumes "finite A" "B \ A" shows "mset_set (A - B) = mset_set A - mset_set B" proof - from assms have "mset_set ((A - B) \ B) = mset_set (A - B) + mset_set B" by (intro mset_set_Union) (auto dest: finite_subset) also from assms have "A - B \ B = A" by blast finally show ?thesis by simp qed lemma mset_set_set: "distinct xs \ mset_set (set xs) = mset xs" by (induction xs) simp_all lemma count_mset_set': "count (mset_set A) x = (if finite A \ x \ A then 1 else 0)" by auto lemma subset_imp_msubset_mset_set: assumes "A \ B" "finite B" shows "mset_set A \# mset_set B" proof (rule mset_subset_eqI) fix x :: 'a from assms have "finite A" by (rule finite_subset) with assms show "count (mset_set A) x \ count (mset_set B) x" by (cases "x \ A"; cases "x \ B") auto qed lemma mset_set_set_mset_msubset: "mset_set (set_mset A) \# A" proof (rule mset_subset_eqI) fix x show "count (mset_set (set_mset A)) x \ count A x" by (cases "x \# A") simp_all qed lemma mset_set_upto_eq_mset_upto: \mset_set {.. by (induction n) (auto simp: ac_simps lessThan_Suc) context linorder begin definition sorted_list_of_multiset :: "'a multiset \ 'a list" where "sorted_list_of_multiset M = fold_mset insort [] M" lemma sorted_list_of_multiset_empty [simp]: "sorted_list_of_multiset {#} = []" by (simp add: sorted_list_of_multiset_def) lemma sorted_list_of_multiset_singleton [simp]: "sorted_list_of_multiset {#x#} = [x]" proof - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) show ?thesis by (simp add: sorted_list_of_multiset_def) qed lemma sorted_list_of_multiset_insert [simp]: "sorted_list_of_multiset (add_mset x M) = List.insort x (sorted_list_of_multiset M)" proof - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) show ?thesis by (simp add: sorted_list_of_multiset_def) qed end lemma mset_sorted_list_of_multiset[simp]: "mset (sorted_list_of_multiset M) = M" by (induct M) simp_all lemma sorted_list_of_multiset_mset[simp]: "sorted_list_of_multiset (mset xs) = sort xs" by (induct xs) simp_all lemma finite_set_mset_mset_set[simp]: "finite A \ set_mset (mset_set A) = A" by auto lemma mset_set_empty_iff: "mset_set A = {#} \ A = {} \ infinite A" using finite_set_mset_mset_set by fastforce lemma infinite_set_mset_mset_set: "\ finite A \ set_mset (mset_set A) = {}" by simp lemma set_sorted_list_of_multiset [simp]: "set (sorted_list_of_multiset M) = set_mset M" by (induct M) (simp_all add: set_insort_key) lemma sorted_list_of_mset_set [simp]: "sorted_list_of_multiset (mset_set A) = sorted_list_of_set A" by (cases "finite A") (induct A rule: finite_induct, simp_all) lemma mset_upt [simp]: "mset [m.. {#the (map_of xs i). i \# mset (map fst xs)#} = mset (map snd xs)" proof (induction xs) case (Cons x xs) have "{#the (map_of (x # xs) i). i \# mset (map fst (x # xs))#} = add_mset (snd x) {#the (if i = fst x then Some (snd x) else map_of xs i). i \# mset (map fst xs)#}" (is "_ = add_mset _ ?A") by simp also from Cons.prems have "?A = {#the (map_of xs i). i :# mset (map fst xs)#}" by (cases x, intro image_mset_cong) (auto simp: in_multiset_in_set) also from Cons.prems have "\ = mset (map snd xs)" by (intro Cons.IH) simp_all finally show ?case by simp qed simp_all lemma msubset_mset_set_iff[simp]: assumes "finite A" "finite B" shows "mset_set A \# mset_set B \ A \ B" using assms set_mset_mono subset_imp_msubset_mset_set by fastforce lemma mset_set_eq_iff[simp]: assumes "finite A" "finite B" shows "mset_set A = mset_set B \ A = B" using assms by (fastforce dest: finite_set_mset_mset_set) lemma image_mset_mset_set: \<^marker>\contributor \Lukas Bulwahn\\ assumes "inj_on f A" shows "image_mset f (mset_set A) = mset_set (f ` A)" proof cases assume "finite A" from this \inj_on f A\ show ?thesis by (induct A) auto next assume "infinite A" from this \inj_on f A\ have "infinite (f ` A)" using finite_imageD by blast from \infinite A\ \infinite (f ` A)\ show ?thesis by simp qed subsection \More properties of the replicate and repeat operations\ lemma in_replicate_mset[simp]: "x \# replicate_mset n y \ n > 0 \ x = y" unfolding replicate_mset_def by (induct n) auto lemma set_mset_replicate_mset_subset[simp]: "set_mset (replicate_mset n x) = (if n = 0 then {} else {x})" by (auto split: if_splits) lemma size_replicate_mset[simp]: "size (replicate_mset n M) = n" by (induct n, simp_all) lemma count_le_replicate_mset_subset_eq: "n \ count M x \ replicate_mset n x \# M" by (auto simp add: mset_subset_eqI) (metis count_replicate_mset subseteq_mset_def) lemma filter_eq_replicate_mset: "{#y \# D. y = x#} = replicate_mset (count D x) x" by (induct D) simp_all lemma replicate_count_mset_eq_filter_eq: "replicate (count (mset xs) k) k = filter (HOL.eq k) xs" by (induct xs) auto lemma replicate_mset_eq_empty_iff [simp]: "replicate_mset n a = {#} \ n = 0" by (induct n) simp_all lemma replicate_mset_eq_iff: "replicate_mset m a = replicate_mset n b \ m = 0 \ n = 0 \ m = n \ a = b" by (auto simp add: multiset_eq_iff) lemma repeat_mset_cancel1: "repeat_mset a A = repeat_mset a B \ A = B \ a = 0" by (auto simp: multiset_eq_iff) lemma repeat_mset_cancel2: "repeat_mset a A = repeat_mset b A \ a = b \ A = {#}" by (auto simp: multiset_eq_iff) lemma repeat_mset_eq_empty_iff: "repeat_mset n A = {#} \ n = 0 \ A = {#}" by (cases n) auto lemma image_replicate_mset [simp]: "image_mset f (replicate_mset n a) = replicate_mset n (f a)" by (induct n) simp_all lemma replicate_mset_msubseteq_iff: "replicate_mset m a \# replicate_mset n b \ m = 0 \ a = b \ m \ n" by (cases m) (auto simp: insert_subset_eq_iff simp flip: count_le_replicate_mset_subset_eq) lemma msubseteq_replicate_msetE: assumes "A \# replicate_mset n a" obtains m where "m \ n" and "A = replicate_mset m a" proof (cases "n = 0") case True with assms that show thesis by simp next case False from assms have "set_mset A \ set_mset (replicate_mset n a)" by (rule set_mset_mono) with False have "set_mset A \ {a}" by simp then have "\m. A = replicate_mset m a" proof (induction A) case empty then show ?case by simp next case (add b A) then obtain m where "A = replicate_mset m a" by auto with add.prems show ?case by (auto intro: exI [of _ "Suc m"]) qed then obtain m where A: "A = replicate_mset m a" .. with assms have "m \ n" by (auto simp add: replicate_mset_msubseteq_iff) then show thesis using A .. qed subsection \Big operators\ locale comm_monoid_mset = comm_monoid begin interpretation comp_fun_commute f by standard (simp add: fun_eq_iff left_commute) interpretation comp?: comp_fun_commute "f \ g" by (fact comp_comp_fun_commute) context begin definition F :: "'a multiset \ 'a" where eq_fold: "F M = fold_mset f \<^bold>1 M" lemma empty [simp]: "F {#} = \<^bold>1" by (simp add: eq_fold) lemma singleton [simp]: "F {#x#} = x" proof - interpret comp_fun_commute by standard (simp add: fun_eq_iff left_commute) show ?thesis by (simp add: eq_fold) qed lemma union [simp]: "F (M + N) = F M \<^bold>* F N" proof - interpret comp_fun_commute f by standard (simp add: fun_eq_iff left_commute) show ?thesis by (induct N) (simp_all add: left_commute eq_fold) qed lemma add_mset [simp]: "F (add_mset x N) = x \<^bold>* F N" unfolding add_mset_add_single[of x N] union by (simp add: ac_simps) lemma insert [simp]: shows "F (image_mset g (add_mset x A)) = g x \<^bold>* F (image_mset g A)" by (simp add: eq_fold) lemma remove: assumes "x \# A" shows "F A = x \<^bold>* F (A - {#x#})" using multi_member_split[OF assms] by auto lemma neutral: "\x\#A. x = \<^bold>1 \ F A = \<^bold>1" by (induct A) simp_all lemma neutral_const [simp]: "F (image_mset (\_. \<^bold>1) A) = \<^bold>1" by (simp add: neutral) private lemma F_image_mset_product: "F {#g x j \<^bold>* F {#g i j. i \# A#}. j \# B#} = F (image_mset (g x) B) \<^bold>* F {#F {#g i j. i \# A#}. j \# B#}" by (induction B) (simp_all add: left_commute semigroup.assoc semigroup_axioms) lemma swap: "F (image_mset (\i. F (image_mset (g i) B)) A) = F (image_mset (\j. F (image_mset (\i. g i j) A)) B)" apply (induction A, simp) apply (induction B, auto simp add: F_image_mset_product ac_simps) done lemma distrib: "F (image_mset (\x. g x \<^bold>* h x) A) = F (image_mset g A) \<^bold>* F (image_mset h A)" by (induction A) (auto simp: ac_simps) lemma union_disjoint: "A \# B = {#} \ F (image_mset g (A \# B)) = F (image_mset g A) \<^bold>* F (image_mset g B)" by (induction A) (auto simp: ac_simps) end end lemma comp_fun_commute_plus_mset[simp]: "comp_fun_commute ((+) :: 'a multiset \ _ \ _)" by standard (simp add: add_ac comp_def) declare comp_fun_commute.fold_mset_add_mset[OF comp_fun_commute_plus_mset, simp] lemma in_mset_fold_plus_iff[iff]: "x \# fold_mset (+) M NN \ x \# M \ (\N. N \# NN \ x \# N)" by (induct NN) auto context comm_monoid_add begin sublocale sum_mset: comm_monoid_mset plus 0 defines sum_mset = sum_mset.F .. lemma sum_unfold_sum_mset: "sum f A = sum_mset (image_mset f (mset_set A))" by (cases "finite A") (induct A rule: finite_induct, simp_all) end notation sum_mset ("\\<^sub>#") syntax (ASCII) "_sum_mset_image" :: "pttrn \ 'b set \ 'a \ 'a::comm_monoid_add" ("(3SUM _:#_. _)" [0, 51, 10] 10) syntax "_sum_mset_image" :: "pttrn \ 'b set \ 'a \ 'a::comm_monoid_add" ("(3\_\#_. _)" [0, 51, 10] 10) translations "\i \# A. b" \ "CONST sum_mset (CONST image_mset (\i. b) A)" context comm_monoid_add begin lemma sum_mset_sum_list: "sum_mset (mset xs) = sum_list xs" by (induction xs) auto end context canonically_ordered_monoid_add begin lemma sum_mset_0_iff [simp]: "sum_mset M = 0 \ (\x \ set_mset M. x = 0)" by (induction M) auto end context ordered_comm_monoid_add begin lemma sum_mset_mono: "sum_mset (image_mset f K) \ sum_mset (image_mset g K)" if "\i. i \# K \ f i \ g i" using that by (induction K) (simp_all add: add_mono) end context cancel_comm_monoid_add begin lemma sum_mset_diff: "sum_mset (M - N) = sum_mset M - sum_mset N" if "N \# M" for M N :: "'a multiset" using that by (auto simp add: subset_mset.le_iff_add) end context semiring_0 begin lemma sum_mset_distrib_left: "c * (\x \# M. f x) = (\x \# M. c * f(x))" by (induction M) (simp_all add: algebra_simps) lemma sum_mset_distrib_right: "(\x \# M. f x) * c = (\x \# M. f x * c)" by (induction M) (simp_all add: algebra_simps) end lemma sum_mset_product: fixes f :: "'a::{comm_monoid_add,times} \ 'b::semiring_0" shows "(\i \# A. f i) * (\i \# B. g i) = (\i\#A. \j\#B. f i * g j)" by (subst sum_mset.swap) (simp add: sum_mset_distrib_left sum_mset_distrib_right) context semiring_1 begin lemma sum_mset_replicate_mset [simp]: "sum_mset (replicate_mset n a) = of_nat n * a" by (induction n) (simp_all add: algebra_simps) lemma sum_mset_delta: "sum_mset (image_mset (\x. if x = y then c else 0) A) = c * of_nat (count A y)" by (induction A) (simp_all add: algebra_simps) lemma sum_mset_delta': "sum_mset (image_mset (\x. if y = x then c else 0) A) = c * of_nat (count A y)" by (induction A) (simp_all add: algebra_simps) end lemma of_nat_sum_mset [simp]: "of_nat (sum_mset A) = sum_mset (image_mset of_nat A)" by (induction A) auto lemma size_eq_sum_mset: "size M = (\a\#M. 1)" using image_mset_const_eq [of "1::nat" M] by simp lemma size_mset_set [simp]: "size (mset_set A) = card A" by (simp only: size_eq_sum_mset card_eq_sum sum_unfold_sum_mset) lemma sum_mset_constant [simp]: fixes y :: "'b::semiring_1" shows \(\x\#A. y) = of_nat (size A) * y\ by (induction A) (auto simp: algebra_simps) lemma set_mset_Union_mset[simp]: "set_mset (\\<^sub># MM) = (\M \ set_mset MM. set_mset M)" by (induct MM) auto lemma in_Union_mset_iff[iff]: "x \# \\<^sub># MM \ (\M. M \# MM \ x \# M)" by (induct MM) auto lemma count_sum: "count (sum f A) x = sum (\a. count (f a) x) A" by (induct A rule: infinite_finite_induct) simp_all lemma sum_eq_empty_iff: assumes "finite A" shows "sum f A = {#} \ (\a\A. f a = {#})" using assms by induct simp_all lemma Union_mset_empty_conv[simp]: "\\<^sub># M = {#} \ (\i\#M. i = {#})" by (induction M) auto lemma Union_image_single_mset[simp]: "\\<^sub># (image_mset (\x. {#x#}) m) = m" by(induction m) auto context comm_monoid_mult begin sublocale prod_mset: comm_monoid_mset times 1 defines prod_mset = prod_mset.F .. lemma prod_mset_empty: "prod_mset {#} = 1" by (fact prod_mset.empty) lemma prod_mset_singleton: "prod_mset {#x#} = x" by (fact prod_mset.singleton) lemma prod_mset_Un: "prod_mset (A + B) = prod_mset A * prod_mset B" by (fact prod_mset.union) lemma prod_mset_prod_list: "prod_mset (mset xs) = prod_list xs" by (induct xs) auto lemma prod_mset_replicate_mset [simp]: "prod_mset (replicate_mset n a) = a ^ n" by (induct n) simp_all lemma prod_unfold_prod_mset: "prod f A = prod_mset (image_mset f (mset_set A))" by (cases "finite A") (induct A rule: finite_induct, simp_all) lemma prod_mset_multiplicity: "prod_mset M = prod (\x. x ^ count M x) (set_mset M)" by (simp add: fold_mset_def prod.eq_fold prod_mset.eq_fold funpow_times_power comp_def) lemma prod_mset_delta: "prod_mset (image_mset (\x. if x = y then c else 1) A) = c ^ count A y" by (induction A) simp_all lemma prod_mset_delta': "prod_mset (image_mset (\x. if y = x then c else 1) A) = c ^ count A y" by (induction A) simp_all lemma prod_mset_subset_imp_dvd: assumes "A \# B" shows "prod_mset A dvd prod_mset B" proof - from assms have "B = (B - A) + A" by (simp add: subset_mset.diff_add) also have "prod_mset \ = prod_mset (B - A) * prod_mset A" by simp also have "prod_mset A dvd \" by simp finally show ?thesis . qed lemma dvd_prod_mset: assumes "x \# A" shows "x dvd prod_mset A" using assms prod_mset_subset_imp_dvd [of "{#x#}" A] by simp end notation prod_mset ("\\<^sub>#") syntax (ASCII) "_prod_mset_image" :: "pttrn \ 'b set \ 'a \ 'a::comm_monoid_mult" ("(3PROD _:#_. _)" [0, 51, 10] 10) syntax "_prod_mset_image" :: "pttrn \ 'b set \ 'a \ 'a::comm_monoid_mult" ("(3\_\#_. _)" [0, 51, 10] 10) translations "\i \# A. b" \ "CONST prod_mset (CONST image_mset (\i. b) A)" lemma prod_mset_constant [simp]: "(\_\#A. c) = c ^ size A" by (simp add: image_mset_const_eq) lemma (in semidom) prod_mset_zero_iff [iff]: "prod_mset A = 0 \ 0 \# A" by (induct A) auto lemma (in semidom_divide) prod_mset_diff: assumes "B \# A" and "0 \# B" shows "prod_mset (A - B) = prod_mset A div prod_mset B" proof - from assms obtain C where "A = B + C" by (metis subset_mset.add_diff_inverse) with assms show ?thesis by simp qed lemma (in semidom_divide) prod_mset_minus: assumes "a \# A" and "a \ 0" shows "prod_mset (A - {#a#}) = prod_mset A div a" using assms prod_mset_diff [of "{#a#}" A] by auto lemma (in normalization_semidom) normalize_prod_mset_normalize: "normalize (prod_mset (image_mset normalize A)) = normalize (prod_mset A)" proof (induction A) case (add x A) have "normalize (prod_mset (image_mset normalize (add_mset x A))) = normalize (x * normalize (prod_mset (image_mset normalize A)))" by simp also note add.IH finally show ?case by simp qed auto lemma (in algebraic_semidom) is_unit_prod_mset_iff: "is_unit (prod_mset A) \ (\x \# A. is_unit x)" by (induct A) (auto simp: is_unit_mult_iff) lemma (in normalization_semidom_multiplicative) normalize_prod_mset: "normalize (prod_mset A) = prod_mset (image_mset normalize A)" by (induct A) (simp_all add: normalize_mult) lemma (in normalization_semidom_multiplicative) normalized_prod_msetI: assumes "\a. a \# A \ normalize a = a" shows "normalize (prod_mset A) = prod_mset A" proof - from assms have "image_mset normalize A = A" by (induct A) simp_all then show ?thesis by (simp add: normalize_prod_mset) qed subsection \Multiset as order-ignorant lists\ context linorder begin lemma mset_insort [simp]: "mset (insort_key k x xs) = add_mset x (mset xs)" by (induct xs) simp_all lemma mset_sort [simp]: "mset (sort_key k xs) = mset xs" by (induct xs) simp_all text \ This lemma shows which properties suffice to show that a function \f\ with \f xs = ys\ behaves like sort. \ lemma properties_for_sort_key: assumes "mset ys = mset xs" and "\k. k \ set ys \ filter (\x. f k = f x) ys = filter (\x. f k = f x) xs" and "sorted (map f ys)" shows "sort_key f xs = ys" using assms proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case (Cons x xs) from Cons.prems(2) have "\k \ set ys. filter (\x. f k = f x) (remove1 x ys) = filter (\x. f k = f x) xs" by (simp add: filter_remove1) with Cons.prems have "sort_key f xs = remove1 x ys" by (auto intro!: Cons.hyps simp add: sorted_map_remove1) moreover from Cons.prems have "x \# mset ys" by auto then have "x \ set ys" by simp ultimately show ?case using Cons.prems by (simp add: insort_key_remove1) qed lemma properties_for_sort: assumes multiset: "mset ys = mset xs" and "sorted ys" shows "sort xs = ys" proof (rule properties_for_sort_key) from multiset show "mset ys = mset xs" . from \sorted ys\ show "sorted (map (\x. x) ys)" by simp from multiset have "length (filter (\y. k = y) ys) = length (filter (\x. k = x) xs)" for k by (rule mset_eq_length_filter) then have "replicate (length (filter (\y. k = y) ys)) k = replicate (length (filter (\x. k = x) xs)) k" for k by simp then show "k \ set ys \ filter (\y. k = y) ys = filter (\x. k = x) xs" for k by (simp add: replicate_length_filter) qed lemma sort_key_inj_key_eq: assumes mset_equal: "mset xs = mset ys" and "inj_on f (set xs)" and "sorted (map f ys)" shows "sort_key f xs = ys" proof (rule properties_for_sort_key) from mset_equal show "mset ys = mset xs" by simp from \sorted (map f ys)\ show "sorted (map f ys)" . show "[x\ys . f k = f x] = [x\xs . f k = f x]" if "k \ set ys" for k proof - from mset_equal have set_equal: "set xs = set ys" by (rule mset_eq_setD) with that have "insert k (set ys) = set ys" by auto with \inj_on f (set xs)\ have inj: "inj_on f (insert k (set ys))" by (simp add: set_equal) from inj have "[x\ys . f k = f x] = filter (HOL.eq k) ys" by (auto intro!: inj_on_filter_key_eq) also have "\ = replicate (count (mset ys) k) k" by (simp add: replicate_count_mset_eq_filter_eq) also have "\ = replicate (count (mset xs) k) k" using mset_equal by simp also have "\ = filter (HOL.eq k) xs" by (simp add: replicate_count_mset_eq_filter_eq) also have "\ = [x\xs . f k = f x]" using inj by (auto intro!: inj_on_filter_key_eq [symmetric] simp add: set_equal) finally show ?thesis . qed qed lemma sort_key_eq_sort_key: assumes "mset xs = mset ys" and "inj_on f (set xs)" shows "sort_key f xs = sort_key f ys" by (rule sort_key_inj_key_eq) (simp_all add: assms) lemma sort_key_by_quicksort: "sort_key f xs = sort_key f [x\xs. f x < f (xs ! (length xs div 2))] @ [x\xs. f x = f (xs ! (length xs div 2))] @ sort_key f [x\xs. f x > f (xs ! (length xs div 2))]" (is "sort_key f ?lhs = ?rhs") proof (rule properties_for_sort_key) show "mset ?rhs = mset ?lhs" by (rule multiset_eqI) auto show "sorted (map f ?rhs)" by (auto simp add: sorted_append intro: sorted_map_same) next fix l assume "l \ set ?rhs" let ?pivot = "f (xs ! (length xs div 2))" have *: "\x. f l = f x \ f x = f l" by auto have "[x \ sort_key f xs . f x = f l] = [x \ xs. f x = f l]" unfolding filter_sort by (rule properties_for_sort_key) (auto intro: sorted_map_same) with * have **: "[x \ sort_key f xs . f l = f x] = [x \ xs. f l = f x]" by simp have "\x P. P (f x) ?pivot \ f l = f x \ P (f l) ?pivot \ f l = f x" by auto then have "\P. [x \ sort_key f xs . P (f x) ?pivot \ f l = f x] = [x \ sort_key f xs. P (f l) ?pivot \ f l = f x]" by simp note *** = this [of "(<)"] this [of "(>)"] this [of "(=)"] show "[x \ ?rhs. f l = f x] = [x \ ?lhs. f l = f x]" proof (cases "f l" ?pivot rule: linorder_cases) case less then have "f l \ ?pivot" and "\ f l > ?pivot" by auto with less show ?thesis by (simp add: filter_sort [symmetric] ** ***) next case equal then show ?thesis by (simp add: * less_le) next case greater then have "f l \ ?pivot" and "\ f l < ?pivot" by auto with greater show ?thesis by (simp add: filter_sort [symmetric] ** ***) qed qed lemma sort_by_quicksort: "sort xs = sort [x\xs. x < xs ! (length xs div 2)] @ [x\xs. x = xs ! (length xs div 2)] @ sort [x\xs. x > xs ! (length xs div 2)]" (is "sort ?lhs = ?rhs") using sort_key_by_quicksort [of "\x. x", symmetric] by simp text \A stable parameterized quicksort\ definition part :: "('b \ 'a) \ 'a \ 'b list \ 'b list \ 'b list \ 'b list" where "part f pivot xs = ([x \ xs. f x < pivot], [x \ xs. f x = pivot], [x \ xs. pivot < f x])" lemma part_code [code]: "part f pivot [] = ([], [], [])" "part f pivot (x # xs) = (let (lts, eqs, gts) = part f pivot xs; x' = f x in if x' < pivot then (x # lts, eqs, gts) else if x' > pivot then (lts, eqs, x # gts) else (lts, x # eqs, gts))" by (auto simp add: part_def Let_def split_def) lemma sort_key_by_quicksort_code [code]: "sort_key f xs = (case xs of [] \ [] | [x] \ xs | [x, y] \ (if f x \ f y then xs else [y, x]) | _ \ let (lts, eqs, gts) = part f (f (xs ! (length xs div 2))) xs in sort_key f lts @ eqs @ sort_key f gts)" proof (cases xs) case Nil then show ?thesis by simp next case (Cons _ ys) note hyps = Cons show ?thesis proof (cases ys) case Nil with hyps show ?thesis by simp next case (Cons _ zs) note hyps = hyps Cons show ?thesis proof (cases zs) case Nil with hyps show ?thesis by auto next case Cons from sort_key_by_quicksort [of f xs] have "sort_key f xs = (let (lts, eqs, gts) = part f (f (xs ! (length xs div 2))) xs in sort_key f lts @ eqs @ sort_key f gts)" by (simp only: split_def Let_def part_def fst_conv snd_conv) with hyps Cons show ?thesis by (simp only: list.cases) qed qed qed end hide_const (open) part lemma mset_remdups_subset_eq: "mset (remdups xs) \# mset xs" by (induct xs) (auto intro: subset_mset.order_trans) lemma mset_update: "i < length ls \ mset (ls[i := v]) = add_mset v (mset ls - {#ls ! i#})" proof (induct ls arbitrary: i) case Nil then show ?case by simp next case (Cons x xs) show ?case proof (cases i) case 0 then show ?thesis by simp next case (Suc i') with Cons show ?thesis by (cases \x = xs ! i'\) auto qed qed lemma mset_swap: "i < length ls \ j < length ls \ mset (ls[j := ls ! i, i := ls ! j]) = mset ls" by (cases "i = j") (simp_all add: mset_update nth_mem_mset) lemma mset_eq_finite: \finite {ys. mset ys = mset xs}\ proof - have \{ys. mset ys = mset xs} \ {ys. set ys \ set xs \ length ys \ length xs}\ by (auto simp add: dest: mset_eq_setD mset_eq_length) moreover have \finite {ys. set ys \ set xs \ length ys \ length xs}\ using finite_lists_length_le by blast ultimately show ?thesis by (rule finite_subset) qed subsection \The multiset order\ subsubsection \Well-foundedness\ definition mult1 :: "('a \ 'a) set \ ('a multiset \ 'a multiset) set" where "mult1 r = {(N, M). \a M0 K. M = add_mset a M0 \ N = M0 + K \ (\b. b \# K \ (b, a) \ r)}" definition mult :: "('a \ 'a) set \ ('a multiset \ 'a multiset) set" where "mult r = (mult1 r)\<^sup>+" lemma mult1I: assumes "M = add_mset a M0" and "N = M0 + K" and "\b. b \# K \ (b, a) \ r" shows "(N, M) \ mult1 r" using assms unfolding mult1_def by blast lemma mult1E: assumes "(N, M) \ mult1 r" obtains a M0 K where "M = add_mset a M0" "N = M0 + K" "\b. b \# K \ (b, a) \ r" using assms unfolding mult1_def by blast lemma mono_mult1: assumes "r \ r'" shows "mult1 r \ mult1 r'" unfolding mult1_def using assms by blast lemma mono_mult: assumes "r \ r'" shows "mult r \ mult r'" unfolding mult_def using mono_mult1[OF assms] trancl_mono by blast lemma not_less_empty [iff]: "(M, {#}) \ mult1 r" by (simp add: mult1_def) lemma less_add: assumes mult1: "(N, add_mset a M0) \ mult1 r" shows "(\M. (M, M0) \ mult1 r \ N = add_mset a M) \ (\K. (\b. b \# K \ (b, a) \ r) \ N = M0 + K)" proof - let ?r = "\K a. \b. b \# K \ (b, a) \ r" let ?R = "\N M. \a M0 K. M = add_mset a M0 \ N = M0 + K \ ?r K a" obtain a' M0' K where M0: "add_mset a M0 = add_mset a' M0'" and N: "N = M0' + K" and r: "?r K a'" using mult1 unfolding mult1_def by auto show ?thesis (is "?case1 \ ?case2") proof - from M0 consider "M0 = M0'" "a = a'" | K' where "M0 = add_mset a' K'" "M0' = add_mset a K'" by atomize_elim (simp only: add_eq_conv_ex) then show ?thesis proof cases case 1 with N r have "?r K a \ N = M0 + K" by simp then have ?case2 .. then show ?thesis .. next case 2 from N 2(2) have n: "N = add_mset a (K' + K)" by simp with r 2(1) have "?R (K' + K) M0" by blast with n have ?case1 by (simp add: mult1_def) then show ?thesis .. qed qed qed lemma all_accessible: assumes "wf r" shows "\M. M \ Wellfounded.acc (mult1 r)" proof let ?R = "mult1 r" let ?W = "Wellfounded.acc ?R" { fix M M0 a assume M0: "M0 \ ?W" and wf_hyp: "\b. (b, a) \ r \ (\M \ ?W. add_mset b M \ ?W)" and acc_hyp: "\M. (M, M0) \ ?R \ add_mset a M \ ?W" have "add_mset a M0 \ ?W" proof (rule accI [of "add_mset a M0"]) fix N assume "(N, add_mset a M0) \ ?R" then consider M where "(M, M0) \ ?R" "N = add_mset a M" | K where "\b. b \# K \ (b, a) \ r" "N = M0 + K" by atomize_elim (rule less_add) then show "N \ ?W" proof cases case 1 from acc_hyp have "(M, M0) \ ?R \ add_mset a M \ ?W" .. from this and \(M, M0) \ ?R\ have "add_mset a M \ ?W" .. then show "N \ ?W" by (simp only: \N = add_mset a M\) next case 2 from this(1) have "M0 + K \ ?W" proof (induct K) case empty from M0 show "M0 + {#} \ ?W" by simp next case (add x K) from add.prems have "(x, a) \ r" by simp with wf_hyp have "\M \ ?W. add_mset x M \ ?W" by blast moreover from add have "M0 + K \ ?W" by simp ultimately have "add_mset x (M0 + K) \ ?W" .. then show "M0 + (add_mset x K) \ ?W" by simp qed then show "N \ ?W" by (simp only: 2(2)) qed qed } note tedious_reasoning = this show "M \ ?W" for M proof (induct M) show "{#} \ ?W" proof (rule accI) fix b assume "(b, {#}) \ ?R" with not_less_empty show "b \ ?W" by contradiction qed fix M a assume "M \ ?W" from \wf r\ have "\M \ ?W. add_mset a M \ ?W" proof induct fix a assume r: "\b. (b, a) \ r \ (\M \ ?W. add_mset b M \ ?W)" show "\M \ ?W. add_mset a M \ ?W" proof fix M assume "M \ ?W" then show "add_mset a M \ ?W" by (rule acc_induct) (rule tedious_reasoning [OF _ r]) qed qed from this and \M \ ?W\ show "add_mset a M \ ?W" .. qed qed theorem wf_mult1: "wf r \ wf (mult1 r)" by (rule acc_wfI) (rule all_accessible) theorem wf_mult: "wf r \ wf (mult r)" unfolding mult_def by (rule wf_trancl) (rule wf_mult1) subsubsection \Closure-free presentation\ text \One direction.\ lemma mult_implies_one_step: assumes trans: "trans r" and MN: "(M, N) \ mult r" shows "\I J K. N = I + J \ M = I + K \ J \ {#} \ (\k \ set_mset K. \j \ set_mset J. (k, j) \ r)" using MN unfolding mult_def mult1_def proof (induction rule: converse_trancl_induct) case (base y) then show ?case by force next case (step y z) note yz = this(1) and zN = this(2) and N_decomp = this(3) obtain I J K where N: "N = I + J" "z = I + K" "J \ {#}" "\k\#K. \j\#J. (k, j) \ r" using N_decomp by blast obtain a M0 K' where z: "z = add_mset a M0" and y: "y = M0 + K'" and K: "\b. b \# K' \ (b, a) \ r" using yz by blast show ?case proof (cases "a \# K") case True moreover have "\j\#J. (k, j) \ r" if "k \# K'" for k using K N trans True by (meson that transE) ultimately show ?thesis by (rule_tac x = I in exI, rule_tac x = J in exI, rule_tac x = "(K - {#a#}) + K'" in exI) (use z y N in \auto simp del: subset_mset.add_diff_assoc2 dest: in_diffD\) next case False then have "a \# I" by (metis N(2) union_iff union_single_eq_member z) moreover have "M0 = I + K - {#a#}" using N(2) z by force ultimately show ?thesis by (rule_tac x = "I - {#a#}" in exI, rule_tac x = "add_mset a J" in exI, rule_tac x = "K + K'" in exI) (use z y N False K in \auto simp: add.assoc\) qed qed lemma one_step_implies_mult: assumes "J \ {#}" and "\k \ set_mset K. \j \ set_mset J. (k, j) \ r" shows "(I + K, I + J) \ mult r" using assms proof (induction "size J" arbitrary: I J K) case 0 then show ?case by auto next case (Suc n) note IH = this(1) and size_J = this(2)[THEN sym] obtain J' a where J: "J = add_mset a J'" using size_J by (blast dest: size_eq_Suc_imp_eq_union) show ?case proof (cases "J' = {#}") case True then show ?thesis using J Suc by (fastforce simp add: mult_def mult1_def) next case [simp]: False have K: "K = {#x \# K. (x, a) \ r#} + {#x \# K. (x, a) \ r#}" by simp have "(I + K, (I + {# x \# K. (x, a) \ r #}) + J') \ mult r" using IH[of J' "{# x \# K. (x, a) \ r#}" "I + {# x \# K. (x, a) \ r#}"] J Suc.prems K size_J by (auto simp: ac_simps) moreover have "(I + {#x \# K. (x, a) \ r#} + J', I + J) \ mult r" by (fastforce simp: J mult1_def mult_def) ultimately show ?thesis unfolding mult_def by simp qed qed lemma subset_implies_mult: assumes sub: "A \# B" shows "(A, B) \ mult r" proof - have ApBmA: "A + (B - A) = B" using sub by simp have BmA: "B - A \ {#}" using sub by (simp add: Diff_eq_empty_iff_mset subset_mset.less_le_not_le) thus ?thesis by (rule one_step_implies_mult[of "B - A" "{#}" _ A, unfolded ApBmA, simplified]) qed subsection \The multiset extension is cancellative for multiset union\ lemma mult_cancel: assumes "trans s" and "irrefl s" shows "(X + Z, Y + Z) \ mult s \ (X, Y) \ mult s" (is "?L \ ?R") proof assume ?L thus ?R proof (induct Z) case (add z Z) obtain X' Y' Z' where *: "add_mset z X + Z = Z' + X'" "add_mset z Y + Z = Z' + Y'" "Y' \ {#}" "\x \ set_mset X'. \y \ set_mset Y'. (x, y) \ s" using mult_implies_one_step[OF \trans s\ add(2)] by auto consider Z2 where "Z' = add_mset z Z2" | X2 Y2 where "X' = add_mset z X2" "Y' = add_mset z Y2" using *(1,2) by (metis add_mset_remove_trivial_If insert_iff set_mset_add_mset_insert union_iff) thus ?case proof (cases) case 1 thus ?thesis using * one_step_implies_mult[of Y' X' s Z2] by (auto simp: add.commute[of _ "{#_#}"] add.assoc intro: add(1)) next case 2 then obtain y where "y \ set_mset Y2" "(z, y) \ s" using *(4) \irrefl s\ by (auto simp: irrefl_def) moreover from this transD[OF \trans s\ _ this(2)] have "x' \ set_mset X2 \ \y \ set_mset Y2. (x', y) \ s" for x' using 2 *(4)[rule_format, of x'] by auto ultimately show ?thesis using * one_step_implies_mult[of Y2 X2 s Z'] 2 by (force simp: add.commute[of "{#_#}"] add.assoc[symmetric] intro: add(1)) qed qed auto next assume ?R then obtain I J K where "Y = I + J" "X = I + K" "J \ {#}" "\k \ set_mset K. \j \ set_mset J. (k, j) \ s" using mult_implies_one_step[OF \trans s\] by blast thus ?L using one_step_implies_mult[of J K s "I + Z"] by (auto simp: ac_simps) qed lemmas mult_cancel_add_mset = mult_cancel[of _ _ "{#_#}", unfolded union_mset_add_mset_right add.comm_neutral] lemma mult_cancel_max: assumes "trans s" and "irrefl s" shows "(X, Y) \ mult s \ (X - X \# Y, Y - X \# Y) \ mult s" (is "?L \ ?R") proof - have "X - X \# Y + X \# Y = X" "Y - X \# Y + X \# Y = Y" by (auto simp flip: count_inject) thus ?thesis using mult_cancel[OF assms, of "X - X \# Y" "X \# Y" "Y - X \# Y"] by auto qed subsection \Quasi-executable version of the multiset extension\ text \ Predicate variants of \mult\ and the reflexive closure of \mult\, which are executable whenever the given predicate \P\ is. Together with the standard code equations for \(\#\) and \(-\) this should yield quadratic (with respect to calls to \P\) implementations of \multp\ and \multeqp\. \ definition multp :: "('a \ 'a \ bool) \ 'a multiset \ 'a multiset \ bool" where "multp P N M = (let Z = M \# N; X = M - Z in X \ {#} \ (let Y = N - Z in (\y \ set_mset Y. \x \ set_mset X. P y x)))" definition multeqp :: "('a \ 'a \ bool) \ 'a multiset \ 'a multiset \ bool" where "multeqp P N M = (let Z = M \# N; X = M - Z; Y = N - Z in (\y \ set_mset Y. \x \ set_mset X. P y x))" lemma multp_iff: assumes "irrefl R" and "trans R" and [simp]: "\x y. P x y \ (x, y) \ R" shows "multp P N M \ (N, M) \ mult R" (is "?L \ ?R") proof - have *: "M \# N + (N - M \# N) = N" "M \# N + (M - M \# N) = M" "(M - M \# N) \# (N - M \# N) = {#}" by (auto simp flip: count_inject) show ?thesis proof assume ?L thus ?R using one_step_implies_mult[of "M - M \# N" "N - M \# N" R "M \# N"] * by (auto simp: multp_def Let_def) next { fix I J K :: "'a multiset" assume "(I + J) \# (I + K) = {#}" then have "I = {#}" by (metis inter_union_distrib_right union_eq_empty) } note [dest!] = this assume ?R thus ?L using mult_implies_one_step[OF assms(2), of "N - M \# N" "M - M \# N"] mult_cancel_max[OF assms(2,1), of "N" "M"] * by (auto simp: multp_def) qed qed lemma multeqp_iff: assumes "irrefl R" and "trans R" and "\x y. P x y \ (x, y) \ R" shows "multeqp P N M \ (N, M) \ (mult R)\<^sup>=" proof - { assume "N \ M" "M - M \# N = {#}" then obtain y where "count N y \ count M y" by (auto simp flip: count_inject) then have "\y. count M y < count N y" using \M - M \# N = {#}\ by (auto simp flip: count_inject dest!: le_neq_implies_less fun_cong[of _ _ y]) } then have "multeqp P N M \ multp P N M \ N = M" by (auto simp: multeqp_def multp_def Let_def in_diff_count) thus ?thesis using multp_iff[OF assms] by simp qed subsubsection \Partial-order properties\ lemma (in preorder) mult1_lessE: assumes "(N, M) \ mult1 {(a, b). a < b}" obtains a M0 K where "M = add_mset a M0" "N = M0 + K" "a \# K" "\b. b \# K \ b < a" proof - from assms obtain a M0 K where "M = add_mset a M0" "N = M0 + K" and *: "b \# K \ b < a" for b by (blast elim: mult1E) moreover from * [of a] have "a \# K" by auto ultimately show thesis by (auto intro: that) qed instantiation multiset :: (preorder) order begin definition less_multiset :: "'a multiset \ 'a multiset \ bool" where "M' < M \ (M', M) \ mult {(x', x). x' < x}" definition less_eq_multiset :: "'a multiset \ 'a multiset \ bool" where "less_eq_multiset M' M \ M' < M \ M' = M" instance proof - have irrefl: "\ M < M" for M :: "'a multiset" proof assume "M < M" then have MM: "(M, M) \ mult {(x, y). x < y}" by (simp add: less_multiset_def) have "trans {(x'::'a, x). x' < x}" by (metis (mono_tags, lifting) case_prodD case_prodI less_trans mem_Collect_eq transI) moreover note MM ultimately have "\I J K. M = I + J \ M = I + K \ J \ {#} \ (\k\set_mset K. \j\set_mset J. (k, j) \ {(x, y). x < y})" by (rule mult_implies_one_step) then obtain I J K where "M = I + J" and "M = I + K" and "J \ {#}" and "(\k\set_mset K. \j\set_mset J. (k, j) \ {(x, y). x < y})" by blast then have *: "K \ {#}" and **: "\k\set_mset K. \j\set_mset K. k < j" by auto have "finite (set_mset K)" by simp moreover note ** ultimately have "set_mset K = {}" by (induct rule: finite_induct) (auto intro: order_less_trans) with * show False by simp qed have trans: "K < M \ M < N \ K < N" for K M N :: "'a multiset" unfolding less_multiset_def mult_def by (blast intro: trancl_trans) show "OFCLASS('a multiset, order_class)" by standard (auto simp add: less_eq_multiset_def irrefl dest: trans) qed end lemma mset_le_irrefl [elim!]: fixes M :: "'a::preorder multiset" shows "M < M \ R" by simp subsubsection \Monotonicity of multiset union\ lemma mult1_union: "(B, D) \ mult1 r \ (C + B, C + D) \ mult1 r" by (force simp: mult1_def) lemma union_le_mono2: "B < D \ C + B < C + (D::'a::preorder multiset)" apply (unfold less_multiset_def mult_def) apply (erule trancl_induct) apply (blast intro: mult1_union) apply (blast intro: mult1_union trancl_trans) done lemma union_le_mono1: "B < D \ B + C < D + (C::'a::preorder multiset)" apply (subst add.commute [of B C]) apply (subst add.commute [of D C]) apply (erule union_le_mono2) done lemma union_less_mono: fixes A B C D :: "'a::preorder multiset" shows "A < C \ B < D \ A + B < C + D" by (blast intro!: union_le_mono1 union_le_mono2 less_trans) instantiation multiset :: (preorder) ordered_ab_semigroup_add begin instance by standard (auto simp add: less_eq_multiset_def intro: union_le_mono2) end subsubsection \Termination proofs with multiset orders\ lemma multi_member_skip: "x \# XS \ x \# {# y #} + XS" and multi_member_this: "x \# {# x #} + XS" and multi_member_last: "x \# {# x #}" by auto definition "ms_strict = mult pair_less" definition "ms_weak = ms_strict \ Id" lemma ms_reduction_pair: "reduction_pair (ms_strict, ms_weak)" unfolding reduction_pair_def ms_strict_def ms_weak_def pair_less_def by (auto intro: wf_mult1 wf_trancl simp: mult_def) lemma smsI: "(set_mset A, set_mset B) \ max_strict \ (Z + A, Z + B) \ ms_strict" unfolding ms_strict_def by (rule one_step_implies_mult) (auto simp add: max_strict_def pair_less_def elim!:max_ext.cases) lemma wmsI: "(set_mset A, set_mset B) \ max_strict \ A = {#} \ B = {#} \ (Z + A, Z + B) \ ms_weak" unfolding ms_weak_def ms_strict_def by (auto simp add: pair_less_def max_strict_def elim!:max_ext.cases intro: one_step_implies_mult) inductive pw_leq where pw_leq_empty: "pw_leq {#} {#}" | pw_leq_step: "\(x,y) \ pair_leq; pw_leq X Y \ \ pw_leq ({#x#} + X) ({#y#} + Y)" lemma pw_leq_lstep: "(x, y) \ pair_leq \ pw_leq {#x#} {#y#}" by (drule pw_leq_step) (rule pw_leq_empty, simp) lemma pw_leq_split: assumes "pw_leq X Y" shows "\A B Z. X = A + Z \ Y = B + Z \ ((set_mset A, set_mset B) \ max_strict \ (B = {#} \ A = {#}))" using assms proof induct case pw_leq_empty thus ?case by auto next case (pw_leq_step x y X Y) then obtain A B Z where [simp]: "X = A + Z" "Y = B + Z" and 1[simp]: "(set_mset A, set_mset B) \ max_strict \ (B = {#} \ A = {#})" by auto from pw_leq_step consider "x = y" | "(x, y) \ pair_less" unfolding pair_leq_def by auto thus ?case proof cases case [simp]: 1 have "{#x#} + X = A + ({#y#}+Z) \ {#y#} + Y = B + ({#y#}+Z) \ ((set_mset A, set_mset B) \ max_strict \ (B = {#} \ A = {#}))" by auto thus ?thesis by blast next case 2 let ?A' = "{#x#} + A" and ?B' = "{#y#} + B" have "{#x#} + X = ?A' + Z" "{#y#} + Y = ?B' + Z" by auto moreover have "(set_mset ?A', set_mset ?B') \ max_strict" using 1 2 unfolding max_strict_def by (auto elim!: max_ext.cases) ultimately show ?thesis by blast qed qed lemma assumes pwleq: "pw_leq Z Z'" shows ms_strictI: "(set_mset A, set_mset B) \ max_strict \ (Z + A, Z' + B) \ ms_strict" and ms_weakI1: "(set_mset A, set_mset B) \ max_strict \ (Z + A, Z' + B) \ ms_weak" and ms_weakI2: "(Z + {#}, Z' + {#}) \ ms_weak" proof - from pw_leq_split[OF pwleq] obtain A' B' Z'' where [simp]: "Z = A' + Z''" "Z' = B' + Z''" and mx_or_empty: "(set_mset A', set_mset B') \ max_strict \ (A' = {#} \ B' = {#})" by blast { assume max: "(set_mset A, set_mset B) \ max_strict" from mx_or_empty have "(Z'' + (A + A'), Z'' + (B + B')) \ ms_strict" proof assume max': "(set_mset A', set_mset B') \ max_strict" with max have "(set_mset (A + A'), set_mset (B + B')) \ max_strict" by (auto simp: max_strict_def intro: max_ext_additive) thus ?thesis by (rule smsI) next assume [simp]: "A' = {#} \ B' = {#}" show ?thesis by (rule smsI) (auto intro: max) qed thus "(Z + A, Z' + B) \ ms_strict" by (simp add: ac_simps) thus "(Z + A, Z' + B) \ ms_weak" by (simp add: ms_weak_def) } from mx_or_empty have "(Z'' + A', Z'' + B') \ ms_weak" by (rule wmsI) thus "(Z + {#}, Z' + {#}) \ ms_weak" by (simp add: ac_simps) qed lemma empty_neutral: "{#} + x = x" "x + {#} = x" and nonempty_plus: "{# x #} + rs \ {#}" and nonempty_single: "{# x #} \ {#}" by auto setup \ let fun msetT T = Type (\<^type_name>\multiset\, [T]); fun mk_mset T [] = Const (\<^const_abbrev>\empty_mset\, msetT T) | mk_mset T [x] = Const (\<^const_name>\add_mset\, T --> msetT T --> msetT T) $ x $ Const (\<^const_abbrev>\empty_mset\, msetT T) | mk_mset T (x :: xs) = Const (\<^const_name>\plus\, msetT T --> msetT T --> msetT T) $ mk_mset T [x] $ mk_mset T xs fun mset_member_tac ctxt m i = if m <= 0 then resolve_tac ctxt @{thms multi_member_this} i ORELSE resolve_tac ctxt @{thms multi_member_last} i else resolve_tac ctxt @{thms multi_member_skip} i THEN mset_member_tac ctxt (m - 1) i fun mset_nonempty_tac ctxt = resolve_tac ctxt @{thms nonempty_plus} ORELSE' resolve_tac ctxt @{thms nonempty_single} fun regroup_munion_conv ctxt = Function_Lib.regroup_conv ctxt \<^const_abbrev>\empty_mset\ \<^const_name>\plus\ (map (fn t => t RS eq_reflection) (@{thms ac_simps} @ @{thms empty_neutral})) fun unfold_pwleq_tac ctxt i = (resolve_tac ctxt @{thms pw_leq_step} i THEN (fn st => unfold_pwleq_tac ctxt (i + 1) st)) ORELSE (resolve_tac ctxt @{thms pw_leq_lstep} i) ORELSE (resolve_tac ctxt @{thms pw_leq_empty} i) val set_mset_simps = [@{thm set_mset_empty}, @{thm set_mset_single}, @{thm set_mset_union}, @{thm Un_insert_left}, @{thm Un_empty_left}] in ScnpReconstruct.multiset_setup (ScnpReconstruct.Multiset { msetT=msetT, mk_mset=mk_mset, mset_regroup_conv=regroup_munion_conv, mset_member_tac=mset_member_tac, mset_nonempty_tac=mset_nonempty_tac, mset_pwleq_tac=unfold_pwleq_tac, set_of_simps=set_mset_simps, smsI'= @{thm ms_strictI}, wmsI2''= @{thm ms_weakI2}, wmsI1= @{thm ms_weakI1}, reduction_pair = @{thm ms_reduction_pair} }) end \ subsection \Legacy theorem bindings\ lemmas multi_count_eq = multiset_eq_iff [symmetric] lemma union_commute: "M + N = N + (M::'a multiset)" by (fact add.commute) lemma union_assoc: "(M + N) + K = M + (N + (K::'a multiset))" by (fact add.assoc) lemma union_lcomm: "M + (N + K) = N + (M + (K::'a multiset))" by (fact add.left_commute) lemmas union_ac = union_assoc union_commute union_lcomm add_mset_commute lemma union_right_cancel: "M + K = N + K \ M = (N::'a multiset)" by (fact add_right_cancel) lemma union_left_cancel: "K + M = K + N \ M = (N::'a multiset)" by (fact add_left_cancel) lemma multi_union_self_other_eq: "(A::'a multiset) + X = A + Y \ X = Y" by (fact add_left_imp_eq) lemma mset_subset_trans: "(M::'a multiset) \# K \ K \# N \ M \# N" by (fact subset_mset.less_trans) lemma multiset_inter_commute: "A \# B = B \# A" by (fact subset_mset.inf.commute) lemma multiset_inter_assoc: "A \# (B \# C) = A \# B \# C" by (fact subset_mset.inf.assoc [symmetric]) lemma multiset_inter_left_commute: "A \# (B \# C) = B \# (A \# C)" by (fact subset_mset.inf.left_commute) lemmas multiset_inter_ac = multiset_inter_commute multiset_inter_assoc multiset_inter_left_commute lemma mset_le_not_refl: "\ M < (M::'a::preorder multiset)" by (fact less_irrefl) lemma mset_le_trans: "K < M \ M < N \ K < (N::'a::preorder multiset)" by (fact less_trans) lemma mset_le_not_sym: "M < N \ \ N < (M::'a::preorder multiset)" by (fact less_not_sym) lemma mset_le_asym: "M < N \ (\ P \ N < (M::'a::preorder multiset)) \ P" by (fact less_asym) declaration \ let fun multiset_postproc _ maybe_name all_values (T as Type (_, [elem_T])) (Const _ $ t') = let val (maybe_opt, ps) = Nitpick_Model.dest_plain_fun t' ||> (~~) ||> map (apsnd (snd o HOLogic.dest_number)) fun elems_for t = (case AList.lookup (=) ps t of SOME n => replicate n t | NONE => [Const (maybe_name, elem_T --> elem_T) $ t]) in (case maps elems_for (all_values elem_T) @ (if maybe_opt then [Const (Nitpick_Model.unrep_mixfix (), elem_T)] else []) of [] => Const (\<^const_name>\zero_class.zero\, T) | ts => foldl1 (fn (s, t) => Const (\<^const_name>\add_mset\, elem_T --> T --> T) $ s $ t) ts) end | multiset_postproc _ _ _ _ t = t in Nitpick_Model.register_term_postprocessor \<^typ>\'a multiset\ multiset_postproc end \ subsection \Naive implementation using lists\ code_datatype mset lemma [code]: "{#} = mset []" by simp lemma [code]: "add_mset x (mset xs) = mset (x # xs)" by simp lemma [code]: "Multiset.is_empty (mset xs) \ List.null xs" by (simp add: Multiset.is_empty_def List.null_def) lemma union_code [code]: "mset xs + mset ys = mset (xs @ ys)" by simp lemma [code]: "image_mset f (mset xs) = mset (map f xs)" by simp lemma [code]: "filter_mset f (mset xs) = mset (filter f xs)" by simp lemma [code]: "mset xs - mset ys = mset (fold remove1 ys xs)" by (rule sym, induct ys arbitrary: xs) (simp_all add: diff_add diff_right_commute diff_diff_add) lemma [code]: "mset xs \# mset ys = mset (snd (fold (\x (ys, zs). if x \ set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, [])))" proof - have "\zs. mset (snd (fold (\x (ys, zs). if x \ set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, zs))) = (mset xs \# mset ys) + mset zs" by (induct xs arbitrary: ys) (auto simp add: inter_add_right1 inter_add_right2 ac_simps) then show ?thesis by simp qed lemma [code]: "mset xs \# mset ys = mset (case_prod append (fold (\x (ys, zs). (remove1 x ys, x # zs)) xs (ys, [])))" proof - have "\zs. mset (case_prod append (fold (\x (ys, zs). (remove1 x ys, x # zs)) xs (ys, zs))) = (mset xs \# mset ys) + mset zs" by (induct xs arbitrary: ys) (simp_all add: multiset_eq_iff) then show ?thesis by simp qed declare in_multiset_in_set [code_unfold] lemma [code]: "count (mset xs) x = fold (\y. if x = y then Suc else id) xs 0" proof - have "\n. fold (\y. if x = y then Suc else id) xs n = count (mset xs) x + n" by (induct xs) simp_all then show ?thesis by simp qed declare set_mset_mset [code] declare sorted_list_of_multiset_mset [code] lemma [code]: \ \not very efficient, but representation-ignorant!\ "mset_set A = mset (sorted_list_of_set A)" apply (cases "finite A") apply simp_all apply (induct A rule: finite_induct) apply simp_all done declare size_mset [code] fun subset_eq_mset_impl :: "'a list \ 'a list \ bool option" where "subset_eq_mset_impl [] ys = Some (ys \ [])" | "subset_eq_mset_impl (Cons x xs) ys = (case List.extract ((=) x) ys of None \ None | Some (ys1,_,ys2) \ subset_eq_mset_impl xs (ys1 @ ys2))" lemma subset_eq_mset_impl: "(subset_eq_mset_impl xs ys = None \ \ mset xs \# mset ys) \ (subset_eq_mset_impl xs ys = Some True \ mset xs \# mset ys) \ (subset_eq_mset_impl xs ys = Some False \ mset xs = mset ys)" proof (induct xs arbitrary: ys) case (Nil ys) show ?case by (auto simp: subset_mset.zero_less_iff_neq_zero) next case (Cons x xs ys) show ?case proof (cases "List.extract ((=) x) ys") case None hence x: "x \ set ys" by (simp add: extract_None_iff) { assume "mset (x # xs) \# mset ys" from set_mset_mono[OF this] x have False by simp } note nle = this moreover { assume "mset (x # xs) \# mset ys" hence "mset (x # xs) \# mset ys" by auto from nle[OF this] have False . } ultimately show ?thesis using None by auto next case (Some res) obtain ys1 y ys2 where res: "res = (ys1,y,ys2)" by (cases res, auto) note Some = Some[unfolded res] from extract_SomeE[OF Some] have "ys = ys1 @ x # ys2" by simp hence id: "mset ys = add_mset x (mset (ys1 @ ys2))" by auto show ?thesis unfolding subset_eq_mset_impl.simps unfolding Some option.simps split unfolding id using Cons[of "ys1 @ ys2"] unfolding subset_mset_def subseteq_mset_def by auto qed qed lemma [code]: "mset xs \# mset ys \ subset_eq_mset_impl xs ys \ None" using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto) lemma [code]: "mset xs \# mset ys \ subset_eq_mset_impl xs ys = Some True" using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto) instantiation multiset :: (equal) equal begin definition [code del]: "HOL.equal A (B :: 'a multiset) \ A = B" lemma [code]: "HOL.equal (mset xs) (mset ys) \ subset_eq_mset_impl xs ys = Some False" unfolding equal_multiset_def using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto) instance by standard (simp add: equal_multiset_def) end declare sum_mset_sum_list [code] lemma [code]: "prod_mset (mset xs) = fold times xs 1" proof - have "\x. fold times xs x = prod_mset (mset xs) * x" by (induct xs) (simp_all add: ac_simps) then show ?thesis by simp qed text \ Exercise for the casual reader: add implementations for \<^term>\(\)\ and \<^term>\(<)\ (multiset order). \ text \Quickcheck generators\ context includes term_syntax begin definition msetify :: "'a::typerep list \ (unit \ Code_Evaluation.term) \ 'a multiset \ (unit \ Code_Evaluation.term)" where [code_unfold]: "msetify xs = Code_Evaluation.valtermify mset {\} xs" end instantiation multiset :: (random) random begin context includes state_combinator_syntax begin definition "Quickcheck_Random.random i = Quickcheck_Random.random i \\ (\xs. Pair (msetify xs))" instance .. end end instantiation multiset :: (full_exhaustive) full_exhaustive begin definition full_exhaustive_multiset :: "('a multiset \ (unit \ term) \ (bool \ term list) option) \ natural \ (bool \ term list) option" where "full_exhaustive_multiset f i = Quickcheck_Exhaustive.full_exhaustive (\xs. f (msetify xs)) i" instance .. end hide_const (open) msetify subsection \BNF setup\ definition rel_mset where "rel_mset R X Y \ (\xs ys. mset xs = X \ mset ys = Y \ list_all2 R xs ys)" lemma mset_zip_take_Cons_drop_twice: assumes "length xs = length ys" "j \ length xs" shows "mset (zip (take j xs @ x # drop j xs) (take j ys @ y # drop j ys)) = add_mset (x,y) (mset (zip xs ys))" using assms proof (induct xs ys arbitrary: x y j rule: list_induct2) case Nil thus ?case by simp next case (Cons x xs y ys) thus ?case proof (cases "j = 0") case True thus ?thesis by simp next case False then obtain k where k: "j = Suc k" by (cases j) simp hence "k \ length xs" using Cons.prems by auto hence "mset (zip (take k xs @ x # drop k xs) (take k ys @ y # drop k ys)) = add_mset (x,y) (mset (zip xs ys))" by (rule Cons.hyps(2)) thus ?thesis unfolding k by auto qed qed lemma ex_mset_zip_left: assumes "length xs = length ys" "mset xs' = mset xs" shows "\ys'. length ys' = length xs' \ mset (zip xs' ys') = mset (zip xs ys)" using assms proof (induct xs ys arbitrary: xs' rule: list_induct2) case Nil thus ?case by auto next case (Cons x xs y ys xs') obtain j where j_len: "j < length xs'" and nth_j: "xs' ! j = x" by (metis Cons.prems in_set_conv_nth list.set_intros(1) mset_eq_setD) define xsa where "xsa = take j xs' @ drop (Suc j) xs'" have "mset xs' = {#x#} + mset xsa" unfolding xsa_def using j_len nth_j by (metis Cons_nth_drop_Suc union_mset_add_mset_right add_mset_remove_trivial add_diff_cancel_left' append_take_drop_id mset.simps(2) mset_append) hence ms_x: "mset xsa = mset xs" by (simp add: Cons.prems) then obtain ysa where len_a: "length ysa = length xsa" and ms_a: "mset (zip xsa ysa) = mset (zip xs ys)" using Cons.hyps(2) by blast define ys' where "ys' = take j ysa @ y # drop j ysa" have xs': "xs' = take j xsa @ x # drop j xsa" using ms_x j_len nth_j Cons.prems xsa_def by (metis append_eq_append_conv append_take_drop_id diff_Suc_Suc Cons_nth_drop_Suc length_Cons length_drop size_mset) have j_len': "j \ length xsa" using j_len xs' xsa_def by (metis add_Suc_right append_take_drop_id length_Cons length_append less_eq_Suc_le not_less) have "length ys' = length xs'" unfolding ys'_def using Cons.prems len_a ms_x by (metis add_Suc_right append_take_drop_id length_Cons length_append mset_eq_length) moreover have "mset (zip xs' ys') = mset (zip (x # xs) (y # ys))" unfolding xs' ys'_def by (rule trans[OF mset_zip_take_Cons_drop_twice]) (auto simp: len_a ms_a j_len') ultimately show ?case by blast qed lemma list_all2_reorder_left_invariance: assumes rel: "list_all2 R xs ys" and ms_x: "mset xs' = mset xs" shows "\ys'. list_all2 R xs' ys' \ mset ys' = mset ys" proof - have len: "length xs = length ys" using rel list_all2_conv_all_nth by auto obtain ys' where len': "length xs' = length ys'" and ms_xy: "mset (zip xs' ys') = mset (zip xs ys)" using len ms_x by (metis ex_mset_zip_left) have "list_all2 R xs' ys'" using assms(1) len' ms_xy unfolding list_all2_iff by (blast dest: mset_eq_setD) moreover have "mset ys' = mset ys" using len len' ms_xy map_snd_zip mset_map by metis ultimately show ?thesis by blast qed lemma ex_mset: "\xs. mset xs = X" by (induct X) (simp, metis mset.simps(2)) inductive pred_mset :: "('a \ bool) \ 'a multiset \ bool" where "pred_mset P {#}" | "\P a; pred_mset P M\ \ pred_mset P (add_mset a M)" lemma pred_mset_iff: \ \TODO: alias for \<^const>\Multiset.Ball\\ \pred_mset P M \ Multiset.Ball M P\ (is \?P \ ?Q\) proof assume ?P then show ?Q by induction simp_all next assume ?Q then show ?P by (induction M) (auto intro: pred_mset.intros) qed bnf "'a multiset" map: image_mset sets: set_mset bd: natLeq wits: "{#}" rel: rel_mset pred: pred_mset proof - show "image_mset id = id" by (rule image_mset.id) show "image_mset (g \ f) = image_mset g \ image_mset f" for f g unfolding comp_def by (rule ext) (simp add: comp_def image_mset.compositionality) show "(\z. z \ set_mset X \ f z = g z) \ image_mset f X = image_mset g X" for f g X by (induct X) simp_all show "set_mset \ image_mset f = (`) f \ set_mset" for f by auto show "card_order natLeq" by (rule natLeq_card_order) show "BNF_Cardinal_Arithmetic.cinfinite natLeq" by (rule natLeq_cinfinite) show "ordLeq3 (card_of (set_mset X)) natLeq" for X by transfer (auto intro!: ordLess_imp_ordLeq simp: finite_iff_ordLess_natLeq[symmetric]) show "rel_mset R OO rel_mset S \ rel_mset (R OO S)" for R S unfolding rel_mset_def[abs_def] OO_def apply clarify subgoal for X Z Y xs ys' ys zs apply (drule list_all2_reorder_left_invariance [where xs = ys' and ys = zs and xs' = ys]) apply (auto intro: list_all2_trans) done done show "rel_mset R = (\x y. \z. set_mset z \ {(x, y). R x y} \ image_mset fst z = x \ image_mset snd z = y)" for R unfolding rel_mset_def[abs_def] apply (rule ext)+ apply safe apply (rule_tac x = "mset (zip xs ys)" in exI; auto simp: in_set_zip list_all2_iff simp flip: mset_map) apply (rename_tac XY) apply (cut_tac X = XY in ex_mset) apply (erule exE) apply (rename_tac xys) apply (rule_tac x = "map fst xys" in exI) apply (auto simp: mset_map) apply (rule_tac x = "map snd xys" in exI) apply (auto simp: mset_map list_all2I subset_eq zip_map_fst_snd) done show "z \ set_mset {#} \ False" for z by auto show "pred_mset P = (\x. Ball (set_mset x) P)" for P by (simp add: fun_eq_iff pred_mset_iff) qed inductive rel_mset' :: \('a \ 'b \ bool) \ 'a multiset \ 'b multiset \ bool\ where Zero[intro]: "rel_mset' R {#} {#}" | Plus[intro]: "\R a b; rel_mset' R M N\ \ rel_mset' R (add_mset a M) (add_mset b N)" lemma rel_mset_Zero: "rel_mset R {#} {#}" unfolding rel_mset_def Grp_def by auto declare multiset.count[simp] declare count_Abs_multiset[simp] declare multiset.count_inverse[simp] lemma rel_mset_Plus: assumes ab: "R a b" and MN: "rel_mset R M N" shows "rel_mset R (add_mset a M) (add_mset b N)" proof - have "\ya. add_mset a (image_mset fst y) = image_mset fst ya \ add_mset b (image_mset snd y) = image_mset snd ya \ set_mset ya \ {(x, y). R x y}" if "R a b" and "set_mset y \ {(x, y). R x y}" for y using that by (intro exI[of _ "add_mset (a,b) y"]) auto thus ?thesis using assms unfolding multiset.rel_compp_Grp Grp_def by blast qed lemma rel_mset'_imp_rel_mset: "rel_mset' R M N \ rel_mset R M N" by (induct rule: rel_mset'.induct) (auto simp: rel_mset_Zero rel_mset_Plus) lemma rel_mset_size: "rel_mset R M N \ size M = size N" unfolding multiset.rel_compp_Grp Grp_def by auto lemma rel_mset_Zero_iff [simp]: shows "rel_mset rel {#} Y \ Y = {#}" and "rel_mset rel X {#} \ X = {#}" by (auto simp add: rel_mset_Zero dest: rel_mset_size) lemma multiset_induct2[case_names empty addL addR]: assumes empty: "P {#} {#}" and addL: "\a M N. P M N \ P (add_mset a M) N" and addR: "\a M N. P M N \ P M (add_mset a N)" shows "P M N" apply(induct N rule: multiset_induct) apply(induct M rule: multiset_induct, rule empty, erule addL) apply(induct M rule: multiset_induct, erule addR, erule addR) done lemma multiset_induct2_size[consumes 1, case_names empty add]: assumes c: "size M = size N" and empty: "P {#} {#}" and add: "\a b M N a b. P M N \ P (add_mset a M) (add_mset b N)" shows "P M N" using c proof (induct M arbitrary: N rule: measure_induct_rule[of size]) case (less M) show ?case proof(cases "M = {#}") case True hence "N = {#}" using less.prems by auto thus ?thesis using True empty by auto next case False then obtain M1 a where M: "M = add_mset a M1" by (metis multi_nonempty_split) have "N \ {#}" using False less.prems by auto then obtain N1 b where N: "N = add_mset b N1" by (metis multi_nonempty_split) have "size M1 = size N1" using less.prems unfolding M N by auto thus ?thesis using M N less.hyps add by auto qed qed lemma msed_map_invL: assumes "image_mset f (add_mset a M) = N" shows "\N1. N = add_mset (f a) N1 \ image_mset f M = N1" proof - have "f a \# N" using assms multiset.set_map[of f "add_mset a M"] by auto then obtain N1 where N: "N = add_mset (f a) N1" using multi_member_split by metis have "image_mset f M = N1" using assms unfolding N by simp thus ?thesis using N by blast qed lemma msed_map_invR: assumes "image_mset f M = add_mset b N" shows "\M1 a. M = add_mset a M1 \ f a = b \ image_mset f M1 = N" proof - obtain a where a: "a \# M" and fa: "f a = b" using multiset.set_map[of f M] unfolding assms by (metis image_iff union_single_eq_member) then obtain M1 where M: "M = add_mset a M1" using multi_member_split by metis have "image_mset f M1 = N" using assms unfolding M fa[symmetric] by simp thus ?thesis using M fa by blast qed lemma msed_rel_invL: assumes "rel_mset R (add_mset a M) N" shows "\N1 b. N = add_mset b N1 \ R a b \ rel_mset R M N1" proof - obtain K where KM: "image_mset fst K = add_mset a M" and KN: "image_mset snd K = N" and sK: "set_mset K \ {(a, b). R a b}" using assms unfolding multiset.rel_compp_Grp Grp_def by auto obtain K1 ab where K: "K = add_mset ab K1" and a: "fst ab = a" and K1M: "image_mset fst K1 = M" using msed_map_invR[OF KM] by auto obtain N1 where N: "N = add_mset (snd ab) N1" and K1N1: "image_mset snd K1 = N1" using msed_map_invL[OF KN[unfolded K]] by auto have Rab: "R a (snd ab)" using sK a unfolding K by auto have "rel_mset R M N1" using sK K1M K1N1 unfolding K multiset.rel_compp_Grp Grp_def by auto thus ?thesis using N Rab by auto qed lemma msed_rel_invR: assumes "rel_mset R M (add_mset b N)" shows "\M1 a. M = add_mset a M1 \ R a b \ rel_mset R M1 N" proof - obtain K where KN: "image_mset snd K = add_mset b N" and KM: "image_mset fst K = M" and sK: "set_mset K \ {(a, b). R a b}" using assms unfolding multiset.rel_compp_Grp Grp_def by auto obtain K1 ab where K: "K = add_mset ab K1" and b: "snd ab = b" and K1N: "image_mset snd K1 = N" using msed_map_invR[OF KN] by auto obtain M1 where M: "M = add_mset (fst ab) M1" and K1M1: "image_mset fst K1 = M1" using msed_map_invL[OF KM[unfolded K]] by auto have Rab: "R (fst ab) b" using sK b unfolding K by auto have "rel_mset R M1 N" using sK K1N K1M1 unfolding K multiset.rel_compp_Grp Grp_def by auto thus ?thesis using M Rab by auto qed lemma rel_mset_imp_rel_mset': assumes "rel_mset R M N" shows "rel_mset' R M N" using assms proof(induct M arbitrary: N rule: measure_induct_rule[of size]) case (less M) have c: "size M = size N" using rel_mset_size[OF less.prems] . show ?case proof(cases "M = {#}") case True hence "N = {#}" using c by simp thus ?thesis using True rel_mset'.Zero by auto next case False then obtain M1 a where M: "M = add_mset a M1" by (metis multi_nonempty_split) obtain N1 b where N: "N = add_mset b N1" and R: "R a b" and ms: "rel_mset R M1 N1" using msed_rel_invL[OF less.prems[unfolded M]] by auto have "rel_mset' R M1 N1" using less.hyps[of M1 N1] ms unfolding M by simp thus ?thesis using rel_mset'.Plus[of R a b, OF R] unfolding M N by simp qed qed lemma rel_mset_rel_mset': "rel_mset R M N = rel_mset' R M N" using rel_mset_imp_rel_mset' rel_mset'_imp_rel_mset by auto text \The main end product for \<^const>\rel_mset\: inductive characterization:\ lemmas rel_mset_induct[case_names empty add, induct pred: rel_mset] = rel_mset'.induct[unfolded rel_mset_rel_mset'[symmetric]] subsection \Size setup\ lemma size_multiset_o_map: "size_multiset g \ image_mset f = size_multiset (g \ f)" apply (rule ext) subgoal for x by (induct x) auto done setup \ BNF_LFP_Size.register_size_global \<^type_name>\multiset\ \<^const_name>\size_multiset\ @{thm size_multiset_overloaded_def} @{thms size_multiset_empty size_multiset_single size_multiset_union size_empty size_single size_union} @{thms size_multiset_o_map} \ subsection \Lemmas about Size\ lemma size_mset_SucE: "size A = Suc n \ (\a B. A = {#a#} + B \ size B = n \ P) \ P" by (cases A) (auto simp add: ac_simps) lemma size_Suc_Diff1: "x \# M \ Suc (size (M - {#x#})) = size M" using arg_cong[OF insert_DiffM, of _ _ size] by simp lemma size_Diff_singleton: "x \# M \ size (M - {#x#}) = size M - 1" by (simp flip: size_Suc_Diff1) lemma size_Diff_singleton_if: "size (A - {#x#}) = (if x \# A then size A - 1 else size A)" by (simp add: diff_single_trivial size_Diff_singleton) lemma size_Un_Int: "size A + size B = size (A \# B) + size (A \# B)" by (metis inter_subset_eq_union size_union subset_mset.diff_add union_diff_inter_eq_sup) lemma size_Un_disjoint: "A \# B = {#} \ size (A \# B) = size A + size B" using size_Un_Int[of A B] by simp lemma size_Diff_subset_Int: "size (M - M') = size M - size (M \# M')" by (metis diff_intersect_left_idem size_Diff_submset subset_mset.inf_le1) lemma diff_size_le_size_Diff: "size (M :: _ multiset) - size M' \ size (M - M')" by (simp add: diff_le_mono2 size_Diff_subset_Int size_mset_mono) lemma size_Diff1_less: "x\# M \ size (M - {#x#}) < size M" by (rule Suc_less_SucD) (simp add: size_Suc_Diff1) lemma size_Diff2_less: "x\# M \ y\# M \ size (M - {#x#} - {#y#}) < size M" by (metis less_imp_diff_less size_Diff1_less size_Diff_subset_Int) lemma size_Diff1_le: "size (M - {#x#}) \ size M" by (cases "x \# M") (simp_all add: size_Diff1_less less_imp_le diff_single_trivial) lemma size_psubset: "M \# M' \ size M < size M' \ M \# M'" using less_irrefl subset_mset_def by blast hide_const (open) wcount end diff --git a/src/HOL/Library/RBT.thy b/src/HOL/Library/RBT.thy --- a/src/HOL/Library/RBT.thy +++ b/src/HOL/Library/RBT.thy @@ -1,240 +1,243 @@ (* Title: HOL/Library/RBT.thy Author: Lukas Bulwahn and Ondrej Kuncar *) section \Abstract type of RBT trees\ theory RBT imports Main RBT_Impl begin subsection \Type definition\ typedef (overloaded) ('a, 'b) rbt = "{t :: ('a::linorder, 'b) RBT_Impl.rbt. is_rbt t}" morphisms impl_of RBT proof - have "RBT_Impl.Empty \ ?rbt" by simp then show ?thesis .. qed lemma rbt_eq_iff: "t1 = t2 \ impl_of t1 = impl_of t2" by (simp add: impl_of_inject) lemma rbt_eqI: "impl_of t1 = impl_of t2 \ t1 = t2" by (simp add: rbt_eq_iff) lemma is_rbt_impl_of [simp, intro]: "is_rbt (impl_of t)" using impl_of [of t] by simp lemma RBT_impl_of [simp, code abstype]: "RBT (impl_of t) = t" by (simp add: impl_of_inverse) subsection \Primitive operations\ setup_lifting type_definition_rbt lift_definition lookup :: "('a::linorder, 'b) rbt \ 'a \ 'b" is "rbt_lookup" . lift_definition empty :: "('a::linorder, 'b) rbt" is RBT_Impl.Empty by (simp add: empty_def) lift_definition insert :: "'a::linorder \ 'b \ ('a, 'b) rbt \ ('a, 'b) rbt" is "rbt_insert" by simp lift_definition delete :: "'a::linorder \ ('a, 'b) rbt \ ('a, 'b) rbt" is "rbt_delete" by simp lift_definition entries :: "('a::linorder, 'b) rbt \ ('a \ 'b) list" is RBT_Impl.entries . lift_definition keys :: "('a::linorder, 'b) rbt \ 'a list" is RBT_Impl.keys . lift_definition bulkload :: "('a::linorder \ 'b) list \ ('a, 'b) rbt" is "rbt_bulkload" .. lift_definition map_entry :: "'a \ ('b \ 'b) \ ('a::linorder, 'b) rbt \ ('a, 'b) rbt" is rbt_map_entry by simp lift_definition map :: "('a \ 'b \ 'c) \ ('a::linorder, 'b) rbt \ ('a, 'c) rbt" is RBT_Impl.map by simp lift_definition fold :: "('a \ 'b \ 'c \ 'c) \ ('a::linorder, 'b) rbt \ 'c \ 'c" is RBT_Impl.fold . lift_definition union :: "('a::linorder, 'b) rbt \ ('a, 'b) rbt \ ('a, 'b) rbt" is "rbt_union" by (simp add: rbt_union_is_rbt) lift_definition foldi :: "('c \ bool) \ ('a \ 'b \ 'c \ 'c) \ ('a :: linorder, 'b) rbt \ 'c \ 'c" is RBT_Impl.foldi . lift_definition combine_with_key :: "('a \ 'b \ 'b \ 'b) \ ('a::linorder, 'b) rbt \ ('a, 'b) rbt \ ('a, 'b) rbt" is RBT_Impl.rbt_union_with_key by (rule is_rbt_rbt_unionwk) lift_definition combine :: "('b \ 'b \ 'b) \ ('a::linorder, 'b) rbt \ ('a, 'b) rbt \ ('a, 'b) rbt" is RBT_Impl.rbt_union_with by (rule rbt_unionw_is_rbt) subsection \Derived operations\ definition is_empty :: "('a::linorder, 'b) rbt \ bool" where [code]: "is_empty t = (case impl_of t of RBT_Impl.Empty \ True | _ \ False)" (* TODO: Is deleting more efficient than re-building the tree? (Probably more difficult to prove though *) definition filter :: "('a \ 'b \ bool) \ ('a::linorder, 'b) rbt \ ('a, 'b) rbt" where [code]: "filter P t = fold (\k v t. if P k v then insert k v t else t) t empty" subsection \Abstract lookup properties\ lemma lookup_RBT: "is_rbt t \ lookup (RBT t) = rbt_lookup t" by (simp add: lookup_def RBT_inverse) lemma lookup_impl_of: "rbt_lookup (impl_of t) = lookup t" by transfer (rule refl) lemma entries_impl_of: "RBT_Impl.entries (impl_of t) = entries t" by transfer (rule refl) lemma keys_impl_of: "RBT_Impl.keys (impl_of t) = keys t" by transfer (rule refl) lemma lookup_keys: "dom (lookup t) = set (keys t)" by transfer (simp add: rbt_lookup_keys) lemma lookup_empty [simp]: "lookup empty = Map.empty" by (simp add: empty_def lookup_RBT fun_eq_iff) lemma lookup_insert [simp]: "lookup (insert k v t) = (lookup t)(k \ v)" by transfer (rule rbt_lookup_rbt_insert) lemma lookup_delete [simp]: "lookup (delete k t) = (lookup t)(k := None)" by transfer (simp add: rbt_lookup_rbt_delete restrict_complement_singleton_eq) lemma map_of_entries [simp]: "map_of (entries t) = lookup t" by transfer (simp add: map_of_entries) lemma entries_lookup: "entries t1 = entries t2 \ lookup t1 = lookup t2" by transfer (simp add: entries_rbt_lookup) lemma lookup_bulkload [simp]: "lookup (bulkload xs) = map_of xs" by transfer (rule rbt_lookup_rbt_bulkload) lemma lookup_map_entry [simp]: "lookup (map_entry k f t) = (lookup t)(k := map_option f (lookup t k))" by transfer (rule rbt_lookup_rbt_map_entry) lemma lookup_map [simp]: "lookup (map f t) k = map_option (f k) (lookup t k)" by transfer (rule rbt_lookup_map) lemma lookup_combine_with_key [simp]: "lookup (combine_with_key f t1 t2) k = combine_options (f k) (lookup t1 k) (lookup t2 k)" by transfer (simp_all add: combine_options_def rbt_lookup_rbt_unionwk) lemma combine_altdef: "combine f t1 t2 = combine_with_key (\_. f) t1 t2" by transfer (simp add: rbt_union_with_def) lemma lookup_combine [simp]: "lookup (combine f t1 t2) k = combine_options f (lookup t1 k) (lookup t2 k)" by (simp add: combine_altdef) lemma fold_fold: "fold f t = List.fold (case_prod f) (entries t)" by transfer (rule RBT_Impl.fold_def) lemma impl_of_empty: "impl_of empty = RBT_Impl.Empty" by transfer (rule refl) lemma is_empty_empty [simp]: "is_empty t \ t = empty" unfolding is_empty_def by transfer (simp split: rbt.split) lemma RBT_lookup_empty [simp]: (*FIXME*) "rbt_lookup t = Map.empty \ t = RBT_Impl.Empty" by (cases t) (auto simp add: fun_eq_iff) lemma lookup_empty_empty [simp]: "lookup t = Map.empty \ t = empty" by transfer (rule RBT_lookup_empty) lemma sorted_keys [iff]: "sorted (keys t)" by transfer (simp add: RBT_Impl.keys_def rbt_sorted_entries) lemma distinct_keys [iff]: "distinct (keys t)" by transfer (simp add: RBT_Impl.keys_def distinct_entries) lemma finite_dom_lookup [simp, intro!]: "finite (dom (lookup t))" by transfer simp lemma lookup_union: "lookup (union s t) = lookup s ++ lookup t" by transfer (simp add: rbt_lookup_rbt_union) lemma lookup_in_tree: "(lookup t k = Some v) = ((k, v) \ set (entries t))" by transfer (simp add: rbt_lookup_in_tree) lemma keys_entries: "(k \ set (keys t)) = (\v. (k, v) \ set (entries t))" by transfer (simp add: keys_entries) lemma fold_def_alt: "fold f t = List.fold (case_prod f) (entries t)" by transfer (auto simp: RBT_Impl.fold_def) lemma distinct_entries: "distinct (List.map fst (entries t))" by transfer (simp add: distinct_entries) +lemma sorted_entries: "sorted (List.map fst (entries t))" + by (transfer) (simp add: rbt_sorted_entries) + lemma non_empty_keys: "t \ empty \ keys t \ []" by transfer (simp add: non_empty_rbt_keys) lemma keys_def_alt: "keys t = List.map fst (entries t)" by transfer (simp add: RBT_Impl.keys_def) context begin private lemma lookup_filter_aux: assumes "distinct (List.map fst xs)" shows "lookup (List.fold (\(k, v) t. if P k v then insert k v t else t) xs t) k = (case map_of xs k of None \ lookup t k | Some v \ if P k v then Some v else lookup t k)" using assms by (induction xs arbitrary: t) (force split: option.splits)+ lemma lookup_filter: "lookup (filter P t) k = (case lookup t k of None \ None | Some v \ if P k v then Some v else None)" unfolding filter_def using lookup_filter_aux[of "entries t" P empty k] by (simp add: fold_fold distinct_entries split: option.splits) end subsection \Quickcheck generators\ quickcheck_generator rbt predicate: is_rbt constructors: empty, insert subsection \Hide implementation details\ lifting_update rbt.lifting lifting_forget rbt.lifting hide_const (open) impl_of empty lookup keys entries bulkload delete map fold union insert map_entry foldi is_empty filter hide_fact (open) empty_def lookup_def keys_def entries_def bulkload_def delete_def map_def fold_def union_def insert_def map_entry_def foldi_def is_empty_def filter_def end diff --git a/src/HOL/Library/RBT_Mapping.thy b/src/HOL/Library/RBT_Mapping.thy --- a/src/HOL/Library/RBT_Mapping.thy +++ b/src/HOL/Library/RBT_Mapping.thy @@ -1,229 +1,247 @@ (* Title: HOL/Library/RBT_Mapping.thy Author: Florian Haftmann and Ondrej Kuncar *) section \Implementation of mappings with Red-Black Trees\ (*<*) theory RBT_Mapping imports RBT Mapping begin subsection \Implementation of mappings\ context includes rbt.lifting begin lift_definition Mapping :: "('a::linorder, 'b) rbt \ ('a, 'b) mapping" is RBT.lookup . end code_datatype Mapping context includes rbt.lifting begin lemma lookup_Mapping [simp, code]: "Mapping.lookup (Mapping t) = RBT.lookup t" by (transfer fixing: t) rule lemma empty_Mapping [code]: "Mapping.empty = Mapping RBT.empty" proof - note RBT.empty.transfer[transfer_rule del] show ?thesis by transfer simp qed lemma is_empty_Mapping [code]: "Mapping.is_empty (Mapping t) \ RBT.is_empty t" unfolding is_empty_def by (transfer fixing: t) simp lemma insert_Mapping [code]: "Mapping.update k v (Mapping t) = Mapping (RBT.insert k v t)" by (transfer fixing: t) simp lemma delete_Mapping [code]: "Mapping.delete k (Mapping t) = Mapping (RBT.delete k t)" by (transfer fixing: t) simp lemma map_entry_Mapping [code]: "Mapping.map_entry k f (Mapping t) = Mapping (RBT.map_entry k f t)" apply (transfer fixing: t) apply (case_tac "RBT.lookup t k") apply auto done lemma keys_Mapping [code]: "Mapping.keys (Mapping t) = set (RBT.keys t)" by (transfer fixing: t) (simp add: lookup_keys) lemma ordered_keys_Mapping [code]: "Mapping.ordered_keys (Mapping t) = RBT.keys t" unfolding ordered_keys_def by (transfer fixing: t) (auto simp add: lookup_keys intro: sorted_distinct_set_unique) +lemma Map_graph_lookup: "Map.graph (RBT.lookup t) = set (RBT.entries t)" + by (metis RBT.distinct_entries RBT.map_of_entries graph_map_of_if_distinct_ran) + +lemma entries_Mapping [code]: "Mapping.entries (Mapping t) = set (RBT.entries t)" + by (transfer fixing: t) (fact Map_graph_lookup) + +lemma ordered_entries_Mapping [code]: "Mapping.ordered_entries (Mapping t) = RBT.entries t" +proof - + note folding_Map_graph.idem_if_sorted_distinct[ + where ?m="RBT.lookup t", OF _ _ folding_Map_graph.distinct_if_distinct_map] + then show ?thesis + unfolding ordered_entries_def + by (transfer fixing: t) (auto simp: Map_graph_lookup distinct_entries sorted_entries) +qed + +lemma fold_Mapping [code]: "Mapping.fold f (Mapping t) a = RBT.fold f t a" + by (simp add: Mapping.fold_def fold_fold ordered_entries_Mapping) + lemma Mapping_size_card_keys: (*FIXME*) "Mapping.size m = card (Mapping.keys m)" unfolding size_def by transfer simp lemma size_Mapping [code]: "Mapping.size (Mapping t) = length (RBT.keys t)" unfolding size_def by (transfer fixing: t) (simp add: lookup_keys distinct_card) context notes RBT.bulkload.transfer[transfer_rule del] begin lemma tabulate_Mapping [code]: "Mapping.tabulate ks f = Mapping (RBT.bulkload (List.map (\k. (k, f k)) ks))" by transfer (simp add: map_of_map_restrict) lemma bulkload_Mapping [code]: "Mapping.bulkload vs = Mapping (RBT.bulkload (List.map (\n. (n, vs ! n)) [0.. RBT.entries t1 = RBT.entries t2" - by (transfer fixing: t1 t2) (simp add: entries_lookup) + by (transfer fixing: t1 t2) (simp add: RBT.entries_lookup) lemma [code nbe]: "HOL.equal (x :: (_, _) mapping) x \ True" by (fact equal_refl) end (*>*) text \ This theory defines abstract red-black trees as an efficient representation of finite maps, backed by the implementation in \<^theory>\HOL-Library.RBT_Impl\. \ subsection \Data type and invariant\ text \ The type \<^typ>\('k, 'v) RBT_Impl.rbt\ denotes red-black trees with keys of type \<^typ>\'k\ and values of type \<^typ>\'v\. To function properly, the key type musorted belong to the \linorder\ class. A value \<^term>\t\ of this type is a valid red-black tree if it satisfies the invariant \is_rbt t\. The abstract type \<^typ>\('k, 'v) rbt\ always obeys this invariant, and for this reason you should only use this in our application. Going back to \<^typ>\('k, 'v) RBT_Impl.rbt\ may be necessary in proofs if not yet proven properties about the operations must be established. The interpretation function \<^const>\RBT.lookup\ returns the partial map represented by a red-black tree: @{term_type[display] "RBT.lookup"} This function should be used for reasoning about the semantics of the RBT operations. Furthermore, it implements the lookup functionality for the data structure: It is executable and the lookup is performed in $O(\log n)$. \ subsection \Operations\ text \ Currently, the following operations are supported: @{term_type [display] "RBT.empty"} Returns the empty tree. $O(1)$ @{term_type [display] "RBT.insert"} Updates the map at a given position. $O(\log n)$ @{term_type [display] "RBT.delete"} Deletes a map entry at a given position. $O(\log n)$ @{term_type [display] "RBT.entries"} Return a corresponding key-value list for a tree. @{term_type [display] "RBT.bulkload"} Builds a tree from a key-value list. @{term_type [display] "RBT.map_entry"} Maps a single entry in a tree. @{term_type [display] "RBT.map"} Maps all values in a tree. $O(n)$ @{term_type [display] "RBT.fold"} Folds over all entries in a tree. $O(n)$ \ subsection \Invariant preservation\ text \ \noindent @{thm Empty_is_rbt}\hfill(\Empty_is_rbt\) \noindent @{thm rbt_insert_is_rbt}\hfill(\rbt_insert_is_rbt\) \noindent @{thm rbt_delete_is_rbt}\hfill(\delete_is_rbt\) \noindent @{thm rbt_bulkload_is_rbt}\hfill(\bulkload_is_rbt\) \noindent @{thm rbt_map_entry_is_rbt}\hfill(\map_entry_is_rbt\) \noindent @{thm map_is_rbt}\hfill(\map_is_rbt\) \noindent @{thm rbt_union_is_rbt}\hfill(\union_is_rbt\) \ subsection \Map Semantics\ text \ \noindent \underline{\lookup_empty\} @{thm [display] lookup_empty} \vspace{1ex} \noindent \underline{\lookup_insert\} @{thm [display] lookup_insert} \vspace{1ex} \noindent \underline{\lookup_delete\} @{thm [display] lookup_delete} \vspace{1ex} \noindent \underline{\lookup_bulkload\} @{thm [display] lookup_bulkload} \vspace{1ex} \noindent \underline{\lookup_map\} @{thm [display] lookup_map} \vspace{1ex} \ end diff --git a/src/HOL/Library/RBT_Set.thy b/src/HOL/Library/RBT_Set.thy --- a/src/HOL/Library/RBT_Set.thy +++ b/src/HOL/Library/RBT_Set.thy @@ -1,800 +1,802 @@ (* Title: HOL/Library/RBT_Set.thy Author: Ondrej Kuncar *) section \Implementation of sets using RBT trees\ theory RBT_Set imports RBT Product_Lexorder begin (* Users should be aware that by including this file all code equations outside of List.thy using 'a list as an implementation of sets cannot be used for code generation. If such equations are not needed, they can be deleted from the code generator. Otherwise, a user has to provide their own equations using RBT trees. *) section \Definition of code datatype constructors\ definition Set :: "('a::linorder, unit) rbt \ 'a set" where "Set t = {x . RBT.lookup t x = Some ()}" definition Coset :: "('a::linorder, unit) rbt \ 'a set" where [simp]: "Coset t = - Set t" section \Deletion of already existing code equations\ declare [[code drop: Set.empty Set.is_empty uminus_set_inst.uminus_set Set.member Set.insert Set.remove UNIV Set.filter image Set.subset_eq Ball Bex can_select Set.union minus_set_inst.minus_set Set.inter card the_elem Pow sum prod Product_Type.product Id_on Image trancl relcomp wf Min Inf_fin Max Sup_fin "(Inf :: 'a set set \ 'a set)" "(Sup :: 'a set set \ 'a set)" sorted_list_of_set List.map_project List.Bleast]] section \Lemmas\ subsection \Auxiliary lemmas\ lemma [simp]: "x \ Some () \ x = None" by (auto simp: not_Some_eq[THEN iffD1]) lemma Set_set_keys: "Set x = dom (RBT.lookup x)" by (auto simp: Set_def) lemma finite_Set [simp, intro!]: "finite (Set x)" by (simp add: Set_set_keys) lemma set_keys: "Set t = set(RBT.keys t)" by (simp add: Set_set_keys lookup_keys) subsection \fold and filter\ lemma finite_fold_rbt_fold_eq: assumes "comp_fun_commute f" shows "Finite_Set.fold f A (set (RBT.entries t)) = RBT.fold (curry f) t A" proof - + interpret comp_fun_commute: comp_fun_commute f + by (fact assms) have *: "remdups (RBT.entries t) = RBT.entries t" using distinct_entries distinct_map by (auto intro: distinct_remdups_id) show ?thesis using assms by (auto simp: fold_def_alt comp_fun_commute.fold_set_fold_remdups *) qed definition fold_keys :: "('a :: linorder \ 'b \ 'b) \ ('a, _) rbt \ 'b \ 'b" where [code_unfold]:"fold_keys f t A = RBT.fold (\k _ t. f k t) t A" lemma fold_keys_def_alt: "fold_keys f t s = List.fold f (RBT.keys t) s" by (auto simp: fold_map o_def split_def fold_def_alt keys_def_alt fold_keys_def) lemma finite_fold_fold_keys: assumes "comp_fun_commute f" shows "Finite_Set.fold f A (Set t) = fold_keys f t A" using assms proof - interpret comp_fun_commute f by fact have "set (RBT.keys t) = fst ` (set (RBT.entries t))" by (auto simp: fst_eq_Domain keys_entries) moreover have "inj_on fst (set (RBT.entries t))" using distinct_entries distinct_map by auto ultimately show ?thesis by (auto simp add: set_keys fold_keys_def curry_def fold_image finite_fold_rbt_fold_eq comp_comp_fun_commute) qed definition rbt_filter :: "('a :: linorder \ bool) \ ('a, 'b) rbt \ 'a set" where "rbt_filter P t = RBT.fold (\k _ A'. if P k then Set.insert k A' else A') t {}" lemma Set_filter_rbt_filter: "Set.filter P (Set t) = rbt_filter P t" by (simp add: fold_keys_def Set_filter_fold rbt_filter_def finite_fold_fold_keys[OF comp_fun_commute_filter_fold]) subsection \foldi and Ball\ lemma Ball_False: "RBT_Impl.fold (\k v s. s \ P k) t False = False" by (induction t) auto lemma rbt_foldi_fold_conj: "RBT_Impl.foldi (\s. s = True) (\k v s. s \ P k) t val = RBT_Impl.fold (\k v s. s \ P k) t val" proof (induction t arbitrary: val) case (Branch c t1) then show ?case by (cases "RBT_Impl.fold (\k v s. s \ P k) t1 True") (simp_all add: Ball_False) qed simp lemma foldi_fold_conj: "RBT.foldi (\s. s = True) (\k v s. s \ P k) t val = fold_keys (\k s. s \ P k) t val" unfolding fold_keys_def including rbt.lifting by transfer (rule rbt_foldi_fold_conj) subsection \foldi and Bex\ lemma Bex_True: "RBT_Impl.fold (\k v s. s \ P k) t True = True" by (induction t) auto lemma rbt_foldi_fold_disj: "RBT_Impl.foldi (\s. s = False) (\k v s. s \ P k) t val = RBT_Impl.fold (\k v s. s \ P k) t val" proof (induction t arbitrary: val) case (Branch c t1) then show ?case by (cases "RBT_Impl.fold (\k v s. s \ P k) t1 False") (simp_all add: Bex_True) qed simp lemma foldi_fold_disj: "RBT.foldi (\s. s = False) (\k v s. s \ P k) t val = fold_keys (\k s. s \ P k) t val" unfolding fold_keys_def including rbt.lifting by transfer (rule rbt_foldi_fold_disj) subsection \folding over non empty trees and selecting the minimal and maximal element\ subsubsection \concrete\ text \The concrete part is here because it's probably not general enough to be moved to \RBT_Impl\\ definition rbt_fold1_keys :: "('a \ 'a \ 'a) \ ('a::linorder, 'b) RBT_Impl.rbt \ 'a" where "rbt_fold1_keys f t = List.fold f (tl(RBT_Impl.keys t)) (hd(RBT_Impl.keys t))" paragraph \minimum\ definition rbt_min :: "('a::linorder, unit) RBT_Impl.rbt \ 'a" where "rbt_min t = rbt_fold1_keys min t" lemma key_le_right: "rbt_sorted (Branch c lt k v rt) \ (\x. x \set (RBT_Impl.keys rt) \ k \ x)" by (auto simp: rbt_greater_prop less_imp_le) lemma left_le_key: "rbt_sorted (Branch c lt k v rt) \ (\x. x \set (RBT_Impl.keys lt) \ x \ k)" by (auto simp: rbt_less_prop less_imp_le) lemma fold_min_triv: fixes k :: "_ :: linorder" shows "(\x\set xs. k \ x) \ List.fold min xs k = k" by (induct xs) (auto simp add: min_def) lemma rbt_min_simps: "is_rbt (Branch c RBT_Impl.Empty k v rt) \ rbt_min (Branch c RBT_Impl.Empty k v rt) = k" by (auto intro: fold_min_triv dest: key_le_right is_rbt_rbt_sorted simp: rbt_fold1_keys_def rbt_min_def) fun rbt_min_opt where "rbt_min_opt (Branch c RBT_Impl.Empty k v rt) = k" | "rbt_min_opt (Branch c (Branch lc llc lk lv lrt) k v rt) = rbt_min_opt (Branch lc llc lk lv lrt)" lemma rbt_min_opt_Branch: "t1 \ rbt.Empty \ rbt_min_opt (Branch c t1 k () t2) = rbt_min_opt t1" by (cases t1) auto lemma rbt_min_opt_induct [case_names empty left_empty left_non_empty]: fixes t :: "('a :: linorder, unit) RBT_Impl.rbt" assumes "P rbt.Empty" assumes "\color t1 a b t2. P t1 \ P t2 \ t1 = rbt.Empty \ P (Branch color t1 a b t2)" assumes "\color t1 a b t2. P t1 \ P t2 \ t1 \ rbt.Empty \ P (Branch color t1 a b t2)" shows "P t" using assms proof (induct t) case Empty then show ?case by simp next case (Branch x1 t1 x3 x4 t2) then show ?case by (cases "t1 = rbt.Empty") simp_all qed lemma rbt_min_opt_in_set: fixes t :: "('a :: linorder, unit) RBT_Impl.rbt" assumes "t \ rbt.Empty" shows "rbt_min_opt t \ set (RBT_Impl.keys t)" using assms by (induction t rule: rbt_min_opt.induct) (auto) lemma rbt_min_opt_is_min: fixes t :: "('a :: linorder, unit) RBT_Impl.rbt" assumes "rbt_sorted t" assumes "t \ rbt.Empty" shows "\y. y \ set (RBT_Impl.keys t) \ y \ rbt_min_opt t" using assms proof (induction t rule: rbt_min_opt_induct) case empty then show ?case by simp next case left_empty then show ?case by (auto intro: key_le_right simp del: rbt_sorted.simps) next case (left_non_empty c t1 k v t2 y) then consider "y = k" | "y \ set (RBT_Impl.keys t1)" | "y \ set (RBT_Impl.keys t2)" by auto then show ?case proof cases case 1 with left_non_empty show ?thesis by (auto simp add: rbt_min_opt_Branch intro: left_le_key rbt_min_opt_in_set) next case 2 with left_non_empty show ?thesis by (auto simp add: rbt_min_opt_Branch) next case y: 3 have "rbt_min_opt t1 \ k" using left_non_empty by (simp add: left_le_key rbt_min_opt_in_set) moreover have "k \ y" using left_non_empty y by (simp add: key_le_right) ultimately show ?thesis using left_non_empty y by (simp add: rbt_min_opt_Branch) qed qed lemma rbt_min_eq_rbt_min_opt: assumes "t \ RBT_Impl.Empty" assumes "is_rbt t" shows "rbt_min t = rbt_min_opt t" proof - from assms have "hd (RBT_Impl.keys t) # tl (RBT_Impl.keys t) = RBT_Impl.keys t" by (cases t) simp_all with assms show ?thesis by (simp add: rbt_min_def rbt_fold1_keys_def rbt_min_opt_is_min Min.set_eq_fold [symmetric] Min_eqI rbt_min_opt_in_set) qed paragraph \maximum\ definition rbt_max :: "('a::linorder, unit) RBT_Impl.rbt \ 'a" where "rbt_max t = rbt_fold1_keys max t" lemma fold_max_triv: fixes k :: "_ :: linorder" shows "(\x\set xs. x \ k) \ List.fold max xs k = k" by (induct xs) (auto simp add: max_def) lemma fold_max_rev_eq: fixes xs :: "('a :: linorder) list" assumes "xs \ []" shows "List.fold max (tl xs) (hd xs) = List.fold max (tl (rev xs)) (hd (rev xs))" using assms by (simp add: Max.set_eq_fold [symmetric]) lemma rbt_max_simps: assumes "is_rbt (Branch c lt k v RBT_Impl.Empty)" shows "rbt_max (Branch c lt k v RBT_Impl.Empty) = k" proof - have "List.fold max (tl (rev(RBT_Impl.keys lt @ [k]))) (hd (rev(RBT_Impl.keys lt @ [k]))) = k" using assms by (auto intro!: fold_max_triv dest!: left_le_key is_rbt_rbt_sorted) then show ?thesis by (auto simp add: rbt_max_def rbt_fold1_keys_def fold_max_rev_eq) qed fun rbt_max_opt where "rbt_max_opt (Branch c lt k v RBT_Impl.Empty) = k" | "rbt_max_opt (Branch c lt k v (Branch rc rlc rk rv rrt)) = rbt_max_opt (Branch rc rlc rk rv rrt)" lemma rbt_max_opt_Branch: "t2 \ rbt.Empty \ rbt_max_opt (Branch c t1 k () t2) = rbt_max_opt t2" by (cases t2) auto lemma rbt_max_opt_induct [case_names empty right_empty right_non_empty]: fixes t :: "('a :: linorder, unit) RBT_Impl.rbt" assumes "P rbt.Empty" assumes "\color t1 a b t2. P t1 \ P t2 \ t2 = rbt.Empty \ P (Branch color t1 a b t2)" assumes "\color t1 a b t2. P t1 \ P t2 \ t2 \ rbt.Empty \ P (Branch color t1 a b t2)" shows "P t" using assms proof (induct t) case Empty then show ?case by simp next case (Branch x1 t1 x3 x4 t2) then show ?case by (cases "t2 = rbt.Empty") simp_all qed lemma rbt_max_opt_in_set: fixes t :: "('a :: linorder, unit) RBT_Impl.rbt" assumes "t \ rbt.Empty" shows "rbt_max_opt t \ set (RBT_Impl.keys t)" using assms by (induction t rule: rbt_max_opt.induct) (auto) lemma rbt_max_opt_is_max: fixes t :: "('a :: linorder, unit) RBT_Impl.rbt" assumes "rbt_sorted t" assumes "t \ rbt.Empty" shows "\y. y \ set (RBT_Impl.keys t) \ y \ rbt_max_opt t" using assms proof (induction t rule: rbt_max_opt_induct) case empty then show ?case by simp next case right_empty then show ?case by (auto intro: left_le_key simp del: rbt_sorted.simps) next case (right_non_empty c t1 k v t2 y) then consider "y = k" | "y \ set (RBT_Impl.keys t2)" | "y \ set (RBT_Impl.keys t1)" by auto then show ?case proof cases case 1 with right_non_empty show ?thesis by (auto simp add: rbt_max_opt_Branch intro: key_le_right rbt_max_opt_in_set) next case 2 with right_non_empty show ?thesis by (auto simp add: rbt_max_opt_Branch) next case y: 3 have "rbt_max_opt t2 \ k" using right_non_empty by (simp add: key_le_right rbt_max_opt_in_set) moreover have "y \ k" using right_non_empty y by (simp add: left_le_key) ultimately show ?thesis using right_non_empty by (simp add: rbt_max_opt_Branch) qed qed lemma rbt_max_eq_rbt_max_opt: assumes "t \ RBT_Impl.Empty" assumes "is_rbt t" shows "rbt_max t = rbt_max_opt t" proof - from assms have "hd (RBT_Impl.keys t) # tl (RBT_Impl.keys t) = RBT_Impl.keys t" by (cases t) simp_all with assms show ?thesis by (simp add: rbt_max_def rbt_fold1_keys_def rbt_max_opt_is_max Max.set_eq_fold [symmetric] Max_eqI rbt_max_opt_in_set) qed subsubsection \abstract\ context includes rbt.lifting begin lift_definition fold1_keys :: "('a \ 'a \ 'a) \ ('a::linorder, 'b) rbt \ 'a" is rbt_fold1_keys . lemma fold1_keys_def_alt: "fold1_keys f t = List.fold f (tl (RBT.keys t)) (hd (RBT.keys t))" by transfer (simp add: rbt_fold1_keys_def) lemma finite_fold1_fold1_keys: assumes "semilattice f" assumes "\ RBT.is_empty t" shows "semilattice_set.F f (Set t) = fold1_keys f t" proof - from \semilattice f\ interpret semilattice_set f by (rule semilattice_set.intro) show ?thesis using assms by (auto simp: fold1_keys_def_alt set_keys fold_def_alt non_empty_keys set_eq_fold [symmetric]) qed paragraph \minimum\ lift_definition r_min :: "('a :: linorder, unit) rbt \ 'a" is rbt_min . lift_definition r_min_opt :: "('a :: linorder, unit) rbt \ 'a" is rbt_min_opt . lemma r_min_alt_def: "r_min t = fold1_keys min t" by transfer (simp add: rbt_min_def) lemma r_min_eq_r_min_opt: assumes "\ (RBT.is_empty t)" shows "r_min t = r_min_opt t" using assms unfolding is_empty_empty by transfer (auto intro: rbt_min_eq_rbt_min_opt) lemma fold_keys_min_top_eq: fixes t :: "('a::{linorder,bounded_lattice_top}, unit) rbt" assumes "\ (RBT.is_empty t)" shows "fold_keys min t top = fold1_keys min t" proof - have *: "\t. RBT_Impl.keys t \ [] \ List.fold min (RBT_Impl.keys t) top = List.fold min (hd (RBT_Impl.keys t) # tl (RBT_Impl.keys t)) top" by (simp add: hd_Cons_tl[symmetric]) have **: "List.fold min (x # xs) top = List.fold min xs x" for x :: 'a and xs by (simp add: inf_min[symmetric]) show ?thesis using assms unfolding fold_keys_def_alt fold1_keys_def_alt is_empty_empty apply transfer apply (case_tac t) apply simp apply (subst *) apply simp apply (subst **) apply simp done qed paragraph \maximum\ lift_definition r_max :: "('a :: linorder, unit) rbt \ 'a" is rbt_max . lift_definition r_max_opt :: "('a :: linorder, unit) rbt \ 'a" is rbt_max_opt . lemma r_max_alt_def: "r_max t = fold1_keys max t" by transfer (simp add: rbt_max_def) lemma r_max_eq_r_max_opt: assumes "\ (RBT.is_empty t)" shows "r_max t = r_max_opt t" using assms unfolding is_empty_empty by transfer (auto intro: rbt_max_eq_rbt_max_opt) lemma fold_keys_max_bot_eq: fixes t :: "('a::{linorder,bounded_lattice_bot}, unit) rbt" assumes "\ (RBT.is_empty t)" shows "fold_keys max t bot = fold1_keys max t" proof - have *: "\t. RBT_Impl.keys t \ [] \ List.fold max (RBT_Impl.keys t) bot = List.fold max (hd(RBT_Impl.keys t) # tl(RBT_Impl.keys t)) bot" by (simp add: hd_Cons_tl[symmetric]) have **: "List.fold max (x # xs) bot = List.fold max xs x" for x :: 'a and xs by (simp add: sup_max[symmetric]) show ?thesis using assms unfolding fold_keys_def_alt fold1_keys_def_alt is_empty_empty apply transfer apply (case_tac t) apply simp apply (subst *) apply simp apply (subst **) apply simp done qed end section \Code equations\ code_datatype Set Coset declare list.set[code] (* needed? *) lemma empty_Set [code]: "Set.empty = Set RBT.empty" by (auto simp: Set_def) lemma UNIV_Coset [code]: "UNIV = Coset RBT.empty" by (auto simp: Set_def) lemma is_empty_Set [code]: "Set.is_empty (Set t) = RBT.is_empty t" unfolding Set.is_empty_def by (auto simp: fun_eq_iff Set_def intro: lookup_empty_empty[THEN iffD1]) lemma compl_code [code]: "- Set xs = Coset xs" "- Coset xs = Set xs" by (simp_all add: Set_def) lemma member_code [code]: "x \ (Set t) = (RBT.lookup t x = Some ())" "x \ (Coset t) = (RBT.lookup t x = None)" by (simp_all add: Set_def) lemma insert_code [code]: "Set.insert x (Set t) = Set (RBT.insert x () t)" "Set.insert x (Coset t) = Coset (RBT.delete x t)" by (auto simp: Set_def) lemma remove_code [code]: "Set.remove x (Set t) = Set (RBT.delete x t)" "Set.remove x (Coset t) = Coset (RBT.insert x () t)" by (auto simp: Set_def) lemma union_Set [code]: "Set t \ A = fold_keys Set.insert t A" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) from finite_fold_fold_keys[OF comp_fun_commute_axioms] show ?thesis by (auto simp add: union_fold_insert) qed lemma inter_Set [code]: "A \ Set t = rbt_filter (\k. k \ A) t" by (simp add: inter_Set_filter Set_filter_rbt_filter) lemma minus_Set [code]: "A - Set t = fold_keys Set.remove t A" proof - interpret comp_fun_idem Set.remove by (fact comp_fun_idem_remove) from finite_fold_fold_keys[OF comp_fun_commute_axioms] show ?thesis by (auto simp add: minus_fold_remove) qed lemma union_Coset [code]: "Coset t \ A = - rbt_filter (\k. k \ A) t" proof - have *: "\A B. (-A \ B) = -(-B \ A)" by blast show ?thesis by (simp del: boolean_algebra_class.compl_inf add: * inter_Set) qed lemma union_Set_Set [code]: "Set t1 \ Set t2 = Set (RBT.union t1 t2)" by (auto simp add: lookup_union map_add_Some_iff Set_def) lemma inter_Coset [code]: "A \ Coset t = fold_keys Set.remove t A" by (simp add: Diff_eq [symmetric] minus_Set) lemma inter_Coset_Coset [code]: "Coset t1 \ Coset t2 = Coset (RBT.union t1 t2)" by (auto simp add: lookup_union map_add_Some_iff Set_def) lemma minus_Coset [code]: "A - Coset t = rbt_filter (\k. k \ A) t" by (simp add: inter_Set[simplified Int_commute]) lemma filter_Set [code]: "Set.filter P (Set t) = (rbt_filter P t)" by (auto simp add: Set_filter_rbt_filter) lemma image_Set [code]: "image f (Set t) = fold_keys (\k A. Set.insert (f k) A) t {}" proof - have "comp_fun_commute (\k. Set.insert (f k))" by standard auto then show ?thesis by (auto simp add: image_fold_insert intro!: finite_fold_fold_keys) qed lemma Ball_Set [code]: "Ball (Set t) P \ RBT.foldi (\s. s = True) (\k v s. s \ P k) t True" proof - have "comp_fun_commute (\k s. s \ P k)" by standard auto then show ?thesis by (simp add: foldi_fold_conj[symmetric] Ball_fold finite_fold_fold_keys) qed lemma Bex_Set [code]: "Bex (Set t) P \ RBT.foldi (\s. s = False) (\k v s. s \ P k) t False" proof - have "comp_fun_commute (\k s. s \ P k)" by standard auto then show ?thesis by (simp add: foldi_fold_disj[symmetric] Bex_fold finite_fold_fold_keys) qed lemma subset_code [code]: "Set t \ B \ (\x\Set t. x \ B)" "A \ Coset t \ (\y\Set t. y \ A)" by auto lemma subset_Coset_empty_Set_empty [code]: "Coset t1 \ Set t2 \ (case (RBT.impl_of t1, RBT.impl_of t2) of (rbt.Empty, rbt.Empty) \ False | (_, _) \ Code.abort (STR ''non_empty_trees'') (\_. Coset t1 \ Set t2))" proof - have *: "\t. RBT.impl_of t = rbt.Empty \ t = RBT rbt.Empty" by (subst(asm) RBT_inverse[symmetric]) (auto simp: impl_of_inject) have **: "eq_onp is_rbt rbt.Empty rbt.Empty" unfolding eq_onp_def by simp show ?thesis by (auto simp: Set_def lookup.abs_eq[OF **] dest!: * split: rbt.split) qed text \A frequent case -- avoid intermediate sets\ lemma [code_unfold]: "Set t1 \ Set t2 \ RBT.foldi (\s. s = True) (\k v s. s \ k \ Set t2) t1 True" by (simp add: subset_code Ball_Set) lemma card_Set [code]: "card (Set t) = fold_keys (\_ n. n + 1) t 0" by (auto simp add: card.eq_fold intro: finite_fold_fold_keys comp_fun_commute_const) lemma sum_Set [code]: "sum f (Set xs) = fold_keys (plus \ f) xs 0" proof - have "comp_fun_commute (\x. (+) (f x))" by standard (auto simp: ac_simps) then show ?thesis by (auto simp add: sum.eq_fold finite_fold_fold_keys o_def) qed lemma the_elem_set [code]: fixes t :: "('a :: linorder, unit) rbt" shows "the_elem (Set t) = (case RBT.impl_of t of (Branch RBT_Impl.B RBT_Impl.Empty x () RBT_Impl.Empty) \ x | _ \ Code.abort (STR ''not_a_singleton_tree'') (\_. the_elem (Set t)))" proof - { fix x :: "'a :: linorder" let ?t = "Branch RBT_Impl.B RBT_Impl.Empty x () RBT_Impl.Empty" have *:"?t \ {t. is_rbt t}" unfolding is_rbt_def by auto then have **:"eq_onp is_rbt ?t ?t" unfolding eq_onp_def by auto have "RBT.impl_of t = ?t \ the_elem (Set t) = x" by (subst(asm) RBT_inverse[symmetric, OF *]) (auto simp: Set_def the_elem_def lookup.abs_eq[OF **] impl_of_inject) } then show ?thesis by(auto split: rbt.split unit.split color.split) qed lemma Pow_Set [code]: "Pow (Set t) = fold_keys (\x A. A \ Set.insert x ` A) t {{}}" by (simp add: Pow_fold finite_fold_fold_keys[OF comp_fun_commute_Pow_fold]) lemma product_Set [code]: "Product_Type.product (Set t1) (Set t2) = fold_keys (\x A. fold_keys (\y. Set.insert (x, y)) t2 A) t1 {}" proof - have *: "comp_fun_commute (\y. Set.insert (x, y))" for x by standard auto show ?thesis using finite_fold_fold_keys[OF comp_fun_commute_product_fold, of "Set t2" "{}" "t1"] by (simp add: product_fold Product_Type.product_def finite_fold_fold_keys[OF *]) qed lemma Id_on_Set [code]: "Id_on (Set t) = fold_keys (\x. Set.insert (x, x)) t {}" proof - have "comp_fun_commute (\x. Set.insert (x, x))" by standard auto then show ?thesis by (auto simp add: Id_on_fold intro!: finite_fold_fold_keys) qed lemma Image_Set [code]: "(Set t) `` S = fold_keys (\(x,y) A. if x \ S then Set.insert y A else A) t {}" by (auto simp add: Image_fold finite_fold_fold_keys[OF comp_fun_commute_Image_fold]) lemma trancl_set_ntrancl [code]: "trancl (Set t) = ntrancl (card (Set t) - 1) (Set t)" by (simp add: finite_trancl_ntranl) lemma relcomp_Set[code]: "(Set t1) O (Set t2) = fold_keys (\(x,y) A. fold_keys (\(w,z) A'. if y = w then Set.insert (x,z) A' else A') t2 A) t1 {}" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) have *: "\x y. comp_fun_commute (\(w, z) A'. if y = w then Set.insert (x, z) A' else A')" by standard (auto simp add: fun_eq_iff) show ?thesis using finite_fold_fold_keys[OF comp_fun_commute_relcomp_fold, of "Set t2" "{}" t1] by (simp add: relcomp_fold finite_fold_fold_keys[OF *]) qed lemma wf_set [code]: "wf (Set t) = acyclic (Set t)" by (simp add: wf_iff_acyclic_if_finite) lemma Min_fin_set_fold [code]: "Min (Set t) = (if RBT.is_empty t then Code.abort (STR ''not_non_empty_tree'') (\_. Min (Set t)) else r_min_opt t)" proof - have *: "semilattice (min :: 'a \ 'a \ 'a)" .. with finite_fold1_fold1_keys [OF *, folded Min_def] show ?thesis by (simp add: r_min_alt_def r_min_eq_r_min_opt [symmetric]) qed lemma Inf_fin_set_fold [code]: "Inf_fin (Set t) = Min (Set t)" by (simp add: inf_min Inf_fin_def Min_def) lemma Inf_Set_fold: fixes t :: "('a :: {linorder, complete_lattice}, unit) rbt" shows "Inf (Set t) = (if RBT.is_empty t then top else r_min_opt t)" proof - have "comp_fun_commute (min :: 'a \ 'a \ 'a)" by standard (simp add: fun_eq_iff ac_simps) then have "t \ RBT.empty \ Finite_Set.fold min top (Set t) = fold1_keys min t" by (simp add: finite_fold_fold_keys fold_keys_min_top_eq) then show ?thesis by (auto simp add: Inf_fold_inf inf_min empty_Set[symmetric] r_min_eq_r_min_opt[symmetric] r_min_alt_def) qed lemma Max_fin_set_fold [code]: "Max (Set t) = (if RBT.is_empty t then Code.abort (STR ''not_non_empty_tree'') (\_. Max (Set t)) else r_max_opt t)" proof - have *: "semilattice (max :: 'a \ 'a \ 'a)" .. with finite_fold1_fold1_keys [OF *, folded Max_def] show ?thesis by (simp add: r_max_alt_def r_max_eq_r_max_opt [symmetric]) qed lemma Sup_fin_set_fold [code]: "Sup_fin (Set t) = Max (Set t)" by (simp add: sup_max Sup_fin_def Max_def) lemma Sup_Set_fold: fixes t :: "('a :: {linorder, complete_lattice}, unit) rbt" shows "Sup (Set t) = (if RBT.is_empty t then bot else r_max_opt t)" proof - have "comp_fun_commute (max :: 'a \ 'a \ 'a)" by standard (simp add: fun_eq_iff ac_simps) then have "t \ RBT.empty \ Finite_Set.fold max bot (Set t) = fold1_keys max t" by (simp add: finite_fold_fold_keys fold_keys_max_bot_eq) then show ?thesis by (auto simp add: Sup_fold_sup sup_max empty_Set[symmetric] r_max_eq_r_max_opt[symmetric] r_max_alt_def) qed context begin qualified definition Inf' :: "'a :: {linorder, complete_lattice} set \ 'a" where [code_abbrev]: "Inf' = Inf" lemma Inf'_Set_fold [code]: "Inf' (Set t) = (if RBT.is_empty t then top else r_min_opt t)" by (simp add: Inf'_def Inf_Set_fold) qualified definition Sup' :: "'a :: {linorder, complete_lattice} set \ 'a" where [code_abbrev]: "Sup' = Sup" lemma Sup'_Set_fold [code]: "Sup' (Set t) = (if RBT.is_empty t then bot else r_max_opt t)" by (simp add: Sup'_def Sup_Set_fold) lemma [code drop: Gcd_fin, code]: "Gcd\<^sub>f\<^sub>i\<^sub>n (Set t) = fold_keys gcd t (0::'a::{semiring_gcd, linorder})" proof - have "comp_fun_commute (gcd :: 'a \ _)" by standard (simp add: fun_eq_iff ac_simps) with finite_fold_fold_keys [of _ 0 t] have "Finite_Set.fold gcd 0 (Set t) = fold_keys gcd t 0" by blast then show ?thesis by (simp add: Gcd_fin.eq_fold) qed lemma [code drop: "Gcd :: _ \ nat", code]: "Gcd (Set t) = (Gcd\<^sub>f\<^sub>i\<^sub>n (Set t) :: nat)" by simp lemma [code drop: "Gcd :: _ \ int", code]: "Gcd (Set t) = (Gcd\<^sub>f\<^sub>i\<^sub>n (Set t) :: int)" by simp lemma [code drop: Lcm_fin,code]: "Lcm\<^sub>f\<^sub>i\<^sub>n (Set t) = fold_keys lcm t (1::'a::{semiring_gcd, linorder})" proof - have "comp_fun_commute (lcm :: 'a \ _)" by standard (simp add: fun_eq_iff ac_simps) with finite_fold_fold_keys [of _ 1 t] have "Finite_Set.fold lcm 1 (Set t) = fold_keys lcm t 1" by blast then show ?thesis by (simp add: Lcm_fin.eq_fold) qed qualified definition Lcm' :: "'a :: semiring_Gcd set \ 'a" where [code_abbrev]: "Lcm' = Lcm" lemma [code drop: "Lcm :: _ \ nat", code]: "Lcm (Set t) = (Lcm\<^sub>f\<^sub>i\<^sub>n (Set t) :: nat)" by simp lemma [code drop: "Lcm :: _ \ int", code]: "Lcm (Set t) = (Lcm\<^sub>f\<^sub>i\<^sub>n (Set t) :: int)" by simp end lemma sorted_list_set[code]: "sorted_list_of_set (Set t) = RBT.keys t" by (auto simp add: set_keys intro: sorted_distinct_set_unique) lemma Bleast_code [code]: "Bleast (Set t) P = (case List.filter P (RBT.keys t) of x # xs \ x | [] \ abort_Bleast (Set t) P)" proof (cases "List.filter P (RBT.keys t)") case Nil thus ?thesis by (simp add: Bleast_def abort_Bleast_def) next case (Cons x ys) have "(LEAST x. x \ Set t \ P x) = x" proof (rule Least_equality) show "x \ Set t \ P x" using Cons[symmetric] by (auto simp add: set_keys Cons_eq_filter_iff) next fix y assume "y \ Set t \ P y" then show "x \ y" using Cons[symmetric] by(auto simp add: set_keys Cons_eq_filter_iff) (metis sorted_wrt.simps(2) sorted_append sorted_keys) qed thus ?thesis using Cons by (simp add: Bleast_def) qed hide_const (open) RBT_Set.Set RBT_Set.Coset end diff --git a/src/HOL/Lifting_Set.thy b/src/HOL/Lifting_Set.thy --- a/src/HOL/Lifting_Set.thy +++ b/src/HOL/Lifting_Set.thy @@ -1,332 +1,372 @@ (* Title: HOL/Lifting_Set.thy Author: Brian Huffman and Ondrej Kuncar *) section \Setup for Lifting/Transfer for the set type\ theory Lifting_Set imports Lifting begin subsection \Relator and predicator properties\ lemma rel_setD1: "\ rel_set R A B; x \ A \ \ \y \ B. R x y" and rel_setD2: "\ rel_set R A B; y \ B \ \ \x \ A. R x y" by (simp_all add: rel_set_def) lemma rel_set_conversep [simp]: "rel_set A\\ = (rel_set A)\\" unfolding rel_set_def by auto lemma rel_set_eq [relator_eq]: "rel_set (=) = (=)" unfolding rel_set_def fun_eq_iff by auto lemma rel_set_mono[relator_mono]: assumes "A \ B" shows "rel_set A \ rel_set B" using assms unfolding rel_set_def by blast lemma rel_set_OO[relator_distr]: "rel_set R OO rel_set S = rel_set (R OO S)" apply (rule sym) apply (intro ext) subgoal for X Z apply (rule iffI) apply (rule relcomppI [where b="{y. (\x\X. R x y) \ (\z\Z. S y z)}"]) apply (simp add: rel_set_def, fast)+ done done lemma Domainp_set[relator_domain]: "Domainp (rel_set T) = (\A. Ball A (Domainp T))" unfolding rel_set_def Domainp_iff[abs_def] apply (intro ext) apply (rule iffI) apply blast subgoal for A by (rule exI [where x="{y. \x\A. T x y}"]) fast done lemma left_total_rel_set[transfer_rule]: "left_total A \ left_total (rel_set A)" unfolding left_total_def rel_set_def apply safe subgoal for X by (rule exI [where x="{y. \x\X. A x y}"]) fast done lemma left_unique_rel_set[transfer_rule]: "left_unique A \ left_unique (rel_set A)" unfolding left_unique_def rel_set_def by fast lemma right_total_rel_set [transfer_rule]: "right_total A \ right_total (rel_set A)" using left_total_rel_set[of "A\\"] by simp lemma right_unique_rel_set [transfer_rule]: "right_unique A \ right_unique (rel_set A)" unfolding right_unique_def rel_set_def by fast lemma bi_total_rel_set [transfer_rule]: "bi_total A \ bi_total (rel_set A)" by(simp add: bi_total_alt_def left_total_rel_set right_total_rel_set) lemma bi_unique_rel_set [transfer_rule]: "bi_unique A \ bi_unique (rel_set A)" unfolding bi_unique_def rel_set_def by fast lemma set_relator_eq_onp [relator_eq_onp]: "rel_set (eq_onp P) = eq_onp (\A. Ball A P)" unfolding fun_eq_iff rel_set_def eq_onp_def Ball_def by fast lemma bi_unique_rel_set_lemma: assumes "bi_unique R" and "rel_set R X Y" obtains f where "Y = image f X" and "inj_on f X" and "\x\X. R x (f x)" proof define f where "f x = (THE y. R x y)" for x { fix x assume "x \ X" with \rel_set R X Y\ \bi_unique R\ have "R x (f x)" by (simp add: bi_unique_def rel_set_def f_def) (metis theI) with assms \x \ X\ have "R x (f x)" "\x'\X. R x' (f x) \ x = x'" "\y\Y. R x y \ y = f x" "f x \ Y" by (fastforce simp add: bi_unique_def rel_set_def)+ } note * = this moreover { fix y assume "y \ Y" with \rel_set R X Y\ *(3) \y \ Y\ have "\x\X. y = f x" by (fastforce simp: rel_set_def) } ultimately show "\x\X. R x (f x)" "Y = image f X" "inj_on f X" by (auto simp: inj_on_def image_iff) qed subsection \Quotient theorem for the Lifting package\ lemma Quotient_set[quot_map]: assumes "Quotient R Abs Rep T" shows "Quotient (rel_set R) (image Abs) (image Rep) (rel_set T)" using assms unfolding Quotient_alt_def4 apply (simp add: rel_set_OO[symmetric]) apply (simp add: rel_set_def) apply fast done subsection \Transfer rules for the Transfer package\ subsubsection \Unconditional transfer rules\ context includes lifting_syntax begin lemma empty_transfer [transfer_rule]: "(rel_set A) {} {}" unfolding rel_set_def by simp lemma insert_transfer [transfer_rule]: "(A ===> rel_set A ===> rel_set A) insert insert" unfolding rel_fun_def rel_set_def by auto lemma union_transfer [transfer_rule]: "(rel_set A ===> rel_set A ===> rel_set A) union union" unfolding rel_fun_def rel_set_def by auto lemma Union_transfer [transfer_rule]: "(rel_set (rel_set A) ===> rel_set A) Union Union" unfolding rel_fun_def rel_set_def by simp fast lemma image_transfer [transfer_rule]: "((A ===> B) ===> rel_set A ===> rel_set B) image image" unfolding rel_fun_def rel_set_def by simp fast lemma UNION_transfer [transfer_rule]: \ \TODO deletion candidate\ "(rel_set A ===> (A ===> rel_set B) ===> rel_set B) (\A f. \(f ` A)) (\A f. \(f ` A))" by transfer_prover lemma Ball_transfer [transfer_rule]: "(rel_set A ===> (A ===> (=)) ===> (=)) Ball Ball" unfolding rel_set_def rel_fun_def by fast lemma Bex_transfer [transfer_rule]: "(rel_set A ===> (A ===> (=)) ===> (=)) Bex Bex" unfolding rel_set_def rel_fun_def by fast lemma Pow_transfer [transfer_rule]: "(rel_set A ===> rel_set (rel_set A)) Pow Pow" apply (rule rel_funI) apply (rule rel_setI) subgoal for X Y X' apply (rule rev_bexI [where x="{y\Y. \x\X'. A x y}"]) apply clarsimp apply (simp add: rel_set_def) apply fast done subgoal for X Y Y' apply (rule rev_bexI [where x="{x\X. \y\Y'. A x y}"]) apply clarsimp apply (simp add: rel_set_def) apply fast done done lemma rel_set_transfer [transfer_rule]: "((A ===> B ===> (=)) ===> rel_set A ===> rel_set B ===> (=)) rel_set rel_set" unfolding rel_fun_def rel_set_def by fast lemma bind_transfer [transfer_rule]: "(rel_set A ===> (A ===> rel_set B) ===> rel_set B) Set.bind Set.bind" unfolding bind_UNION [abs_def] by transfer_prover lemma INF_parametric [transfer_rule]: \ \TODO deletion candidate\ "(rel_set A ===> (A ===> HOL.eq) ===> HOL.eq) (\A f. Inf (f ` A)) (\A f. Inf (f ` A))" by transfer_prover lemma SUP_parametric [transfer_rule]: \ \TODO deletion candidate\ "(rel_set R ===> (R ===> HOL.eq) ===> HOL.eq) (\A f. Sup (f ` A)) (\A f. Sup (f ` A))" by transfer_prover subsubsection \Rules requiring bi-unique, bi-total or right-total relations\ lemma member_transfer [transfer_rule]: assumes "bi_unique A" shows "(A ===> rel_set A ===> (=)) (\) (\)" using assms unfolding rel_fun_def rel_set_def bi_unique_def by fast lemma right_total_Collect_transfer[transfer_rule]: assumes "right_total A" shows "((A ===> (=)) ===> rel_set A) (\P. Collect (\x. P x \ Domainp A x)) Collect" using assms unfolding right_total_def rel_set_def rel_fun_def Domainp_iff by fast lemma Collect_transfer [transfer_rule]: assumes "bi_total A" shows "((A ===> (=)) ===> rel_set A) Collect Collect" using assms unfolding rel_fun_def rel_set_def bi_total_def by fast lemma inter_transfer [transfer_rule]: assumes "bi_unique A" shows "(rel_set A ===> rel_set A ===> rel_set A) inter inter" using assms unfolding rel_fun_def rel_set_def bi_unique_def by fast lemma Diff_transfer [transfer_rule]: assumes "bi_unique A" shows "(rel_set A ===> rel_set A ===> rel_set A) (-) (-)" using assms unfolding rel_fun_def rel_set_def bi_unique_def unfolding Ball_def Bex_def Diff_eq by (safe, simp, metis, simp, metis) lemma subset_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(rel_set A ===> rel_set A ===> (=)) (\) (\)" unfolding subset_eq [abs_def] by transfer_prover context includes lifting_syntax begin lemma strict_subset_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(rel_set A ===> rel_set A ===> (=)) (\) (\)" unfolding subset_not_subset_eq by transfer_prover end declare right_total_UNIV_transfer[transfer_rule] lemma UNIV_transfer [transfer_rule]: assumes "bi_total A" shows "(rel_set A) UNIV UNIV" using assms unfolding rel_set_def bi_total_def by simp lemma right_total_Compl_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" and [transfer_rule]: "right_total A" shows "(rel_set A ===> rel_set A) (\S. uminus S \ Collect (Domainp A)) uminus" unfolding Compl_eq [abs_def] by (subst Collect_conj_eq[symmetric]) transfer_prover lemma Compl_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" and [transfer_rule]: "bi_total A" shows "(rel_set A ===> rel_set A) uminus uminus" unfolding Compl_eq [abs_def] by transfer_prover lemma right_total_Inter_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" and [transfer_rule]: "right_total A" shows "(rel_set (rel_set A) ===> rel_set A) (\S. \S \ Collect (Domainp A)) Inter" unfolding Inter_eq[abs_def] by (subst Collect_conj_eq[symmetric]) transfer_prover lemma Inter_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" and [transfer_rule]: "bi_total A" shows "(rel_set (rel_set A) ===> rel_set A) Inter Inter" unfolding Inter_eq [abs_def] by transfer_prover lemma filter_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "((A ===> (=)) ===> rel_set A ===> rel_set A) Set.filter Set.filter" unfolding Set.filter_def[abs_def] rel_fun_def rel_set_def by blast lemma finite_transfer [transfer_rule]: "bi_unique A \ (rel_set A ===> (=)) finite finite" by (rule rel_funI, erule (1) bi_unique_rel_set_lemma) (auto dest: finite_imageD) lemma card_transfer [transfer_rule]: "bi_unique A \ (rel_set A ===> (=)) card card" by (rule rel_funI, erule (1) bi_unique_rel_set_lemma) (simp add: card_image) context includes lifting_syntax begin lemma vimage_right_total_transfer[transfer_rule]: assumes [transfer_rule]: "bi_unique B" "right_total A" shows "((A ===> B) ===> rel_set B ===> rel_set A) (\f X. f -` X \ Collect (Domainp A)) vimage" proof - let ?vimage = "(\f B. {x. f x \ B \ Domainp A x})" have "((A ===> B) ===> rel_set B ===> rel_set A) ?vimage vimage" unfolding vimage_def by transfer_prover also have "?vimage = (\f X. f -` X \ Collect (Domainp A))" by auto finally show ?thesis . qed end lemma vimage_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total A" "bi_unique B" shows "((A ===> B) ===> rel_set B ===> rel_set A) vimage vimage" unfolding vimage_def[abs_def] by transfer_prover lemma Image_parametric [transfer_rule]: assumes "bi_unique A" shows "(rel_set (rel_prod A B) ===> rel_set A ===> rel_set B) (``) (``)" by (intro rel_funI rel_setI) (force dest: rel_setD1 bi_uniqueDr[OF assms], force dest: rel_setD2 bi_uniqueDl[OF assms]) lemma inj_on_transfer[transfer_rule]: "((A ===> B) ===> rel_set A ===> (=)) inj_on inj_on" if [transfer_rule]: "bi_unique A" "bi_unique B" unfolding inj_on_def by transfer_prover end lemma (in comm_monoid_set) F_parametric [transfer_rule]: fixes A :: "'b \ 'c \ bool" assumes "bi_unique A" shows "rel_fun (rel_fun A (=)) (rel_fun (rel_set A) (=)) F F" proof (rule rel_funI)+ fix f :: "'b \ 'a" and g S T assume "rel_fun A (=) f g" "rel_set A S T" with \bi_unique A\ obtain i where "bij_betw i S T" "\x. x \ S \ f x = g (i x)" by (auto elim: bi_unique_rel_set_lemma simp: rel_fun_def bij_betw_def) then show "F f S = F g T" by (simp add: reindex_bij_betw) qed lemmas sum_parametric = sum.F_parametric lemmas prod_parametric = prod.F_parametric lemma rel_set_UNION: assumes [transfer_rule]: "rel_set Q A B" "rel_fun Q (rel_set R) f g" shows "rel_set R (\(f ` A)) (\(g ` B))" by transfer_prover +context + includes lifting_syntax +begin + +lemma fold_graph_transfer[transfer_rule]: + assumes "bi_unique R" "right_total R" + shows "((R ===> (=) ===> (=)) ===> (=) ===> rel_set R ===> (=) ===> (=)) fold_graph fold_graph" +proof(intro rel_funI) + fix f1 :: "'a \ 'c \ 'c" and f2 :: "'b \ 'c \ 'c" + assume rel_f: "(R ===> (=) ===> (=)) f1 f2" + fix z1 z2 :: 'c assume [simp]: "z1 = z2" + fix A1 A2 assume rel_A: "rel_set R A1 A2" + fix y1 y2 :: 'c assume [simp]: "y1 = y2" + + from \bi_unique R\ \right_total R\ have The_y: "\y. \!x. R x y" + unfolding bi_unique_def right_total_def by auto + define r where "r \ \y. THE x. R x y" + + from The_y have r_y: "R (r y) y" for y + unfolding r_def using the_equality by fastforce + with assms rel_A have "inj_on r A2" "A1 = r ` A2" + unfolding r_def rel_set_def inj_on_def bi_unique_def + apply(auto simp: image_iff) by metis+ + with \bi_unique R\ rel_f r_y have "(f1 o r) y = f2 y" for y + unfolding bi_unique_def rel_fun_def by auto + then have "(f1 o r) = f2" + by blast + then show "fold_graph f1 z1 A1 y1 = fold_graph f2 z2 A2 y2" + by (fastforce simp: fold_graph_image[OF \inj_on r A2\] \A1 = r ` A2\) +qed + +lemma fold_transfer[transfer_rule]: + assumes [transfer_rule]: "bi_unique R" "right_total R" + shows "((R ===> (=) ===> (=)) ===> (=) ===> rel_set R ===> (=)) Finite_Set.fold Finite_Set.fold" + unfolding Finite_Set.fold_def + by transfer_prover + end + + +end diff --git a/src/HOL/List.thy b/src/HOL/List.thy --- a/src/HOL/List.thy +++ b/src/HOL/List.thy @@ -1,8217 +1,8327 @@ (* Title: HOL/List.thy Author: Tobias Nipkow; proofs tidied by LCP *) section \The datatype of finite lists\ theory List imports Sledgehammer Code_Numeral Lifting_Set begin datatype (set: 'a) list = Nil ("[]") | Cons (hd: 'a) (tl: "'a list") (infixr "#" 65) for map: map rel: list_all2 pred: list_all where "tl [] = []" datatype_compat list lemma [case_names Nil Cons, cases type: list]: \ \for backward compatibility -- names of variables differ\ "(y = [] \ P) \ (\a list. y = a # list \ P) \ P" by (rule list.exhaust) lemma [case_names Nil Cons, induct type: list]: \ \for backward compatibility -- names of variables differ\ "P [] \ (\a list. P list \ P (a # list)) \ P list" by (rule list.induct) text \Compatibility:\ setup \Sign.mandatory_path "list"\ lemmas inducts = list.induct lemmas recs = list.rec lemmas cases = list.case setup \Sign.parent_path\ lemmas set_simps = list.set (* legacy *) syntax \ \list Enumeration\ "_list" :: "args => 'a list" ("[(_)]") translations "[x, xs]" == "x#[xs]" "[x]" == "x#[]" subsection \Basic list processing functions\ primrec (nonexhaustive) last :: "'a list \ 'a" where "last (x # xs) = (if xs = [] then x else last xs)" primrec butlast :: "'a list \ 'a list" where "butlast [] = []" | "butlast (x # xs) = (if xs = [] then [] else x # butlast xs)" lemma set_rec: "set xs = rec_list {} (\x _. insert x) xs" by (induct xs) auto definition coset :: "'a list \ 'a set" where [simp]: "coset xs = - set xs" primrec append :: "'a list \ 'a list \ 'a list" (infixr "@" 65) where append_Nil: "[] @ ys = ys" | append_Cons: "(x#xs) @ ys = x # xs @ ys" primrec rev :: "'a list \ 'a list" where "rev [] = []" | "rev (x # xs) = rev xs @ [x]" primrec filter:: "('a \ bool) \ 'a list \ 'a list" where "filter P [] = []" | "filter P (x # xs) = (if P x then x # filter P xs else filter P xs)" text \Special input syntax for filter:\ syntax (ASCII) "_filter" :: "[pttrn, 'a list, bool] => 'a list" ("(1[_<-_./ _])") syntax "_filter" :: "[pttrn, 'a list, bool] => 'a list" ("(1[_\_ ./ _])") translations "[x<-xs . P]" \ "CONST filter (\x. P) xs" primrec fold :: "('a \ 'b \ 'b) \ 'a list \ 'b \ 'b" where fold_Nil: "fold f [] = id" | fold_Cons: "fold f (x # xs) = fold f xs \ f x" primrec foldr :: "('a \ 'b \ 'b) \ 'a list \ 'b \ 'b" where foldr_Nil: "foldr f [] = id" | foldr_Cons: "foldr f (x # xs) = f x \ foldr f xs" primrec foldl :: "('b \ 'a \ 'b) \ 'b \ 'a list \ 'b" where foldl_Nil: "foldl f a [] = a" | foldl_Cons: "foldl f a (x # xs) = foldl f (f a x) xs" primrec concat:: "'a list list \ 'a list" where "concat [] = []" | "concat (x # xs) = x @ concat xs" primrec drop:: "nat \ 'a list \ 'a list" where drop_Nil: "drop n [] = []" | drop_Cons: "drop n (x # xs) = (case n of 0 \ x # xs | Suc m \ drop m xs)" \ \Warning: simpset does not contain this definition, but separate theorems for \n = 0\ and \n = Suc k\\ primrec take:: "nat \ 'a list \ 'a list" where take_Nil:"take n [] = []" | take_Cons: "take n (x # xs) = (case n of 0 \ [] | Suc m \ x # take m xs)" \ \Warning: simpset does not contain this definition, but separate theorems for \n = 0\ and \n = Suc k\\ primrec (nonexhaustive) nth :: "'a list => nat => 'a" (infixl "!" 100) where nth_Cons: "(x # xs) ! n = (case n of 0 \ x | Suc k \ xs ! k)" \ \Warning: simpset does not contain this definition, but separate theorems for \n = 0\ and \n = Suc k\\ primrec list_update :: "'a list \ nat \ 'a \ 'a list" where "list_update [] i v = []" | "list_update (x # xs) i v = (case i of 0 \ v # xs | Suc j \ x # list_update xs j v)" nonterminal lupdbinds and lupdbind syntax "_lupdbind":: "['a, 'a] => lupdbind" ("(2_ :=/ _)") "" :: "lupdbind => lupdbinds" ("_") "_lupdbinds" :: "[lupdbind, lupdbinds] => lupdbinds" ("_,/ _") "_LUpdate" :: "['a, lupdbinds] => 'a" ("_/[(_)]" [1000,0] 900) translations "_LUpdate xs (_lupdbinds b bs)" == "_LUpdate (_LUpdate xs b) bs" "xs[i:=x]" == "CONST list_update xs i x" primrec takeWhile :: "('a \ bool) \ 'a list \ 'a list" where "takeWhile P [] = []" | "takeWhile P (x # xs) = (if P x then x # takeWhile P xs else [])" primrec dropWhile :: "('a \ bool) \ 'a list \ 'a list" where "dropWhile P [] = []" | "dropWhile P (x # xs) = (if P x then dropWhile P xs else x # xs)" primrec zip :: "'a list \ 'b list \ ('a \ 'b) list" where "zip xs [] = []" | zip_Cons: "zip xs (y # ys) = (case xs of [] \ [] | z # zs \ (z, y) # zip zs ys)" \ \Warning: simpset does not contain this definition, but separate theorems for \xs = []\ and \xs = z # zs\\ abbreviation map2 :: "('a \ 'b \ 'c) \ 'a list \ 'b list \ 'c list" where "map2 f xs ys \ map (\(x,y). f x y) (zip xs ys)" primrec product :: "'a list \ 'b list \ ('a \ 'b) list" where "product [] _ = []" | "product (x#xs) ys = map (Pair x) ys @ product xs ys" hide_const (open) product primrec product_lists :: "'a list list \ 'a list list" where "product_lists [] = [[]]" | "product_lists (xs # xss) = concat (map (\x. map (Cons x) (product_lists xss)) xs)" primrec upt :: "nat \ nat \ nat list" ("(1[_.. j then [i.. 'a list \ 'a list" where "insert x xs = (if x \ set xs then xs else x # xs)" definition union :: "'a list \ 'a list \ 'a list" where "union = fold insert" hide_const (open) insert union hide_fact (open) insert_def union_def primrec find :: "('a \ bool) \ 'a list \ 'a option" where "find _ [] = None" | "find P (x#xs) = (if P x then Some x else find P xs)" text \In the context of multisets, \count_list\ is equivalent to \<^term>\count \ mset\ and it it advisable to use the latter.\ primrec count_list :: "'a list \ 'a \ nat" where "count_list [] y = 0" | "count_list (x#xs) y = (if x=y then count_list xs y + 1 else count_list xs y)" definition "extract" :: "('a \ bool) \ 'a list \ ('a list * 'a * 'a list) option" where "extract P xs = (case dropWhile (Not \ P) xs of [] \ None | y#ys \ Some(takeWhile (Not \ P) xs, y, ys))" hide_const (open) "extract" primrec those :: "'a option list \ 'a list option" where "those [] = Some []" | "those (x # xs) = (case x of None \ None | Some y \ map_option (Cons y) (those xs))" primrec remove1 :: "'a \ 'a list \ 'a list" where "remove1 x [] = []" | "remove1 x (y # xs) = (if x = y then xs else y # remove1 x xs)" primrec removeAll :: "'a \ 'a list \ 'a list" where "removeAll x [] = []" | "removeAll x (y # xs) = (if x = y then removeAll x xs else y # removeAll x xs)" primrec distinct :: "'a list \ bool" where "distinct [] \ True" | "distinct (x # xs) \ x \ set xs \ distinct xs" fun successively :: "('a \ 'a \ bool) \ 'a list \ bool" where "successively P [] = True" | "successively P [x] = True" | "successively P (x # y # xs) = (P x y \ successively P (y#xs))" definition distinct_adj where "distinct_adj = successively (\)" primrec remdups :: "'a list \ 'a list" where "remdups [] = []" | "remdups (x # xs) = (if x \ set xs then remdups xs else x # remdups xs)" fun remdups_adj :: "'a list \ 'a list" where "remdups_adj [] = []" | "remdups_adj [x] = [x]" | "remdups_adj (x # y # xs) = (if x = y then remdups_adj (x # xs) else x # remdups_adj (y # xs))" primrec replicate :: "nat \ 'a \ 'a list" where replicate_0: "replicate 0 x = []" | replicate_Suc: "replicate (Suc n) x = x # replicate n x" text \ Function \size\ is overloaded for all datatypes. Users may refer to the list version as \length\.\ abbreviation length :: "'a list \ nat" where "length \ size" definition enumerate :: "nat \ 'a list \ (nat \ 'a) list" where enumerate_eq_zip: "enumerate n xs = zip [n.. 'a list" where "rotate1 [] = []" | "rotate1 (x # xs) = xs @ [x]" definition rotate :: "nat \ 'a list \ 'a list" where "rotate n = rotate1 ^^ n" definition nths :: "'a list => nat set => 'a list" where "nths xs A = map fst (filter (\p. snd p \ A) (zip xs [0.. 'a list list" where "subseqs [] = [[]]" | "subseqs (x#xs) = (let xss = subseqs xs in map (Cons x) xss @ xss)" primrec n_lists :: "nat \ 'a list \ 'a list list" where "n_lists 0 xs = [[]]" | "n_lists (Suc n) xs = concat (map (\ys. map (\y. y # ys) xs) (n_lists n xs))" hide_const (open) n_lists function splice :: "'a list \ 'a list \ 'a list" where "splice [] ys = ys" | "splice (x#xs) ys = x # splice ys xs" by pat_completeness auto termination by(relation "measure(\(xs,ys). size xs + size ys)") auto function shuffles where "shuffles [] ys = {ys}" | "shuffles xs [] = {xs}" | "shuffles (x # xs) (y # ys) = (#) x ` shuffles xs (y # ys) \ (#) y ` shuffles (x # xs) ys" by pat_completeness simp_all termination by lexicographic_order text\Use only if you cannot use \<^const>\Min\ instead:\ fun min_list :: "'a::ord list \ 'a" where "min_list (x # xs) = (case xs of [] \ x | _ \ min x (min_list xs))" text\Returns first minimum:\ fun arg_min_list :: "('a \ ('b::linorder)) \ 'a list \ 'a" where "arg_min_list f [x] = x" | "arg_min_list f (x#y#zs) = (let m = arg_min_list f (y#zs) in if f x \ f m then x else m)" text\ \begin{figure}[htbp] \fbox{ \begin{tabular}{l} @{lemma "[a,b]@[c,d] = [a,b,c,d]" by simp}\\ @{lemma "length [a,b,c] = 3" by simp}\\ @{lemma "set [a,b,c] = {a,b,c}" by simp}\\ @{lemma "map f [a,b,c] = [f a, f b, f c]" by simp}\\ @{lemma "rev [a,b,c] = [c,b,a]" by simp}\\ @{lemma "hd [a,b,c,d] = a" by simp}\\ @{lemma "tl [a,b,c,d] = [b,c,d]" by simp}\\ @{lemma "last [a,b,c,d] = d" by simp}\\ @{lemma "butlast [a,b,c,d] = [a,b,c]" by simp}\\ @{lemma[source] "filter (\n::nat. n<2) [0,2,1] = [0,1]" by simp}\\ @{lemma "concat [[a,b],[c,d,e],[],[f]] = [a,b,c,d,e,f]" by simp}\\ @{lemma "fold f [a,b,c] x = f c (f b (f a x))" by simp}\\ @{lemma "foldr f [a,b,c] x = f a (f b (f c x))" by simp}\\ @{lemma "foldl f x [a,b,c] = f (f (f x a) b) c" by simp}\\ @{lemma "successively (\) [True,False,True,False]" by simp}\\ @{lemma "zip [a,b,c] [x,y,z] = [(a,x),(b,y),(c,z)]" by simp}\\ @{lemma "zip [a,b] [x,y,z] = [(a,x),(b,y)]" by simp}\\ @{lemma "enumerate 3 [a,b,c] = [(3,a),(4,b),(5,c)]" by normalization}\\ @{lemma "List.product [a,b] [c,d] = [(a, c), (a, d), (b, c), (b, d)]" by simp}\\ @{lemma "product_lists [[a,b], [c], [d,e]] = [[a,c,d], [a,c,e], [b,c,d], [b,c,e]]" by simp}\\ @{lemma "splice [a,b,c] [x,y,z] = [a,x,b,y,c,z]" by simp}\\ @{lemma "splice [a,b,c,d] [x,y] = [a,x,b,y,c,d]" by simp}\\ @{lemma "shuffles [a,b] [c,d] = {[a,b,c,d],[a,c,b,d],[a,c,d,b],[c,a,b,d],[c,a,d,b],[c,d,a,b]}" by (simp add: insert_commute)}\\ @{lemma "take 2 [a,b,c,d] = [a,b]" by simp}\\ @{lemma "take 6 [a,b,c,d] = [a,b,c,d]" by simp}\\ @{lemma "drop 2 [a,b,c,d] = [c,d]" by simp}\\ @{lemma "drop 6 [a,b,c,d] = []" by simp}\\ @{lemma "takeWhile (%n::nat. n<3) [1,2,3,0] = [1,2]" by simp}\\ @{lemma "dropWhile (%n::nat. n<3) [1,2,3,0] = [3,0]" by simp}\\ @{lemma "distinct [2,0,1::nat]" by simp}\\ @{lemma "remdups [2,0,2,1::nat,2] = [0,1,2]" by simp}\\ @{lemma "remdups_adj [2,2,3,1,1::nat,2,1] = [2,3,1,2,1]" by simp}\\ @{lemma "List.insert 2 [0::nat,1,2] = [0,1,2]" by (simp add: List.insert_def)}\\ @{lemma "List.insert 3 [0::nat,1,2] = [3,0,1,2]" by (simp add: List.insert_def)}\\ @{lemma "List.union [2,3,4] [0::int,1,2] = [4,3,0,1,2]" by (simp add: List.insert_def List.union_def)}\\ @{lemma "List.find (%i::int. i>0) [0,0] = None" by simp}\\ @{lemma "List.find (%i::int. i>0) [0,1,0,2] = Some 1" by simp}\\ @{lemma "count_list [0,1,0,2::int] 0 = 2" by (simp)}\\ @{lemma "List.extract (%i::int. i>0) [0,0] = None" by(simp add: extract_def)}\\ @{lemma "List.extract (%i::int. i>0) [0,1,0,2] = Some([0], 1, [0,2])" by(simp add: extract_def)}\\ @{lemma "remove1 2 [2,0,2,1::nat,2] = [0,2,1,2]" by simp}\\ @{lemma "removeAll 2 [2,0,2,1::nat,2] = [0,1]" by simp}\\ @{lemma "nth [a,b,c,d] 2 = c" by simp}\\ @{lemma "[a,b,c,d][2 := x] = [a,b,x,d]" by simp}\\ @{lemma "nths [a,b,c,d,e] {0,2,3} = [a,c,d]" by (simp add:nths_def)}\\ @{lemma "subseqs [a,b] = [[a, b], [a], [b], []]" by simp}\\ @{lemma "List.n_lists 2 [a,b,c] = [[a, a], [b, a], [c, a], [a, b], [b, b], [c, b], [a, c], [b, c], [c, c]]" by (simp add: eval_nat_numeral)}\\ @{lemma "rotate1 [a,b,c,d] = [b,c,d,a]" by simp}\\ @{lemma "rotate 3 [a,b,c,d] = [d,a,b,c]" by (simp add:rotate_def eval_nat_numeral)}\\ @{lemma "replicate 4 a = [a,a,a,a]" by (simp add:eval_nat_numeral)}\\ @{lemma "[2..<5] = [2,3,4]" by (simp add:eval_nat_numeral)}\\ @{lemma "min_list [3,1,-2::int] = -2" by (simp)}\\ @{lemma "arg_min_list (\i. i*i) [3,-1,1,-2::int] = -1" by (simp)} \end{tabular}} \caption{Characteristic examples} \label{fig:Characteristic} \end{figure} Figure~\ref{fig:Characteristic} shows characteristic examples that should give an intuitive understanding of the above functions. \ text\The following simple sort(ed) functions are intended for proofs, not for efficient implementations.\ text \A sorted predicate w.r.t. a relation:\ fun sorted_wrt :: "('a \ 'a \ bool) \ 'a list \ bool" where "sorted_wrt P [] = True" | "sorted_wrt P (x # ys) = ((\y \ set ys. P x y) \ sorted_wrt P ys)" text \A class-based sorted predicate:\ context linorder begin abbreviation sorted :: "'a list \ bool" where "sorted \ sorted_wrt (\)" lemma sorted_simps: "sorted [] = True" "sorted (x # ys) = ((\y \ set ys. x\y) \ sorted ys)" by auto lemma strict_sorted_simps: "sorted_wrt (<) [] = True" "sorted_wrt (<) (x # ys) = ((\y \ set ys. x sorted_wrt (<) ys)" by auto primrec insort_key :: "('b \ 'a) \ 'b \ 'b list \ 'b list" where "insort_key f x [] = [x]" | "insort_key f x (y#ys) = (if f x \ f y then (x#y#ys) else y#(insort_key f x ys))" definition sort_key :: "('b \ 'a) \ 'b list \ 'b list" where "sort_key f xs = foldr (insort_key f) xs []" definition insort_insert_key :: "('b \ 'a) \ 'b \ 'b list \ 'b list" where "insort_insert_key f x xs = (if f x \ f ` set xs then xs else insort_key f x xs)" abbreviation "sort \ sort_key (\x. x)" abbreviation "insort \ insort_key (\x. x)" abbreviation "insort_insert \ insort_insert_key (\x. x)" definition stable_sort_key :: "(('b \ 'a) \ 'b list \ 'b list) \ bool" where "stable_sort_key sk = (\f xs k. filter (\y. f y = k) (sk f xs) = filter (\y. f y = k) xs)" lemma strict_sorted_iff: "sorted_wrt (<) l \ sorted l \ distinct l" by (induction l) (auto iff: antisym_conv1) lemma strict_sorted_imp_sorted: "sorted_wrt (<) xs \ sorted xs" by (auto simp: strict_sorted_iff) end subsubsection \List comprehension\ text\Input syntax for Haskell-like list comprehension notation. Typical example: \[(x,y). x \ xs, y \ ys, x \ y]\, the list of all pairs of distinct elements from \xs\ and \ys\. The syntax is as in Haskell, except that \|\ becomes a dot (like in Isabelle's set comprehension): \[e. x \ xs, \]\ rather than \verb![e| x <- xs, ...]!. The qualifiers after the dot are \begin{description} \item[generators] \p \ xs\, where \p\ is a pattern and \xs\ an expression of list type, or \item[guards] \b\, where \b\ is a boolean expression. %\item[local bindings] @ {text"let x = e"}. \end{description} Just like in Haskell, list comprehension is just a shorthand. To avoid misunderstandings, the translation into desugared form is not reversed upon output. Note that the translation of \[e. x \ xs]\ is optmized to \<^term>\map (%x. e) xs\. It is easy to write short list comprehensions which stand for complex expressions. During proofs, they may become unreadable (and mangled). In such cases it can be advisable to introduce separate definitions for the list comprehensions in question.\ nonterminal lc_qual and lc_quals syntax "_listcompr" :: "'a \ lc_qual \ lc_quals \ 'a list" ("[_ . __") "_lc_gen" :: "'a \ 'a list \ lc_qual" ("_ \ _") "_lc_test" :: "bool \ lc_qual" ("_") (*"_lc_let" :: "letbinds => lc_qual" ("let _")*) "_lc_end" :: "lc_quals" ("]") "_lc_quals" :: "lc_qual \ lc_quals \ lc_quals" (", __") syntax (ASCII) "_lc_gen" :: "'a \ 'a list \ lc_qual" ("_ <- _") parse_translation \ let val NilC = Syntax.const \<^const_syntax>\Nil\; val ConsC = Syntax.const \<^const_syntax>\Cons\; val mapC = Syntax.const \<^const_syntax>\map\; val concatC = Syntax.const \<^const_syntax>\concat\; val IfC = Syntax.const \<^const_syntax>\If\; val dummyC = Syntax.const \<^const_syntax>\Pure.dummy_pattern\ fun single x = ConsC $ x $ NilC; fun pat_tr ctxt p e opti = (* %x. case x of p => e | _ => [] *) let (* FIXME proper name context!? *) val x = Free (singleton (Name.variant_list (fold Term.add_free_names [p, e] [])) "x", dummyT); val e = if opti then single e else e; val case1 = Syntax.const \<^syntax_const>\_case1\ $ p $ e; val case2 = Syntax.const \<^syntax_const>\_case1\ $ dummyC $ NilC; val cs = Syntax.const \<^syntax_const>\_case2\ $ case1 $ case2; in Syntax_Trans.abs_tr [x, Case_Translation.case_tr false ctxt [x, cs]] end; fun pair_pat_tr (x as Free _) e = Syntax_Trans.abs_tr [x, e] | pair_pat_tr (_ $ p1 $ p2) e = Syntax.const \<^const_syntax>\case_prod\ $ pair_pat_tr p1 (pair_pat_tr p2 e) | pair_pat_tr dummy e = Syntax_Trans.abs_tr [Syntax.const "_idtdummy", e] fun pair_pat ctxt (Const (\<^const_syntax>\Pair\,_) $ s $ t) = pair_pat ctxt s andalso pair_pat ctxt t | pair_pat ctxt (Free (s,_)) = let val thy = Proof_Context.theory_of ctxt; val s' = Proof_Context.intern_const ctxt s; in not (Sign.declared_const thy s') end | pair_pat _ t = (t = dummyC); fun abs_tr ctxt p e opti = let val p = Term_Position.strip_positions p in if pair_pat ctxt p then (pair_pat_tr p e, true) else (pat_tr ctxt p e opti, false) end fun lc_tr ctxt [e, Const (\<^syntax_const>\_lc_test\, _) $ b, qs] = let val res = (case qs of Const (\<^syntax_const>\_lc_end\, _) => single e | Const (\<^syntax_const>\_lc_quals\, _) $ q $ qs => lc_tr ctxt [e, q, qs]); in IfC $ b $ res $ NilC end | lc_tr ctxt [e, Const (\<^syntax_const>\_lc_gen\, _) $ p $ es, Const(\<^syntax_const>\_lc_end\, _)] = (case abs_tr ctxt p e true of (f, true) => mapC $ f $ es | (f, false) => concatC $ (mapC $ f $ es)) | lc_tr ctxt [e, Const (\<^syntax_const>\_lc_gen\, _) $ p $ es, Const (\<^syntax_const>\_lc_quals\, _) $ q $ qs] = let val e' = lc_tr ctxt [e, q, qs]; in concatC $ (mapC $ (fst (abs_tr ctxt p e' false)) $ es) end; in [(\<^syntax_const>\_listcompr\, lc_tr)] end \ ML_val \ let val read = Syntax.read_term \<^context> o Syntax.implode_input; fun check s1 s2 = read s1 aconv read s2 orelse error ("Check failed: " ^ quote (#1 (Input.source_content s1)) ^ Position.here_list [Input.pos_of s1, Input.pos_of s2]); in check \[(x,y,z). b]\ \if b then [(x, y, z)] else []\; check \[(x,y,z). (x,_,y)\xs]\ \map (\(x,_,y). (x, y, z)) xs\; check \[e x y. (x,_)\xs, y\ys]\ \concat (map (\(x,_). map (\y. e x y) ys) xs)\; check \[(x,y,z). xb]\ \if x < a then if b < x then [(x, y, z)] else [] else []\; check \[(x,y,z). x\xs, x>b]\ \concat (map (\x. if b < x then [(x, y, z)] else []) xs)\; check \[(x,y,z). xxs]\ \if x < a then map (\x. (x, y, z)) xs else []\; check \[(x,y). Cons True x \ xs]\ \concat (map (\xa. case xa of [] \ [] | True # x \ [(x, y)] | False # x \ []) xs)\; check \[(x,y,z). Cons x [] \ xs]\ \concat (map (\xa. case xa of [] \ [] | [x] \ [(x, y, z)] | x # aa # lista \ []) xs)\; check \[(x,y,z). xb, x=d]\ \if x < a then if b < x then if x = d then [(x, y, z)] else [] else [] else []\; check \[(x,y,z). xb, y\ys]\ \if x < a then if b < x then map (\y. (x, y, z)) ys else [] else []\; check \[(x,y,z). xxs,y>b]\ \if x < a then concat (map (\(_,x). if b < y then [(x, y, z)] else []) xs) else []\; check \[(x,y,z). xxs, y\ys]\ \if x < a then concat (map (\x. map (\y. (x, y, z)) ys) xs) else []\; check \[(x,y,z). x\xs, x>b, y \concat (map (\x. if b < x then if y < a then [(x, y, z)] else [] else []) xs)\; check \[(x,y,z). x\xs, x>b, y\ys]\ \concat (map (\x. if b < x then map (\y. (x, y, z)) ys else []) xs)\; check \[(x,y,z). x\xs, (y,_)\ys,y>x]\ \concat (map (\x. concat (map (\(y,_). if x < y then [(x, y, z)] else []) ys)) xs)\; check \[(x,y,z). x\xs, y\ys,z\zs]\ \concat (map (\x. concat (map (\y. map (\z. (x, y, z)) zs) ys)) xs)\ end; \ ML \ (* Simproc for rewriting list comprehensions applied to List.set to set comprehension. *) signature LIST_TO_SET_COMPREHENSION = sig val simproc : Proof.context -> cterm -> thm option end structure List_to_Set_Comprehension : LIST_TO_SET_COMPREHENSION = struct (* conversion *) fun all_exists_conv cv ctxt ct = (case Thm.term_of ct of Const (\<^const_name>\Ex\, _) $ Abs _ => Conv.arg_conv (Conv.abs_conv (all_exists_conv cv o #2) ctxt) ct | _ => cv ctxt ct) fun all_but_last_exists_conv cv ctxt ct = (case Thm.term_of ct of Const (\<^const_name>\Ex\, _) $ Abs (_, _, Const (\<^const_name>\Ex\, _) $ _) => Conv.arg_conv (Conv.abs_conv (all_but_last_exists_conv cv o #2) ctxt) ct | _ => cv ctxt ct) fun Collect_conv cv ctxt ct = (case Thm.term_of ct of Const (\<^const_name>\Collect\, _) $ Abs _ => Conv.arg_conv (Conv.abs_conv cv ctxt) ct | _ => raise CTERM ("Collect_conv", [ct])) fun rewr_conv' th = Conv.rewr_conv (mk_meta_eq th) fun conjunct_assoc_conv ct = Conv.try_conv (rewr_conv' @{thm conj_assoc} then_conv HOLogic.conj_conv Conv.all_conv conjunct_assoc_conv) ct fun right_hand_set_comprehension_conv conv ctxt = HOLogic.Trueprop_conv (HOLogic.eq_conv Conv.all_conv (Collect_conv (all_exists_conv conv o #2) ctxt)) (* term abstraction of list comprehension patterns *) datatype termlets = If | Case of typ * int local val set_Nil_I = @{lemma "set [] = {x. False}" by (simp add: empty_def [symmetric])} val set_singleton = @{lemma "set [a] = {x. x = a}" by simp} val inst_Collect_mem_eq = @{lemma "set A = {x. x \ set A}" by simp} val del_refl_eq = @{lemma "(t = t \ P) \ P" by simp} fun mk_set T = Const (\<^const_name>\set\, HOLogic.listT T --> HOLogic.mk_setT T) fun dest_set (Const (\<^const_name>\set\, _) $ xs) = xs fun dest_singleton_list (Const (\<^const_name>\Cons\, _) $ t $ (Const (\<^const_name>\Nil\, _))) = t | dest_singleton_list t = raise TERM ("dest_singleton_list", [t]) (*We check that one case returns a singleton list and all other cases return [], and return the index of the one singleton list case.*) fun possible_index_of_singleton_case cases = let fun check (i, case_t) s = (case strip_abs_body case_t of (Const (\<^const_name>\Nil\, _)) => s | _ => (case s of SOME NONE => SOME (SOME i) | _ => NONE)) in fold_index check cases (SOME NONE) |> the_default NONE end (*returns condition continuing term option*) fun dest_if (Const (\<^const_name>\If\, _) $ cond $ then_t $ Const (\<^const_name>\Nil\, _)) = SOME (cond, then_t) | dest_if _ = NONE (*returns (case_expr type index chosen_case constr_name) option*) fun dest_case ctxt case_term = let val (case_const, args) = strip_comb case_term in (case try dest_Const case_const of SOME (c, T) => (case Ctr_Sugar.ctr_sugar_of_case ctxt c of SOME {ctrs, ...} => (case possible_index_of_singleton_case (fst (split_last args)) of SOME i => let val constr_names = map (fst o dest_Const) ctrs val (Ts, _) = strip_type T val T' = List.last Ts in SOME (List.last args, T', i, nth args i, nth constr_names i) end | NONE => NONE) | NONE => NONE) | NONE => NONE) end fun tac ctxt [] = resolve_tac ctxt [set_singleton] 1 ORELSE resolve_tac ctxt [inst_Collect_mem_eq] 1 | tac ctxt (If :: cont) = Splitter.split_tac ctxt @{thms if_split} 1 THEN resolve_tac ctxt @{thms conjI} 1 THEN resolve_tac ctxt @{thms impI} 1 THEN Subgoal.FOCUS (fn {prems, context = ctxt', ...} => CONVERSION (right_hand_set_comprehension_conv (K (HOLogic.conj_conv (Conv.rewr_conv (List.last prems RS @{thm Eq_TrueI})) Conv.all_conv then_conv rewr_conv' @{lemma "(True \ P) = P" by simp})) ctxt') 1) ctxt 1 THEN tac ctxt cont THEN resolve_tac ctxt @{thms impI} 1 THEN Subgoal.FOCUS (fn {prems, context = ctxt', ...} => CONVERSION (right_hand_set_comprehension_conv (K (HOLogic.conj_conv (Conv.rewr_conv (List.last prems RS @{thm Eq_FalseI})) Conv.all_conv then_conv rewr_conv' @{lemma "(False \ P) = False" by simp})) ctxt') 1) ctxt 1 THEN resolve_tac ctxt [set_Nil_I] 1 | tac ctxt (Case (T, i) :: cont) = let val SOME {injects, distincts, case_thms, split, ...} = Ctr_Sugar.ctr_sugar_of ctxt (fst (dest_Type T)) in (* do case distinction *) Splitter.split_tac ctxt [split] 1 THEN EVERY (map_index (fn (i', _) => (if i' < length case_thms - 1 then resolve_tac ctxt @{thms conjI} 1 else all_tac) THEN REPEAT_DETERM (resolve_tac ctxt @{thms allI} 1) THEN resolve_tac ctxt @{thms impI} 1 THEN (if i' = i then (* continue recursively *) Subgoal.FOCUS (fn {prems, context = ctxt', ...} => CONVERSION (Thm.eta_conversion then_conv right_hand_set_comprehension_conv (K ((HOLogic.conj_conv (HOLogic.eq_conv Conv.all_conv (rewr_conv' (List.last prems)) then_conv (Conv.try_conv (Conv.rewrs_conv (map mk_meta_eq injects)))) Conv.all_conv) then_conv (Conv.try_conv (Conv.rewr_conv del_refl_eq)) then_conv conjunct_assoc_conv)) ctxt' then_conv (HOLogic.Trueprop_conv (HOLogic.eq_conv Conv.all_conv (Collect_conv (fn (_, ctxt'') => Conv.repeat_conv (all_but_last_exists_conv (K (rewr_conv' @{lemma "(\x. x = t \ P x) = P t" by simp})) ctxt'')) ctxt')))) 1) ctxt 1 THEN tac ctxt cont else Subgoal.FOCUS (fn {prems, context = ctxt', ...} => CONVERSION (right_hand_set_comprehension_conv (K (HOLogic.conj_conv ((HOLogic.eq_conv Conv.all_conv (rewr_conv' (List.last prems))) then_conv (Conv.rewrs_conv (map (fn th => th RS @{thm Eq_FalseI}) distincts))) Conv.all_conv then_conv (rewr_conv' @{lemma "(False \ P) = False" by simp}))) ctxt' then_conv HOLogic.Trueprop_conv (HOLogic.eq_conv Conv.all_conv (Collect_conv (fn (_, ctxt'') => Conv.repeat_conv (Conv.bottom_conv (K (rewr_conv' @{lemma "(\x. P) = P" by simp})) ctxt'')) ctxt'))) 1) ctxt 1 THEN resolve_tac ctxt [set_Nil_I] 1)) case_thms) end in fun simproc ctxt redex = let fun make_inner_eqs bound_vs Tis eqs t = (case dest_case ctxt t of SOME (x, T, i, cont, constr_name) => let val (vs, body) = strip_abs (Envir.eta_long (map snd bound_vs) cont) val x' = incr_boundvars (length vs) x val eqs' = map (incr_boundvars (length vs)) eqs val constr_t = list_comb (Const (constr_name, map snd vs ---> T), map Bound (((length vs) - 1) downto 0)) val constr_eq = Const (\<^const_name>\HOL.eq\, T --> T --> \<^typ>\bool\) $ constr_t $ x' in make_inner_eqs (rev vs @ bound_vs) (Case (T, i) :: Tis) (constr_eq :: eqs') body end | NONE => (case dest_if t of SOME (condition, cont) => make_inner_eqs bound_vs (If :: Tis) (condition :: eqs) cont | NONE => if null eqs then NONE (*no rewriting, nothing to be done*) else let val Type (\<^type_name>\list\, [rT]) = fastype_of1 (map snd bound_vs, t) val pat_eq = (case try dest_singleton_list t of SOME t' => Const (\<^const_name>\HOL.eq\, rT --> rT --> \<^typ>\bool\) $ Bound (length bound_vs) $ t' | NONE => Const (\<^const_name>\Set.member\, rT --> HOLogic.mk_setT rT --> \<^typ>\bool\) $ Bound (length bound_vs) $ (mk_set rT $ t)) val reverse_bounds = curry subst_bounds ((map Bound ((length bound_vs - 1) downto 0)) @ [Bound (length bound_vs)]) val eqs' = map reverse_bounds eqs val pat_eq' = reverse_bounds pat_eq val inner_t = fold (fn (_, T) => fn t => HOLogic.exists_const T $ absdummy T t) (rev bound_vs) (fold (curry HOLogic.mk_conj) eqs' pat_eq') val lhs = Thm.term_of redex val rhs = HOLogic.mk_Collect ("x", rT, inner_t) val rewrite_rule_t = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs)) in SOME ((Goal.prove ctxt [] [] rewrite_rule_t (fn {context = ctxt', ...} => tac ctxt' (rev Tis))) RS @{thm eq_reflection}) end)) in make_inner_eqs [] [] [] (dest_set (Thm.term_of redex)) end end end \ simproc_setup list_to_set_comprehension ("set xs") = \K List_to_Set_Comprehension.simproc\ code_datatype set coset hide_const (open) coset subsubsection \\<^const>\Nil\ and \<^const>\Cons\\ lemma not_Cons_self [simp]: "xs \ x # xs" by (induct xs) auto lemma not_Cons_self2 [simp]: "x # xs \ xs" by (rule not_Cons_self [symmetric]) lemma neq_Nil_conv: "(xs \ []) = (\y ys. xs = y # ys)" by (induct xs) auto lemma tl_Nil: "tl xs = [] \ xs = [] \ (\x. xs = [x])" by (cases xs) auto lemma Nil_tl: "[] = tl xs \ xs = [] \ (\x. xs = [x])" by (cases xs) auto lemma length_induct: "(\xs. \ys. length ys < length xs \ P ys \ P xs) \ P xs" by (fact measure_induct) lemma induct_list012: "\P []; \x. P [x]; \x y zs. \ P zs; P (y # zs) \ \ P (x # y # zs)\ \ P xs" by induction_schema (pat_completeness, lexicographic_order) lemma list_nonempty_induct [consumes 1, case_names single cons]: "\ xs \ []; \x. P [x]; \x xs. xs \ [] \ P xs \ P (x # xs)\ \ P xs" by(induction xs rule: induct_list012) auto lemma inj_split_Cons: "inj_on (\(xs, n). n#xs) X" by (auto intro!: inj_onI) lemma inj_on_Cons1 [simp]: "inj_on ((#) x) A" by(simp add: inj_on_def) subsubsection \\<^const>\length\\ text \ Needs to come before \@\ because of theorem \append_eq_append_conv\. \ lemma length_append [simp]: "length (xs @ ys) = length xs + length ys" by (induct xs) auto lemma length_map [simp]: "length (map f xs) = length xs" by (induct xs) auto lemma length_rev [simp]: "length (rev xs) = length xs" by (induct xs) auto lemma length_tl [simp]: "length (tl xs) = length xs - 1" by (cases xs) auto lemma length_0_conv [iff]: "(length xs = 0) = (xs = [])" by (induct xs) auto lemma length_greater_0_conv [iff]: "(0 < length xs) = (xs \ [])" by (induct xs) auto lemma length_pos_if_in_set: "x \ set xs \ length xs > 0" by auto lemma length_Suc_conv: "(length xs = Suc n) = (\y ys. xs = y # ys \ length ys = n)" by (induct xs) auto lemma Suc_length_conv: "(Suc n = length xs) = (\y ys. xs = y # ys \ length ys = n)" by (induct xs; simp; blast) lemma Suc_le_length_iff: "(Suc n \ length xs) = (\x ys. xs = x # ys \ n \ length ys)" by (metis Suc_le_D[of n] Suc_le_mono[of n] Suc_length_conv[of _ xs]) lemma impossible_Cons: "length xs \ length ys \ xs = x # ys = False" by (induct xs) auto lemma list_induct2 [consumes 1, case_names Nil Cons]: "length xs = length ys \ P [] [] \ (\x xs y ys. length xs = length ys \ P xs ys \ P (x#xs) (y#ys)) \ P xs ys" proof (induct xs arbitrary: ys) case (Cons x xs ys) then show ?case by (cases ys) simp_all qed simp lemma list_induct3 [consumes 2, case_names Nil Cons]: "length xs = length ys \ length ys = length zs \ P [] [] [] \ (\x xs y ys z zs. length xs = length ys \ length ys = length zs \ P xs ys zs \ P (x#xs) (y#ys) (z#zs)) \ P xs ys zs" proof (induct xs arbitrary: ys zs) case Nil then show ?case by simp next case (Cons x xs ys zs) then show ?case by (cases ys, simp_all) (cases zs, simp_all) qed lemma list_induct4 [consumes 3, case_names Nil Cons]: "length xs = length ys \ length ys = length zs \ length zs = length ws \ P [] [] [] [] \ (\x xs y ys z zs w ws. length xs = length ys \ length ys = length zs \ length zs = length ws \ P xs ys zs ws \ P (x#xs) (y#ys) (z#zs) (w#ws)) \ P xs ys zs ws" proof (induct xs arbitrary: ys zs ws) case Nil then show ?case by simp next case (Cons x xs ys zs ws) then show ?case by ((cases ys, simp_all), (cases zs,simp_all)) (cases ws, simp_all) qed lemma list_induct2': "\ P [] []; \x xs. P (x#xs) []; \y ys. P [] (y#ys); \x xs y ys. P xs ys \ P (x#xs) (y#ys) \ \ P xs ys" by (induct xs arbitrary: ys) (case_tac x, auto)+ lemma list_all2_iff: "list_all2 P xs ys \ length xs = length ys \ (\(x, y) \ set (zip xs ys). P x y)" by (induct xs ys rule: list_induct2') auto lemma neq_if_length_neq: "length xs \ length ys \ (xs = ys) == False" by (rule Eq_FalseI) auto subsubsection \\@\ -- append\ global_interpretation append: monoid append Nil proof fix xs ys zs :: "'a list" show "(xs @ ys) @ zs = xs @ (ys @ zs)" by (induct xs) simp_all show "xs @ [] = xs" by (induct xs) simp_all qed simp lemma append_assoc [simp]: "(xs @ ys) @ zs = xs @ (ys @ zs)" by (fact append.assoc) lemma append_Nil2: "xs @ [] = xs" by (fact append.right_neutral) lemma append_is_Nil_conv [iff]: "(xs @ ys = []) = (xs = [] \ ys = [])" by (induct xs) auto lemma Nil_is_append_conv [iff]: "([] = xs @ ys) = (xs = [] \ ys = [])" by (induct xs) auto lemma append_self_conv [iff]: "(xs @ ys = xs) = (ys = [])" by (induct xs) auto lemma self_append_conv [iff]: "(xs = xs @ ys) = (ys = [])" by (induct xs) auto lemma append_eq_append_conv [simp]: "length xs = length ys \ length us = length vs \ (xs@us = ys@vs) = (xs=ys \ us=vs)" by (induct xs arbitrary: ys; case_tac ys; force) lemma append_eq_append_conv2: "(xs @ ys = zs @ ts) = (\us. xs = zs @ us \ us @ ys = ts \ xs @ us = zs \ ys = us @ ts)" proof (induct xs arbitrary: ys zs ts) case (Cons x xs) then show ?case by (cases zs) auto qed fastforce lemma same_append_eq [iff, induct_simp]: "(xs @ ys = xs @ zs) = (ys = zs)" by simp lemma append1_eq_conv [iff]: "(xs @ [x] = ys @ [y]) = (xs = ys \ x = y)" by simp lemma append_same_eq [iff, induct_simp]: "(ys @ xs = zs @ xs) = (ys = zs)" by simp lemma append_self_conv2 [iff]: "(xs @ ys = ys) = (xs = [])" using append_same_eq [of _ _ "[]"] by auto lemma self_append_conv2 [iff]: "(ys = xs @ ys) = (xs = [])" using append_same_eq [of "[]"] by auto lemma hd_Cons_tl: "xs \ [] \ hd xs # tl xs = xs" by (fact list.collapse) lemma hd_append: "hd (xs @ ys) = (if xs = [] then hd ys else hd xs)" by (induct xs) auto lemma hd_append2 [simp]: "xs \ [] \ hd (xs @ ys) = hd xs" by (simp add: hd_append split: list.split) lemma tl_append: "tl (xs @ ys) = (case xs of [] \ tl ys | z#zs \ zs @ ys)" by (simp split: list.split) lemma tl_append2 [simp]: "xs \ [] \ tl (xs @ ys) = tl xs @ ys" by (simp add: tl_append split: list.split) lemma Cons_eq_append_conv: "x#xs = ys@zs = (ys = [] \ x#xs = zs \ (\ys'. x#ys' = ys \ xs = ys'@zs))" by(cases ys) auto lemma append_eq_Cons_conv: "(ys@zs = x#xs) = (ys = [] \ zs = x#xs \ (\ys'. ys = x#ys' \ ys'@zs = xs))" by(cases ys) auto lemma longest_common_prefix: "\ps xs' ys'. xs = ps @ xs' \ ys = ps @ ys' \ (xs' = [] \ ys' = [] \ hd xs' \ hd ys')" by (induct xs ys rule: list_induct2') (blast, blast, blast, metis (no_types, hide_lams) append_Cons append_Nil list.sel(1)) text \Trivial rules for solving \@\-equations automatically.\ lemma eq_Nil_appendI: "xs = ys \ xs = [] @ ys" by simp lemma Cons_eq_appendI: "\x # xs1 = ys; xs = xs1 @ zs\ \ x # xs = ys @ zs" by auto lemma append_eq_appendI: "\xs @ xs1 = zs; ys = xs1 @ us\ \ xs @ ys = zs @ us" by auto text \ Simplification procedure for all list equalities. Currently only tries to rearrange \@\ to see if - both lists end in a singleton list, - or both lists end in the same list. \ simproc_setup list_eq ("(xs::'a list) = ys") = \ let fun last (cons as Const (\<^const_name>\Cons\, _) $ _ $ xs) = (case xs of Const (\<^const_name>\Nil\, _) => cons | _ => last xs) | last (Const(\<^const_name>\append\,_) $ _ $ ys) = last ys | last t = t; fun list1 (Const(\<^const_name>\Cons\,_) $ _ $ Const(\<^const_name>\Nil\,_)) = true | list1 _ = false; fun butlast ((cons as Const(\<^const_name>\Cons\,_) $ x) $ xs) = (case xs of Const (\<^const_name>\Nil\, _) => xs | _ => cons $ butlast xs) | butlast ((app as Const (\<^const_name>\append\, _) $ xs) $ ys) = app $ butlast ys | butlast xs = Const(\<^const_name>\Nil\, fastype_of xs); val rearr_ss = simpset_of (put_simpset HOL_basic_ss \<^context> addsimps [@{thm append_assoc}, @{thm append_Nil}, @{thm append_Cons}]); fun list_eq ctxt (F as (eq as Const(_,eqT)) $ lhs $ rhs) = let val lastl = last lhs and lastr = last rhs; fun rearr conv = let val lhs1 = butlast lhs and rhs1 = butlast rhs; val Type(_,listT::_) = eqT val appT = [listT,listT] ---> listT val app = Const(\<^const_name>\append\,appT) val F2 = eq $ (app$lhs1$lastl) $ (app$rhs1$lastr) val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (F,F2)); val thm = Goal.prove ctxt [] [] eq (K (simp_tac (put_simpset rearr_ss ctxt) 1)); in SOME ((conv RS (thm RS trans)) RS eq_reflection) end; in if list1 lastl andalso list1 lastr then rearr @{thm append1_eq_conv} else if lastl aconv lastr then rearr @{thm append_same_eq} else NONE end; in fn _ => fn ctxt => fn ct => list_eq ctxt (Thm.term_of ct) end \ subsubsection \\<^const>\map\\ lemma hd_map: "xs \ [] \ hd (map f xs) = f (hd xs)" by (cases xs) simp_all lemma map_tl: "map f (tl xs) = tl (map f xs)" by (cases xs) simp_all lemma map_ext: "(\x. x \ set xs \ f x = g x) \ map f xs = map g xs" by (induct xs) simp_all lemma map_ident [simp]: "map (\x. x) = (\xs. xs)" by (rule ext, induct_tac xs) auto lemma map_append [simp]: "map f (xs @ ys) = map f xs @ map f ys" by (induct xs) auto lemma map_map [simp]: "map f (map g xs) = map (f \ g) xs" by (induct xs) auto lemma map_comp_map[simp]: "((map f) \ (map g)) = map(f \ g)" by (rule ext) simp lemma rev_map: "rev (map f xs) = map f (rev xs)" by (induct xs) auto lemma map_eq_conv[simp]: "(map f xs = map g xs) = (\x \ set xs. f x = g x)" by (induct xs) auto lemma map_cong [fundef_cong]: "xs = ys \ (\x. x \ set ys \ f x = g x) \ map f xs = map g ys" by simp lemma map_is_Nil_conv [iff]: "(map f xs = []) = (xs = [])" by (cases xs) auto lemma Nil_is_map_conv [iff]: "([] = map f xs) = (xs = [])" by (cases xs) auto lemma map_eq_Cons_conv: "(map f xs = y#ys) = (\z zs. xs = z#zs \ f z = y \ map f zs = ys)" by (cases xs) auto lemma Cons_eq_map_conv: "(x#xs = map f ys) = (\z zs. ys = z#zs \ x = f z \ xs = map f zs)" by (cases ys) auto lemmas map_eq_Cons_D = map_eq_Cons_conv [THEN iffD1] lemmas Cons_eq_map_D = Cons_eq_map_conv [THEN iffD1] declare map_eq_Cons_D [dest!] Cons_eq_map_D [dest!] lemma ex_map_conv: "(\xs. ys = map f xs) = (\y \ set ys. \x. y = f x)" by(induct ys, auto simp add: Cons_eq_map_conv) lemma map_eq_imp_length_eq: assumes "map f xs = map g ys" shows "length xs = length ys" using assms proof (induct ys arbitrary: xs) case Nil then show ?case by simp next case (Cons y ys) then obtain z zs where xs: "xs = z # zs" by auto from Cons xs have "map f zs = map g ys" by simp with Cons have "length zs = length ys" by blast with xs show ?case by simp qed lemma map_inj_on: assumes map: "map f xs = map f ys" and inj: "inj_on f (set xs Un set ys)" shows "xs = ys" using map_eq_imp_length_eq [OF map] assms proof (induct rule: list_induct2) case (Cons x xs y ys) then show ?case by (auto intro: sym) qed auto lemma inj_on_map_eq_map: "inj_on f (set xs Un set ys) \ (map f xs = map f ys) = (xs = ys)" by(blast dest:map_inj_on) lemma map_injective: "map f xs = map f ys \ inj f \ xs = ys" by (induct ys arbitrary: xs) (auto dest!:injD) lemma inj_map_eq_map[simp]: "inj f \ (map f xs = map f ys) = (xs = ys)" by(blast dest:map_injective) lemma inj_mapI: "inj f \ inj (map f)" by (iprover dest: map_injective injD intro: inj_onI) lemma inj_mapD: "inj (map f) \ inj f" by (metis (no_types, hide_lams) injI list.inject list.simps(9) the_inv_f_f) lemma inj_map[iff]: "inj (map f) = inj f" by (blast dest: inj_mapD intro: inj_mapI) lemma inj_on_mapI: "inj_on f (\(set ` A)) \ inj_on (map f) A" by (blast intro:inj_onI dest:inj_onD map_inj_on) lemma map_idI: "(\x. x \ set xs \ f x = x) \ map f xs = xs" by (induct xs, auto) lemma map_fun_upd [simp]: "y \ set xs \ map (f(y:=v)) xs = map f xs" by (induct xs) auto lemma map_fst_zip[simp]: "length xs = length ys \ map fst (zip xs ys) = xs" by (induct rule:list_induct2, simp_all) lemma map_snd_zip[simp]: "length xs = length ys \ map snd (zip xs ys) = ys" by (induct rule:list_induct2, simp_all) lemma map_fst_zip_take: "map fst (zip xs ys) = take (min (length xs) (length ys)) xs" by (induct xs ys rule: list_induct2') simp_all lemma map_snd_zip_take: "map snd (zip xs ys) = take (min (length xs) (length ys)) ys" by (induct xs ys rule: list_induct2') simp_all lemma map2_map_map: "map2 h (map f xs) (map g xs) = map (\x. h (f x) (g x)) xs" by (induction xs) (auto) functor map: map by (simp_all add: id_def) declare map.id [simp] subsubsection \\<^const>\rev\\ lemma rev_append [simp]: "rev (xs @ ys) = rev ys @ rev xs" by (induct xs) auto lemma rev_rev_ident [simp]: "rev (rev xs) = xs" by (induct xs) auto lemma rev_swap: "(rev xs = ys) = (xs = rev ys)" by auto lemma rev_is_Nil_conv [iff]: "(rev xs = []) = (xs = [])" by (induct xs) auto lemma Nil_is_rev_conv [iff]: "([] = rev xs) = (xs = [])" by (induct xs) auto lemma rev_singleton_conv [simp]: "(rev xs = [x]) = (xs = [x])" by (cases xs) auto lemma singleton_rev_conv [simp]: "([x] = rev xs) = (xs = [x])" by (cases xs) auto lemma rev_is_rev_conv [iff]: "(rev xs = rev ys) = (xs = ys)" proof (induct xs arbitrary: ys) case Nil then show ?case by force next case Cons then show ?case by (cases ys) auto qed lemma inj_on_rev[iff]: "inj_on rev A" by(simp add:inj_on_def) lemma rev_induct [case_names Nil snoc]: assumes "P []" and "\x xs. P xs \ P (xs @ [x])" shows "P xs" proof - have "P (rev (rev xs))" by (rule_tac list = "rev xs" in list.induct, simp_all add: assms) then show ?thesis by simp qed lemma rev_exhaust [case_names Nil snoc]: "(xs = [] \ P) \(\ys y. xs = ys @ [y] \ P) \ P" by (induct xs rule: rev_induct) auto lemmas rev_cases = rev_exhaust lemma rev_nonempty_induct [consumes 1, case_names single snoc]: assumes "xs \ []" and single: "\x. P [x]" and snoc': "\x xs. xs \ [] \ P xs \ P (xs@[x])" shows "P xs" using \xs \ []\ proof (induct xs rule: rev_induct) case (snoc x xs) then show ?case proof (cases xs) case Nil thus ?thesis by (simp add: single) next case Cons with snoc show ?thesis by (fastforce intro!: snoc') qed qed simp lemma rev_eq_Cons_iff[iff]: "(rev xs = y#ys) = (xs = rev ys @ [y])" by(rule rev_cases[of xs]) auto subsubsection \\<^const>\set\\ declare list.set[code_post] \ \pretty output\ lemma finite_set [iff]: "finite (set xs)" by (induct xs) auto lemma set_append [simp]: "set (xs @ ys) = (set xs \ set ys)" by (induct xs) auto lemma hd_in_set[simp]: "xs \ [] \ hd xs \ set xs" by(cases xs) auto lemma set_subset_Cons: "set xs \ set (x # xs)" by auto lemma set_ConsD: "y \ set (x # xs) \ y=x \ y \ set xs" by auto lemma set_empty [iff]: "(set xs = {}) = (xs = [])" by (induct xs) auto lemma set_empty2[iff]: "({} = set xs) = (xs = [])" by(induct xs) auto lemma set_rev [simp]: "set (rev xs) = set xs" by (induct xs) auto lemma set_map [simp]: "set (map f xs) = f`(set xs)" by (induct xs) auto lemma set_filter [simp]: "set (filter P xs) = {x. x \ set xs \ P x}" by (induct xs) auto lemma set_upt [simp]: "set[i.. set xs \ \ys zs. xs = ys @ x # zs" proof (induct xs) case Nil thus ?case by simp next case Cons thus ?case by (auto intro: Cons_eq_appendI) qed lemma in_set_conv_decomp: "x \ set xs \ (\ys zs. xs = ys @ x # zs)" by (auto elim: split_list) lemma split_list_first: "x \ set xs \ \ys zs. xs = ys @ x # zs \ x \ set ys" proof (induct xs) case Nil thus ?case by simp next case (Cons a xs) show ?case proof cases assume "x = a" thus ?case using Cons by fastforce next assume "x \ a" thus ?case using Cons by(fastforce intro!: Cons_eq_appendI) qed qed lemma in_set_conv_decomp_first: "(x \ set xs) = (\ys zs. xs = ys @ x # zs \ x \ set ys)" by (auto dest!: split_list_first) lemma split_list_last: "x \ set xs \ \ys zs. xs = ys @ x # zs \ x \ set zs" proof (induct xs rule: rev_induct) case Nil thus ?case by simp next case (snoc a xs) show ?case proof cases assume "x = a" thus ?case using snoc by (auto intro!: exI) next assume "x \ a" thus ?case using snoc by fastforce qed qed lemma in_set_conv_decomp_last: "(x \ set xs) = (\ys zs. xs = ys @ x # zs \ x \ set zs)" by (auto dest!: split_list_last) lemma split_list_prop: "\x \ set xs. P x \ \ys x zs. xs = ys @ x # zs \ P x" proof (induct xs) case Nil thus ?case by simp next case Cons thus ?case by(simp add:Bex_def)(metis append_Cons append.simps(1)) qed lemma split_list_propE: assumes "\x \ set xs. P x" obtains ys x zs where "xs = ys @ x # zs" and "P x" using split_list_prop [OF assms] by blast lemma split_list_first_prop: "\x \ set xs. P x \ \ys x zs. xs = ys@x#zs \ P x \ (\y \ set ys. \ P y)" proof (induct xs) case Nil thus ?case by simp next case (Cons x xs) show ?case proof cases assume "P x" hence "x # xs = [] @ x # xs \ P x \ (\y\set []. \ P y)" by simp thus ?thesis by fast next assume "\ P x" hence "\x\set xs. P x" using Cons(2) by simp thus ?thesis using \\ P x\ Cons(1) by (metis append_Cons set_ConsD) qed qed lemma split_list_first_propE: assumes "\x \ set xs. P x" obtains ys x zs where "xs = ys @ x # zs" and "P x" and "\y \ set ys. \ P y" using split_list_first_prop [OF assms] by blast lemma split_list_first_prop_iff: "(\x \ set xs. P x) \ (\ys x zs. xs = ys@x#zs \ P x \ (\y \ set ys. \ P y))" by (rule, erule split_list_first_prop) auto lemma split_list_last_prop: "\x \ set xs. P x \ \ys x zs. xs = ys@x#zs \ P x \ (\z \ set zs. \ P z)" proof(induct xs rule:rev_induct) case Nil thus ?case by simp next case (snoc x xs) show ?case proof cases assume "P x" thus ?thesis by (auto intro!: exI) next assume "\ P x" hence "\x\set xs. P x" using snoc(2) by simp thus ?thesis using \\ P x\ snoc(1) by fastforce qed qed lemma split_list_last_propE: assumes "\x \ set xs. P x" obtains ys x zs where "xs = ys @ x # zs" and "P x" and "\z \ set zs. \ P z" using split_list_last_prop [OF assms] by blast lemma split_list_last_prop_iff: "(\x \ set xs. P x) \ (\ys x zs. xs = ys@x#zs \ P x \ (\z \ set zs. \ P z))" by rule (erule split_list_last_prop, auto) lemma finite_list: "finite A \ \xs. set xs = A" by (erule finite_induct) (auto simp add: list.set(2)[symmetric] simp del: list.set(2)) lemma card_length: "card (set xs) \ length xs" by (induct xs) (auto simp add: card_insert_if) lemma set_minus_filter_out: "set xs - {y} = set (filter (\x. \ (x = y)) xs)" by (induct xs) auto lemma append_Cons_eq_iff: "\ x \ set xs; x \ set ys \ \ xs @ x # ys = xs' @ x # ys' \ (xs = xs' \ ys = ys')" by(auto simp: append_eq_Cons_conv Cons_eq_append_conv append_eq_append_conv2) subsubsection \\<^const>\concat\\ lemma concat_append [simp]: "concat (xs @ ys) = concat xs @ concat ys" by (induct xs) auto lemma concat_eq_Nil_conv [simp]: "(concat xss = []) = (\xs \ set xss. xs = [])" by (induct xss) auto lemma Nil_eq_concat_conv [simp]: "([] = concat xss) = (\xs \ set xss. xs = [])" by (induct xss) auto lemma set_concat [simp]: "set (concat xs) = (\x\set xs. set x)" by (induct xs) auto lemma concat_map_singleton[simp]: "concat(map (%x. [f x]) xs) = map f xs" by (induct xs) auto lemma map_concat: "map f (concat xs) = concat (map (map f) xs)" by (induct xs) auto lemma rev_concat: "rev (concat xs) = concat (map rev (rev xs))" by (induct xs) auto lemma length_concat_rev[simp]: "length (concat (rev xs)) = length (concat xs)" by (induction xs) auto lemma concat_eq_concat_iff: "\(x, y) \ set (zip xs ys). length x = length y \ length xs = length ys \ (concat xs = concat ys) = (xs = ys)" proof (induct xs arbitrary: ys) case (Cons x xs ys) thus ?case by (cases ys) auto qed (auto) lemma concat_injective: "concat xs = concat ys \ length xs = length ys \ \(x, y) \ set (zip xs ys). length x = length y \ xs = ys" by (simp add: concat_eq_concat_iff) lemma concat_eq_appendD: assumes "concat xss = ys @ zs" "xss \ []" shows "\xss1 xs xs' xss2. xss = xss1 @ (xs @ xs') # xss2 \ ys = concat xss1 @ xs \ zs = xs' @ concat xss2" using assms proof(induction xss arbitrary: ys) case (Cons xs xss) from Cons.prems consider us where "xs @ us = ys" "concat xss = us @ zs" | us where "xs = ys @ us" "us @ concat xss = zs" by(auto simp add: append_eq_append_conv2) then show ?case proof cases case 1 then show ?thesis using Cons.IH[OF 1(2)] by(cases xss)(auto intro: exI[where x="[]"], metis append.assoc append_Cons concat.simps(2)) qed(auto intro: exI[where x="[]"]) qed simp lemma concat_eq_append_conv: "concat xss = ys @ zs \ (if xss = [] then ys = [] \ zs = [] else \xss1 xs xs' xss2. xss = xss1 @ (xs @ xs') # xss2 \ ys = concat xss1 @ xs \ zs = xs' @ concat xss2)" by(auto dest: concat_eq_appendD) lemma hd_concat: "\xs \ []; hd xs \ []\ \ hd (concat xs) = hd (hd xs)" by (metis concat.simps(2) hd_Cons_tl hd_append2) simproc_setup list_neq ("(xs::'a list) = ys") = \ (* Reduces xs=ys to False if xs and ys cannot be of the same length. This is the case if the atomic sublists of one are a submultiset of those of the other list and there are fewer Cons's in one than the other. *) let fun len (Const(\<^const_name>\Nil\,_)) acc = acc | len (Const(\<^const_name>\Cons\,_) $ _ $ xs) (ts,n) = len xs (ts,n+1) | len (Const(\<^const_name>\append\,_) $ xs $ ys) acc = len xs (len ys acc) | len (Const(\<^const_name>\rev\,_) $ xs) acc = len xs acc | len (Const(\<^const_name>\map\,_) $ _ $ xs) acc = len xs acc | len (Const(\<^const_name>\concat\,T) $ (Const(\<^const_name>\rev\,_) $ xss)) acc = len (Const(\<^const_name>\concat\,T) $ xss) acc | len t (ts,n) = (t::ts,n); val ss = simpset_of \<^context>; fun list_neq ctxt ct = let val (Const(_,eqT) $ lhs $ rhs) = Thm.term_of ct; val (ls,m) = len lhs ([],0) and (rs,n) = len rhs ([],0); fun prove_neq() = let val Type(_,listT::_) = eqT; val size = HOLogic.size_const listT; val eq_len = HOLogic.mk_eq (size $ lhs, size $ rhs); val neq_len = HOLogic.mk_Trueprop (HOLogic.Not $ eq_len); val thm = Goal.prove ctxt [] [] neq_len (K (simp_tac (put_simpset ss ctxt) 1)); in SOME (thm RS @{thm neq_if_length_neq}) end in if m < n andalso submultiset (op aconv) (ls,rs) orelse n < m andalso submultiset (op aconv) (rs,ls) then prove_neq() else NONE end; in K list_neq end \ subsubsection \\<^const>\filter\\ lemma filter_append [simp]: "filter P (xs @ ys) = filter P xs @ filter P ys" by (induct xs) auto lemma rev_filter: "rev (filter P xs) = filter P (rev xs)" by (induct xs) simp_all lemma filter_filter [simp]: "filter P (filter Q xs) = filter (\x. Q x \ P x) xs" by (induct xs) auto lemma filter_concat: "filter p (concat xs) = concat (map (filter p) xs)" by (induct xs) auto lemma length_filter_le [simp]: "length (filter P xs) \ length xs" by (induct xs) (auto simp add: le_SucI) lemma sum_length_filter_compl: "length(filter P xs) + length(filter (\x. \P x) xs) = length xs" by(induct xs) simp_all lemma filter_True [simp]: "\x \ set xs. P x \ filter P xs = xs" by (induct xs) auto lemma filter_False [simp]: "\x \ set xs. \ P x \ filter P xs = []" by (induct xs) auto lemma filter_empty_conv: "(filter P xs = []) = (\x\set xs. \ P x)" by (induct xs) simp_all lemma filter_id_conv: "(filter P xs = xs) = (\x\set xs. P x)" proof (induct xs) case (Cons x xs) then show ?case using length_filter_le by (simp add: impossible_Cons) qed auto lemma filter_map: "filter P (map f xs) = map f (filter (P \ f) xs)" by (induct xs) simp_all lemma length_filter_map[simp]: "length (filter P (map f xs)) = length(filter (P \ f) xs)" by (simp add:filter_map) lemma filter_is_subset [simp]: "set (filter P xs) \ set xs" by auto lemma length_filter_less: "\ x \ set xs; \ P x \ \ length(filter P xs) < length xs" proof (induct xs) case Nil thus ?case by simp next case (Cons x xs) thus ?case using Suc_le_eq by fastforce qed lemma length_filter_conv_card: "length(filter p xs) = card{i. i < length xs \ p(xs!i)}" proof (induct xs) case Nil thus ?case by simp next case (Cons x xs) let ?S = "{i. i < length xs \ p(xs!i)}" have fin: "finite ?S" by(fast intro: bounded_nat_set_is_finite) show ?case (is "?l = card ?S'") proof (cases) assume "p x" hence eq: "?S' = insert 0 (Suc ` ?S)" by(auto simp: image_def split:nat.split dest:gr0_implies_Suc) have "length (filter p (x # xs)) = Suc(card ?S)" using Cons \p x\ by simp also have "\ = Suc(card(Suc ` ?S))" using fin by (simp add: card_image) also have "\ = card ?S'" using eq fin by (simp add:card_insert_if) finally show ?thesis . next assume "\ p x" hence eq: "?S' = Suc ` ?S" by(auto simp add: image_def split:nat.split elim:lessE) have "length (filter p (x # xs)) = card ?S" using Cons \\ p x\ by simp also have "\ = card(Suc ` ?S)" using fin by (simp add: card_image) also have "\ = card ?S'" using eq fin by (simp add:card_insert_if) finally show ?thesis . qed qed lemma Cons_eq_filterD: "x#xs = filter P ys \ \us vs. ys = us @ x # vs \ (\u\set us. \ P u) \ P x \ xs = filter P vs" (is "_ \ \us vs. ?P ys us vs") proof(induct ys) case Nil thus ?case by simp next case (Cons y ys) show ?case (is "\x. ?Q x") proof cases assume Py: "P y" show ?thesis proof cases assume "x = y" with Py Cons.prems have "?Q []" by simp then show ?thesis .. next assume "x \ y" with Py Cons.prems show ?thesis by simp qed next assume "\ P y" with Cons obtain us vs where "?P (y#ys) (y#us) vs" by fastforce then have "?Q (y#us)" by simp then show ?thesis .. qed qed lemma filter_eq_ConsD: "filter P ys = x#xs \ \us vs. ys = us @ x # vs \ (\u\set us. \ P u) \ P x \ xs = filter P vs" by(rule Cons_eq_filterD) simp lemma filter_eq_Cons_iff: "(filter P ys = x#xs) = (\us vs. ys = us @ x # vs \ (\u\set us. \ P u) \ P x \ xs = filter P vs)" by(auto dest:filter_eq_ConsD) lemma Cons_eq_filter_iff: "(x#xs = filter P ys) = (\us vs. ys = us @ x # vs \ (\u\set us. \ P u) \ P x \ xs = filter P vs)" by(auto dest:Cons_eq_filterD) lemma inj_on_filter_key_eq: assumes "inj_on f (insert y (set xs))" shows "filter (\x. f y = f x) xs = filter (HOL.eq y) xs" using assms by (induct xs) auto lemma filter_cong[fundef_cong]: "xs = ys \ (\x. x \ set ys \ P x = Q x) \ filter P xs = filter Q ys" by (induct ys arbitrary: xs) auto subsubsection \List partitioning\ primrec partition :: "('a \ bool) \'a list \ 'a list \ 'a list" where "partition P [] = ([], [])" | "partition P (x # xs) = (let (yes, no) = partition P xs in if P x then (x # yes, no) else (yes, x # no))" lemma partition_filter1: "fst (partition P xs) = filter P xs" by (induct xs) (auto simp add: Let_def split_def) lemma partition_filter2: "snd (partition P xs) = filter (Not \ P) xs" by (induct xs) (auto simp add: Let_def split_def) lemma partition_P: assumes "partition P xs = (yes, no)" shows "(\p \ set yes. P p) \ (\p \ set no. \ P p)" proof - from assms have "yes = fst (partition P xs)" and "no = snd (partition P xs)" by simp_all then show ?thesis by (simp_all add: partition_filter1 partition_filter2) qed lemma partition_set: assumes "partition P xs = (yes, no)" shows "set yes \ set no = set xs" proof - from assms have "yes = fst (partition P xs)" and "no = snd (partition P xs)" by simp_all then show ?thesis by (auto simp add: partition_filter1 partition_filter2) qed lemma partition_filter_conv[simp]: "partition f xs = (filter f xs,filter (Not \ f) xs)" unfolding partition_filter2[symmetric] unfolding partition_filter1[symmetric] by simp declare partition.simps[simp del] subsubsection \\<^const>\nth\\ lemma nth_Cons_0 [simp, code]: "(x # xs)!0 = x" by auto lemma nth_Cons_Suc [simp, code]: "(x # xs)!(Suc n) = xs!n" by auto declare nth.simps [simp del] lemma nth_Cons_pos[simp]: "0 < n \ (x#xs) ! n = xs ! (n - 1)" by(auto simp: Nat.gr0_conv_Suc) lemma nth_append: "(xs @ ys)!n = (if n < length xs then xs!n else ys!(n - length xs))" proof (induct xs arbitrary: n) case (Cons x xs) then show ?case using less_Suc_eq_0_disj by auto qed simp lemma nth_append_length [simp]: "(xs @ x # ys) ! length xs = x" by (induct xs) auto lemma nth_append_length_plus[simp]: "(xs @ ys) ! (length xs + n) = ys ! n" by (induct xs) auto lemma nth_map [simp]: "n < length xs \ (map f xs)!n = f(xs!n)" proof (induct xs arbitrary: n) case (Cons x xs) then show ?case using less_Suc_eq_0_disj by auto qed simp lemma nth_tl: "n < length (tl xs) \ tl xs ! n = xs ! Suc n" by (induction xs) auto lemma hd_conv_nth: "xs \ [] \ hd xs = xs!0" by(cases xs) simp_all lemma list_eq_iff_nth_eq: "(xs = ys) = (length xs = length ys \ (\i ?R" by force show "?R \ ?L" using less_Suc_eq_0_disj by auto qed with Cons show ?case by simp qed simp lemma in_set_conv_nth: "(x \ set xs) = (\i < length xs. xs!i = x)" by(auto simp:set_conv_nth) lemma nth_equal_first_eq: assumes "x \ set xs" assumes "n \ length xs" shows "(x # xs) ! n = x \ n = 0" (is "?lhs \ ?rhs") proof assume ?lhs show ?rhs proof (rule ccontr) assume "n \ 0" then have "n > 0" by simp with \?lhs\ have "xs ! (n - 1) = x" by simp moreover from \n > 0\ \n \ length xs\ have "n - 1 < length xs" by simp ultimately have "\ix \ set xs\ in_set_conv_nth [of x xs] show False by simp qed next assume ?rhs then show ?lhs by simp qed lemma nth_non_equal_first_eq: assumes "x \ y" shows "(x # xs) ! n = y \ xs ! (n - 1) = y \ n > 0" (is "?lhs \ ?rhs") proof assume "?lhs" with assms have "n > 0" by (cases n) simp_all with \?lhs\ show ?rhs by simp next assume "?rhs" then show "?lhs" by simp qed lemma list_ball_nth: "\n < length xs; \x \ set xs. P x\ \ P(xs!n)" by (auto simp add: set_conv_nth) lemma nth_mem [simp]: "n < length xs \ xs!n \ set xs" by (auto simp add: set_conv_nth) lemma all_nth_imp_all_set: "\\i < length xs. P(xs!i); x \ set xs\ \ P x" by (auto simp add: set_conv_nth) lemma all_set_conv_all_nth: "(\x \ set xs. P x) = (\i. i < length xs \ P (xs ! i))" by (auto simp add: set_conv_nth) lemma rev_nth: "n < size xs \ rev xs ! n = xs ! (length xs - Suc n)" proof (induct xs arbitrary: n) case Nil thus ?case by simp next case (Cons x xs) hence n: "n < Suc (length xs)" by simp moreover { assume "n < length xs" with n obtain n' where n': "length xs - n = Suc n'" by (cases "length xs - n", auto) moreover from n' have "length xs - Suc n = n'" by simp ultimately have "xs ! (length xs - Suc n) = (x # xs) ! (length xs - n)" by simp } ultimately show ?case by (clarsimp simp add: Cons nth_append) qed lemma Skolem_list_nth: "(\ix. P i x) = (\xs. size xs = k \ (\ixs. ?P k xs)") proof(induct k) case 0 show ?case by simp next case (Suc k) show ?case (is "?L = ?R" is "_ = (\xs. ?P' xs)") proof assume "?R" thus "?L" using Suc by auto next assume "?L" with Suc obtain x xs where "?P k xs \ P k x" by (metis less_Suc_eq) hence "?P'(xs@[x])" by(simp add:nth_append less_Suc_eq) thus "?R" .. qed qed subsubsection \\<^const>\list_update\\ lemma length_list_update [simp]: "length(xs[i:=x]) = length xs" by (induct xs arbitrary: i) (auto split: nat.split) lemma nth_list_update: "i < length xs\ (xs[i:=x])!j = (if i = j then x else xs!j)" by (induct xs arbitrary: i j) (auto simp add: nth_Cons split: nat.split) lemma nth_list_update_eq [simp]: "i < length xs \ (xs[i:=x])!i = x" by (simp add: nth_list_update) lemma nth_list_update_neq [simp]: "i \ j \ xs[i:=x]!j = xs!j" by (induct xs arbitrary: i j) (auto simp add: nth_Cons split: nat.split) lemma list_update_id[simp]: "xs[i := xs!i] = xs" by (induct xs arbitrary: i) (simp_all split:nat.splits) lemma list_update_beyond[simp]: "length xs \ i \ xs[i:=x] = xs" proof (induct xs arbitrary: i) case (Cons x xs i) then show ?case by (metis leD length_list_update list_eq_iff_nth_eq nth_list_update_neq) qed simp lemma list_update_nonempty[simp]: "xs[k:=x] = [] \ xs=[]" by (simp only: length_0_conv[symmetric] length_list_update) lemma list_update_same_conv: "i < length xs \ (xs[i := x] = xs) = (xs!i = x)" by (induct xs arbitrary: i) (auto split: nat.split) lemma list_update_append1: "i < size xs \ (xs @ ys)[i:=x] = xs[i:=x] @ ys" by (induct xs arbitrary: i)(auto split:nat.split) lemma list_update_append: "(xs @ ys) [n:= x] = (if n < length xs then xs[n:= x] @ ys else xs @ (ys [n-length xs:= x]))" by (induct xs arbitrary: n) (auto split:nat.splits) lemma list_update_length [simp]: "(xs @ x # ys)[length xs := y] = (xs @ y # ys)" by (induct xs, auto) lemma map_update: "map f (xs[k:= y]) = (map f xs)[k := f y]" by(induct xs arbitrary: k)(auto split:nat.splits) lemma rev_update: "k < length xs \ rev (xs[k:= y]) = (rev xs)[length xs - k - 1 := y]" by (induct xs arbitrary: k) (auto simp: list_update_append split:nat.splits) lemma update_zip: "(zip xs ys)[i:=xy] = zip (xs[i:=fst xy]) (ys[i:=snd xy])" by (induct ys arbitrary: i xy xs) (auto, case_tac xs, auto split: nat.split) lemma set_update_subset_insert: "set(xs[i:=x]) \ insert x (set xs)" by (induct xs arbitrary: i) (auto split: nat.split) lemma set_update_subsetI: "\set xs \ A; x \ A\ \ set(xs[i := x]) \ A" by (blast dest!: set_update_subset_insert [THEN subsetD]) lemma set_update_memI: "n < length xs \ x \ set (xs[n := x])" by (induct xs arbitrary: n) (auto split:nat.splits) lemma list_update_overwrite[simp]: "xs [i := x, i := y] = xs [i := y]" by (induct xs arbitrary: i) (simp_all split: nat.split) lemma list_update_swap: "i \ i' \ xs [i := x, i' := x'] = xs [i' := x', i := x]" by (induct xs arbitrary: i i') (simp_all split: nat.split) lemma list_update_code [code]: "[][i := y] = []" "(x # xs)[0 := y] = y # xs" "(x # xs)[Suc i := y] = x # xs[i := y]" by simp_all subsubsection \\<^const>\last\ and \<^const>\butlast\\ lemma hd_Nil_eq_last: "hd Nil = last Nil" unfolding hd_def last_def by simp lemma last_snoc [simp]: "last (xs @ [x]) = x" by (induct xs) auto lemma butlast_snoc [simp]: "butlast (xs @ [x]) = xs" by (induct xs) auto lemma last_ConsL: "xs = [] \ last(x#xs) = x" by simp lemma last_ConsR: "xs \ [] \ last(x#xs) = last xs" by simp lemma last_append: "last(xs @ ys) = (if ys = [] then last xs else last ys)" by (induct xs) (auto) lemma last_appendL[simp]: "ys = [] \ last(xs @ ys) = last xs" by(simp add:last_append) lemma last_appendR[simp]: "ys \ [] \ last(xs @ ys) = last ys" by(simp add:last_append) lemma last_tl: "xs = [] \ tl xs \ [] \last (tl xs) = last xs" by (induct xs) simp_all lemma butlast_tl: "butlast (tl xs) = tl (butlast xs)" by (induct xs) simp_all lemma hd_rev: "hd(rev xs) = last xs" by (metis hd_Cons_tl hd_Nil_eq_last last_snoc rev_eq_Cons_iff rev_is_Nil_conv) lemma last_rev: "last(rev xs) = hd xs" by (metis hd_rev rev_swap) lemma last_in_set[simp]: "as \ [] \ last as \ set as" by (induct as) auto lemma length_butlast [simp]: "length (butlast xs) = length xs - 1" by (induct xs rule: rev_induct) auto lemma butlast_append: "butlast (xs @ ys) = (if ys = [] then butlast xs else xs @ butlast ys)" by (induct xs arbitrary: ys) auto lemma append_butlast_last_id [simp]: "xs \ [] \ butlast xs @ [last xs] = xs" by (induct xs) auto lemma in_set_butlastD: "x \ set (butlast xs) \ x \ set xs" by (induct xs) (auto split: if_split_asm) lemma in_set_butlast_appendI: "x \ set (butlast xs) \ x \ set (butlast ys) \ x \ set (butlast (xs @ ys))" by (auto dest: in_set_butlastD simp add: butlast_append) lemma last_drop[simp]: "n < length xs \ last (drop n xs) = last xs" by (induct xs arbitrary: n)(auto split:nat.split) lemma nth_butlast: assumes "n < length (butlast xs)" shows "butlast xs ! n = xs ! n" proof (cases xs) case (Cons y ys) moreover from assms have "butlast xs ! n = (butlast xs @ [last xs]) ! n" by (simp add: nth_append) ultimately show ?thesis using append_butlast_last_id by simp qed simp lemma last_conv_nth: "xs\[] \ last xs = xs!(length xs - 1)" by(induct xs)(auto simp:neq_Nil_conv) lemma butlast_conv_take: "butlast xs = take (length xs - 1) xs" by (induction xs rule: induct_list012) simp_all lemma last_list_update: "xs \ [] \ last(xs[k:=x]) = (if k = size xs - 1 then x else last xs)" by (auto simp: last_conv_nth) lemma butlast_list_update: "butlast(xs[k:=x]) = (if k = size xs - 1 then butlast xs else (butlast xs)[k:=x])" by(cases xs rule:rev_cases)(auto simp: list_update_append split: nat.splits) lemma last_map: "xs \ [] \ last (map f xs) = f (last xs)" by (cases xs rule: rev_cases) simp_all lemma map_butlast: "map f (butlast xs) = butlast (map f xs)" by (induct xs) simp_all lemma snoc_eq_iff_butlast: "xs @ [x] = ys \ (ys \ [] \ butlast ys = xs \ last ys = x)" by fastforce corollary longest_common_suffix: "\ss xs' ys'. xs = xs' @ ss \ ys = ys' @ ss \ (xs' = [] \ ys' = [] \ last xs' \ last ys')" using longest_common_prefix[of "rev xs" "rev ys"] unfolding rev_swap rev_append by (metis last_rev rev_is_Nil_conv) lemma butlast_rev [simp]: "butlast (rev xs) = rev (tl xs)" by (cases xs) simp_all subsubsection \\<^const>\take\ and \<^const>\drop\\ lemma take_0: "take 0 xs = []" by (induct xs) auto lemma drop_0: "drop 0 xs = xs" by (induct xs) auto lemma take0[simp]: "take 0 = (\xs. [])" by(rule ext) (rule take_0) lemma drop0[simp]: "drop 0 = (\x. x)" by(rule ext) (rule drop_0) lemma take_Suc_Cons [simp]: "take (Suc n) (x # xs) = x # take n xs" by simp lemma drop_Suc_Cons [simp]: "drop (Suc n) (x # xs) = drop n xs" by simp declare take_Cons [simp del] and drop_Cons [simp del] lemma take_Suc: "xs \ [] \ take (Suc n) xs = hd xs # take n (tl xs)" by(clarsimp simp add:neq_Nil_conv) lemma drop_Suc: "drop (Suc n) xs = drop n (tl xs)" by(cases xs, simp_all) lemma hd_take[simp]: "j > 0 \ hd (take j xs) = hd xs" by (metis gr0_conv_Suc list.sel(1) take.simps(1) take_Suc) lemma take_tl: "take n (tl xs) = tl (take (Suc n) xs)" by (induct xs arbitrary: n) simp_all lemma drop_tl: "drop n (tl xs) = tl(drop n xs)" by(induct xs arbitrary: n, simp_all add:drop_Cons drop_Suc split:nat.split) lemma tl_take: "tl (take n xs) = take (n - 1) (tl xs)" by (cases n, simp, cases xs, auto) lemma tl_drop: "tl (drop n xs) = drop n (tl xs)" by (simp only: drop_tl) lemma nth_via_drop: "drop n xs = y#ys \ xs!n = y" by (induct xs arbitrary: n, simp)(auto simp: drop_Cons nth_Cons split: nat.splits) lemma take_Suc_conv_app_nth: "i < length xs \ take (Suc i) xs = take i xs @ [xs!i]" proof (induct xs arbitrary: i) case Nil then show ?case by simp next case Cons then show ?case by (cases i) auto qed lemma Cons_nth_drop_Suc: "i < length xs \ (xs!i) # (drop (Suc i) xs) = drop i xs" proof (induct xs arbitrary: i) case Nil then show ?case by simp next case Cons then show ?case by (cases i) auto qed lemma length_take [simp]: "length (take n xs) = min (length xs) n" by (induct n arbitrary: xs) (auto, case_tac xs, auto) lemma length_drop [simp]: "length (drop n xs) = (length xs - n)" by (induct n arbitrary: xs) (auto, case_tac xs, auto) lemma take_all [simp]: "length xs \ n \ take n xs = xs" by (induct n arbitrary: xs) (auto, case_tac xs, auto) lemma drop_all [simp]: "length xs \ n \ drop n xs = []" by (induct n arbitrary: xs) (auto, case_tac xs, auto) lemma take_all_iff [simp]: "take n xs = xs \ length xs \ n" by (metis length_take min.order_iff take_all) lemma drop_all_iff [simp]: "drop n xs = [] \ length xs \ n" by (metis diff_is_0_eq drop_all length_drop list.size(3)) lemma take_append [simp]: "take n (xs @ ys) = (take n xs @ take (n - length xs) ys)" by (induct n arbitrary: xs) (auto, case_tac xs, auto) lemma drop_append [simp]: "drop n (xs @ ys) = drop n xs @ drop (n - length xs) ys" by (induct n arbitrary: xs) (auto, case_tac xs, auto) lemma take_take [simp]: "take n (take m xs) = take (min n m) xs" proof (induct m arbitrary: xs n) case 0 then show ?case by simp next case Suc then show ?case by (cases xs; cases n) simp_all qed lemma drop_drop [simp]: "drop n (drop m xs) = drop (n + m) xs" proof (induct m arbitrary: xs) case 0 then show ?case by simp next case Suc then show ?case by (cases xs) simp_all qed lemma take_drop: "take n (drop m xs) = drop m (take (n + m) xs)" proof (induct m arbitrary: xs n) case 0 then show ?case by simp next case Suc then show ?case by (cases xs; cases n) simp_all qed lemma drop_take: "drop n (take m xs) = take (m-n) (drop n xs)" by(induct xs arbitrary: m n)(auto simp: take_Cons drop_Cons split: nat.split) lemma append_take_drop_id [simp]: "take n xs @ drop n xs = xs" proof (induct n arbitrary: xs) case 0 then show ?case by simp next case Suc then show ?case by (cases xs) simp_all qed lemma take_eq_Nil[simp]: "(take n xs = []) = (n = 0 \ xs = [])" by(induct xs arbitrary: n)(auto simp: take_Cons split:nat.split) lemma drop_eq_Nil[simp]: "(drop n xs = []) = (length xs \ n)" by (induct xs arbitrary: n) (auto simp: drop_Cons split:nat.split) lemma take_map: "take n (map f xs) = map f (take n xs)" proof (induct n arbitrary: xs) case 0 then show ?case by simp next case Suc then show ?case by (cases xs) simp_all qed lemma drop_map: "drop n (map f xs) = map f (drop n xs)" proof (induct n arbitrary: xs) case 0 then show ?case by simp next case Suc then show ?case by (cases xs) simp_all qed lemma rev_take: "rev (take i xs) = drop (length xs - i) (rev xs)" proof (induct xs arbitrary: i) case Nil then show ?case by simp next case Cons then show ?case by (cases i) auto qed lemma rev_drop: "rev (drop i xs) = take (length xs - i) (rev xs)" proof (induct xs arbitrary: i) case Nil then show ?case by simp next case Cons then show ?case by (cases i) auto qed lemma drop_rev: "drop n (rev xs) = rev (take (length xs - n) xs)" by (cases "length xs < n") (auto simp: rev_take) lemma take_rev: "take n (rev xs) = rev (drop (length xs - n) xs)" by (cases "length xs < n") (auto simp: rev_drop) lemma nth_take [simp]: "i < n \ (take n xs)!i = xs!i" proof (induct xs arbitrary: i n) case Nil then show ?case by simp next case Cons then show ?case by (cases n; cases i) simp_all qed lemma nth_drop [simp]: "n \ length xs \ (drop n xs)!i = xs!(n + i)" proof (induct n arbitrary: xs) case 0 then show ?case by simp next case Suc then show ?case by (cases xs) simp_all qed lemma butlast_take: "n \ length xs \ butlast (take n xs) = take (n - 1) xs" by (simp add: butlast_conv_take min.absorb1 min.absorb2) lemma butlast_drop: "butlast (drop n xs) = drop n (butlast xs)" by (simp add: butlast_conv_take drop_take ac_simps) lemma take_butlast: "n < length xs \ take n (butlast xs) = take n xs" by (simp add: butlast_conv_take min.absorb1) lemma drop_butlast: "drop n (butlast xs) = butlast (drop n xs)" by (simp add: butlast_conv_take drop_take ac_simps) lemma butlast_power: "(butlast ^^ n) xs = take (length xs - n) xs" by (induct n) (auto simp: butlast_take) lemma hd_drop_conv_nth: "n < length xs \ hd(drop n xs) = xs!n" by(simp add: hd_conv_nth) lemma set_take_subset_set_take: "m \ n \ set(take m xs) \ set(take n xs)" proof (induct xs arbitrary: m n) case (Cons x xs m n) then show ?case by (cases n) (auto simp: take_Cons) qed simp lemma set_take_subset: "set(take n xs) \ set xs" by(induct xs arbitrary: n)(auto simp:take_Cons split:nat.split) lemma set_drop_subset: "set(drop n xs) \ set xs" by(induct xs arbitrary: n)(auto simp:drop_Cons split:nat.split) lemma set_drop_subset_set_drop: "m \ n \ set(drop m xs) \ set(drop n xs)" proof (induct xs arbitrary: m n) case (Cons x xs m n) then show ?case by (clarsimp simp: drop_Cons split: nat.split) (metis set_drop_subset subset_iff) qed simp lemma in_set_takeD: "x \ set(take n xs) \ x \ set xs" using set_take_subset by fast lemma in_set_dropD: "x \ set(drop n xs) \ x \ set xs" using set_drop_subset by fast lemma append_eq_conv_conj: "(xs @ ys = zs) = (xs = take (length xs) zs \ ys = drop (length xs) zs)" proof (induct xs arbitrary: zs) case (Cons x xs zs) then show ?case by (cases zs, auto) qed auto lemma map_eq_append_conv: "map f xs = ys @ zs \ (\us vs. xs = us @ vs \ ys = map f us \ zs = map f vs)" proof - have "map f xs \ ys @ zs \ map f xs \ ys @ zs \ map f xs \ ys @ zs \ map f xs = ys @ zs \ (\bs bsa. xs = bs @ bsa \ ys = map f bs \ zs = map f bsa)" by (metis append_eq_conv_conj append_take_drop_id drop_map take_map) then show ?thesis using map_append by blast qed lemma append_eq_map_conv: "ys @ zs = map f xs \ (\us vs. xs = us @ vs \ ys = map f us \ zs = map f vs)" by (metis map_eq_append_conv) lemma take_add: "take (i+j) xs = take i xs @ take j (drop i xs)" proof (induct xs arbitrary: i) case (Cons x xs i) then show ?case by (cases i, auto) qed auto lemma append_eq_append_conv_if: "(xs\<^sub>1 @ xs\<^sub>2 = ys\<^sub>1 @ ys\<^sub>2) = (if size xs\<^sub>1 \ size ys\<^sub>1 then xs\<^sub>1 = take (size xs\<^sub>1) ys\<^sub>1 \ xs\<^sub>2 = drop (size xs\<^sub>1) ys\<^sub>1 @ ys\<^sub>2 else take (size ys\<^sub>1) xs\<^sub>1 = ys\<^sub>1 \ drop (size ys\<^sub>1) xs\<^sub>1 @ xs\<^sub>2 = ys\<^sub>2)" proof (induct xs\<^sub>1 arbitrary: ys\<^sub>1) case (Cons a xs\<^sub>1 ys\<^sub>1) then show ?case by (cases ys\<^sub>1, auto) qed auto lemma take_hd_drop: "n < length xs \ take n xs @ [hd (drop n xs)] = take (Suc n) xs" by (induct xs arbitrary: n) (simp_all add:drop_Cons split:nat.split) lemma id_take_nth_drop: "i < length xs \ xs = take i xs @ xs!i # drop (Suc i) xs" proof - assume si: "i < length xs" hence "xs = take (Suc i) xs @ drop (Suc i) xs" by auto moreover from si have "take (Suc i) xs = take i xs @ [xs!i]" using take_Suc_conv_app_nth by blast ultimately show ?thesis by auto qed lemma take_update_cancel[simp]: "n \ m \ take n (xs[m := y]) = take n xs" by(simp add: list_eq_iff_nth_eq) lemma drop_update_cancel[simp]: "n < m \ drop m (xs[n := x]) = drop m xs" by(simp add: list_eq_iff_nth_eq) lemma upd_conv_take_nth_drop: "i < length xs \ xs[i:=a] = take i xs @ a # drop (Suc i) xs" proof - assume i: "i < length xs" have "xs[i:=a] = (take i xs @ xs!i # drop (Suc i) xs)[i:=a]" by(rule arg_cong[OF id_take_nth_drop[OF i]]) also have "\ = take i xs @ a # drop (Suc i) xs" using i by (simp add: list_update_append) finally show ?thesis . qed lemma take_update_swap: "take m (xs[n := x]) = (take m xs)[n := x]" proof (cases "n \ length xs") case False then show ?thesis by (simp add: upd_conv_take_nth_drop take_Cons drop_take min_def diff_Suc split: nat.split) qed auto lemma drop_update_swap: assumes "m \ n" shows "drop m (xs[n := x]) = (drop m xs)[n-m := x]" proof (cases "n \ length xs") case False with assms show ?thesis by (simp add: upd_conv_take_nth_drop drop_take) qed auto lemma nth_image: "l \ size xs \ nth xs ` {0..\<^const>\takeWhile\ and \<^const>\dropWhile\\ lemma length_takeWhile_le: "length (takeWhile P xs) \ length xs" by (induct xs) auto lemma takeWhile_dropWhile_id [simp]: "takeWhile P xs @ dropWhile P xs = xs" by (induct xs) auto lemma takeWhile_append1 [simp]: "\x \ set xs; \P(x)\ \ takeWhile P (xs @ ys) = takeWhile P xs" by (induct xs) auto lemma takeWhile_append2 [simp]: "(\x. x \ set xs \ P x) \ takeWhile P (xs @ ys) = xs @ takeWhile P ys" by (induct xs) auto lemma takeWhile_append: "takeWhile P (xs @ ys) = (if \x\set xs. P x then xs @ takeWhile P ys else takeWhile P xs)" using takeWhile_append1[of _ xs P ys] takeWhile_append2[of xs P ys] by auto lemma takeWhile_tail: "\ P x \ takeWhile P (xs @ (x#l)) = takeWhile P xs" by (induct xs) auto lemma takeWhile_eq_Nil_iff: "takeWhile P xs = [] \ xs = [] \ \P (hd xs)" by (cases xs) auto lemma takeWhile_nth: "j < length (takeWhile P xs) \ takeWhile P xs ! j = xs ! j" by (metis nth_append takeWhile_dropWhile_id) lemma dropWhile_nth: "j < length (dropWhile P xs) \ dropWhile P xs ! j = xs ! (j + length (takeWhile P xs))" by (metis add.commute nth_append_length_plus takeWhile_dropWhile_id) lemma length_dropWhile_le: "length (dropWhile P xs) \ length xs" by (induct xs) auto lemma dropWhile_append1 [simp]: "\x \ set xs; \P(x)\ \ dropWhile P (xs @ ys) = (dropWhile P xs)@ys" by (induct xs) auto lemma dropWhile_append2 [simp]: "(\x. x \ set xs \ P(x)) \ dropWhile P (xs @ ys) = dropWhile P ys" by (induct xs) auto lemma dropWhile_append3: "\ P y \dropWhile P (xs @ y # ys) = dropWhile P xs @ y # ys" by (induct xs) auto lemma dropWhile_append: "dropWhile P (xs @ ys) = (if \x\set xs. P x then dropWhile P ys else dropWhile P xs @ ys)" using dropWhile_append1[of _ xs P ys] dropWhile_append2[of xs P ys] by auto lemma dropWhile_last: "x \ set xs \ \ P x \ last (dropWhile P xs) = last xs" by (auto simp add: dropWhile_append3 in_set_conv_decomp) lemma set_dropWhileD: "x \ set (dropWhile P xs) \ x \ set xs" by (induct xs) (auto split: if_split_asm) lemma set_takeWhileD: "x \ set (takeWhile P xs) \ x \ set xs \ P x" by (induct xs) (auto split: if_split_asm) lemma takeWhile_eq_all_conv[simp]: "(takeWhile P xs = xs) = (\x \ set xs. P x)" by(induct xs, auto) lemma dropWhile_eq_Nil_conv[simp]: "(dropWhile P xs = []) = (\x \ set xs. P x)" by(induct xs, auto) lemma dropWhile_eq_Cons_conv: "(dropWhile P xs = y#ys) = (xs = takeWhile P xs @ y # ys \ \ P y)" by(induct xs, auto) lemma dropWhile_eq_self_iff: "dropWhile P xs = xs \ xs = [] \ \P (hd xs)" by (cases xs) (auto simp: dropWhile_eq_Cons_conv) lemma distinct_takeWhile[simp]: "distinct xs \ distinct (takeWhile P xs)" by (induct xs) (auto dest: set_takeWhileD) lemma distinct_dropWhile[simp]: "distinct xs \ distinct (dropWhile P xs)" by (induct xs) auto lemma takeWhile_map: "takeWhile P (map f xs) = map f (takeWhile (P \ f) xs)" by (induct xs) auto lemma dropWhile_map: "dropWhile P (map f xs) = map f (dropWhile (P \ f) xs)" by (induct xs) auto lemma takeWhile_eq_take: "takeWhile P xs = take (length (takeWhile P xs)) xs" by (induct xs) auto lemma dropWhile_eq_drop: "dropWhile P xs = drop (length (takeWhile P xs)) xs" by (induct xs) auto lemma hd_dropWhile: "dropWhile P xs \ [] \ \ P (hd (dropWhile P xs))" by (induct xs) auto lemma takeWhile_eq_filter: assumes "\ x. x \ set (dropWhile P xs) \ \ P x" shows "takeWhile P xs = filter P xs" proof - have A: "filter P xs = filter P (takeWhile P xs @ dropWhile P xs)" by simp have B: "filter P (dropWhile P xs) = []" unfolding filter_empty_conv using assms by blast have "filter P xs = takeWhile P xs" unfolding A filter_append B by (auto simp add: filter_id_conv dest: set_takeWhileD) thus ?thesis .. qed lemma takeWhile_eq_take_P_nth: "\ \ i. \ i < n ; i < length xs \ \ P (xs ! i) ; n < length xs \ \ P (xs ! n) \ \ takeWhile P xs = take n xs" proof (induct xs arbitrary: n) case Nil thus ?case by simp next case (Cons x xs) show ?case proof (cases n) case 0 with Cons show ?thesis by simp next case [simp]: (Suc n') have "P x" using Cons.prems(1)[of 0] by simp moreover have "takeWhile P xs = take n' xs" proof (rule Cons.hyps) fix i assume "i < n'" "i < length xs" thus "P (xs ! i)" using Cons.prems(1)[of "Suc i"] by simp next assume "n' < length xs" thus "\ P (xs ! n')" using Cons by auto qed ultimately show ?thesis by simp qed qed lemma nth_length_takeWhile: "length (takeWhile P xs) < length xs \ \ P (xs ! length (takeWhile P xs))" by (induct xs) auto lemma length_takeWhile_less_P_nth: assumes all: "\ i. i < j \ P (xs ! i)" and "j \ length xs" shows "j \ length (takeWhile P xs)" proof (rule classical) assume "\ ?thesis" hence "length (takeWhile P xs) < length xs" using assms by simp thus ?thesis using all \\ ?thesis\ nth_length_takeWhile[of P xs] by auto qed lemma takeWhile_neq_rev: "\distinct xs; x \ set xs\ \ takeWhile (\y. y \ x) (rev xs) = rev (tl (dropWhile (\y. y \ x) xs))" by(induct xs) (auto simp: takeWhile_tail[where l="[]"]) lemma dropWhile_neq_rev: "\distinct xs; x \ set xs\ \ dropWhile (\y. y \ x) (rev xs) = x # rev (takeWhile (\y. y \ x) xs)" proof (induct xs) case (Cons a xs) then show ?case by(auto, subst dropWhile_append2, auto) qed simp lemma takeWhile_not_last: "distinct xs \ takeWhile (\y. y \ last xs) xs = butlast xs" by(induction xs rule: induct_list012) auto lemma takeWhile_cong [fundef_cong]: "\l = k; \x. x \ set l \ P x = Q x\ \ takeWhile P l = takeWhile Q k" by (induct k arbitrary: l) (simp_all) lemma dropWhile_cong [fundef_cong]: "\l = k; \x. x \ set l \ P x = Q x\ \ dropWhile P l = dropWhile Q k" by (induct k arbitrary: l, simp_all) lemma takeWhile_idem [simp]: "takeWhile P (takeWhile P xs) = takeWhile P xs" by (induct xs) auto lemma dropWhile_idem [simp]: "dropWhile P (dropWhile P xs) = dropWhile P xs" by (induct xs) auto subsubsection \\<^const>\zip\\ lemma zip_Nil [simp]: "zip [] ys = []" by (induct ys) auto lemma zip_Cons_Cons [simp]: "zip (x # xs) (y # ys) = (x, y) # zip xs ys" by simp declare zip_Cons [simp del] lemma [code]: "zip [] ys = []" "zip xs [] = []" "zip (x # xs) (y # ys) = (x, y) # zip xs ys" by (fact zip_Nil zip.simps(1) zip_Cons_Cons)+ lemma zip_Cons1: "zip (x#xs) ys = (case ys of [] \ [] | y#ys \ (x,y)#zip xs ys)" by(auto split:list.split) lemma length_zip [simp]: "length (zip xs ys) = min (length xs) (length ys)" by (induct xs ys rule:list_induct2') auto lemma zip_obtain_same_length: assumes "\zs ws n. length zs = length ws \ n = min (length xs) (length ys) \ zs = take n xs \ ws = take n ys \ P (zip zs ws)" shows "P (zip xs ys)" proof - let ?n = "min (length xs) (length ys)" have "P (zip (take ?n xs) (take ?n ys))" by (rule assms) simp_all moreover have "zip xs ys = zip (take ?n xs) (take ?n ys)" proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case (Cons x xs) then show ?case by (cases ys) simp_all qed ultimately show ?thesis by simp qed lemma zip_append1: "zip (xs @ ys) zs = zip xs (take (length xs) zs) @ zip ys (drop (length xs) zs)" by (induct xs zs rule:list_induct2') auto lemma zip_append2: "zip xs (ys @ zs) = zip (take (length ys) xs) ys @ zip (drop (length ys) xs) zs" by (induct xs ys rule:list_induct2') auto lemma zip_append [simp]: "\length xs = length us\ \ zip (xs@ys) (us@vs) = zip xs us @ zip ys vs" by (simp add: zip_append1) lemma zip_rev: "length xs = length ys \ zip (rev xs) (rev ys) = rev (zip xs ys)" by (induct rule:list_induct2, simp_all) lemma zip_map_map: "zip (map f xs) (map g ys) = map (\ (x, y). (f x, g y)) (zip xs ys)" proof (induct xs arbitrary: ys) case (Cons x xs) note Cons_x_xs = Cons.hyps show ?case proof (cases ys) case (Cons y ys') show ?thesis unfolding Cons using Cons_x_xs by simp qed simp qed simp lemma zip_map1: "zip (map f xs) ys = map (\(x, y). (f x, y)) (zip xs ys)" using zip_map_map[of f xs "\x. x" ys] by simp lemma zip_map2: "zip xs (map f ys) = map (\(x, y). (x, f y)) (zip xs ys)" using zip_map_map[of "\x. x" xs f ys] by simp lemma map_zip_map: "map f (zip (map g xs) ys) = map (%(x,y). f(g x, y)) (zip xs ys)" by (auto simp: zip_map1) lemma map_zip_map2: "map f (zip xs (map g ys)) = map (%(x,y). f(x, g y)) (zip xs ys)" by (auto simp: zip_map2) text\Courtesy of Andreas Lochbihler:\ lemma zip_same_conv_map: "zip xs xs = map (\x. (x, x)) xs" by(induct xs) auto lemma nth_zip [simp]: "\i < length xs; i < length ys\ \ (zip xs ys)!i = (xs!i, ys!i)" proof (induct ys arbitrary: i xs) case (Cons y ys) then show ?case by (cases xs) (simp_all add: nth.simps split: nat.split) qed auto lemma set_zip: "set (zip xs ys) = {(xs!i, ys!i) | i. i < min (length xs) (length ys)}" by(simp add: set_conv_nth cong: rev_conj_cong) lemma zip_same: "((a,b) \ set (zip xs xs)) = (a \ set xs \ a = b)" by(induct xs) auto lemma zip_update: "zip (xs[i:=x]) (ys[i:=y]) = (zip xs ys)[i:=(x,y)]" by (simp add: update_zip) lemma zip_replicate [simp]: "zip (replicate i x) (replicate j y) = replicate (min i j) (x,y)" proof (induct i arbitrary: j) case (Suc i) then show ?case by (cases j, auto) qed auto lemma zip_replicate1: "zip (replicate n x) ys = map (Pair x) (take n ys)" by(induction ys arbitrary: n)(case_tac [2] n, simp_all) lemma take_zip: "take n (zip xs ys) = zip (take n xs) (take n ys)" proof (induct n arbitrary: xs ys) case 0 then show ?case by simp next case Suc then show ?case by (cases xs; cases ys) simp_all qed lemma drop_zip: "drop n (zip xs ys) = zip (drop n xs) (drop n ys)" proof (induct n arbitrary: xs ys) case 0 then show ?case by simp next case Suc then show ?case by (cases xs; cases ys) simp_all qed lemma zip_takeWhile_fst: "zip (takeWhile P xs) ys = takeWhile (P \ fst) (zip xs ys)" proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case Cons then show ?case by (cases ys) auto qed lemma zip_takeWhile_snd: "zip xs (takeWhile P ys) = takeWhile (P \ snd) (zip xs ys)" proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case Cons then show ?case by (cases ys) auto qed lemma set_zip_leftD: "(x,y)\ set (zip xs ys) \ x \ set xs" by (induct xs ys rule:list_induct2') auto lemma set_zip_rightD: "(x,y)\ set (zip xs ys) \ y \ set ys" by (induct xs ys rule:list_induct2') auto lemma in_set_zipE: "(x,y) \ set(zip xs ys) \ (\ x \ set xs; y \ set ys \ \ R) \ R" by(blast dest: set_zip_leftD set_zip_rightD) lemma zip_map_fst_snd: "zip (map fst zs) (map snd zs) = zs" by (induct zs) simp_all lemma zip_eq_conv: "length xs = length ys \ zip xs ys = zs \ map fst zs = xs \ map snd zs = ys" by (auto simp add: zip_map_fst_snd) lemma in_set_zip: "p \ set (zip xs ys) \ (\n. xs ! n = fst p \ ys ! n = snd p \ n < length xs \ n < length ys)" by (cases p) (auto simp add: set_zip) lemma in_set_impl_in_set_zip1: assumes "length xs = length ys" assumes "x \ set xs" obtains y where "(x, y) \ set (zip xs ys)" proof - from assms have "x \ set (map fst (zip xs ys))" by simp from this that show ?thesis by fastforce qed lemma in_set_impl_in_set_zip2: assumes "length xs = length ys" assumes "y \ set ys" obtains x where "(x, y) \ set (zip xs ys)" proof - from assms have "y \ set (map snd (zip xs ys))" by simp from this that show ?thesis by fastforce qed lemma zip_eq_Nil_iff: "zip xs ys = [] \ xs = [] \ ys = []" by (cases xs; cases ys) simp_all lemma zip_eq_ConsE: assumes "zip xs ys = xy # xys" obtains x xs' y ys' where "xs = x # xs'" and "ys = y # ys'" and "xy = (x, y)" and "xys = zip xs' ys'" proof - from assms have "xs \ []" and "ys \ []" using zip_eq_Nil_iff [of xs ys] by simp_all then obtain x xs' y ys' where xs: "xs = x # xs'" and ys: "ys = y # ys'" by (cases xs; cases ys) auto with assms have "xy = (x, y)" and "xys = zip xs' ys'" by simp_all with xs ys show ?thesis .. qed lemma semilattice_map2: "semilattice (map2 (\<^bold>*))" if "semilattice (\<^bold>*)" for f (infixl "\<^bold>*" 70) proof - from that interpret semilattice f . show ?thesis proof show "map2 (\<^bold>*) (map2 (\<^bold>*) xs ys) zs = map2 (\<^bold>*) xs (map2 (\<^bold>*) ys zs)" for xs ys zs :: "'a list" proof (induction "zip xs (zip ys zs)" arbitrary: xs ys zs) case Nil from Nil [symmetric] show ?case by (auto simp add: zip_eq_Nil_iff) next case (Cons xyz xyzs) from Cons.hyps(2) [symmetric] show ?case by (rule zip_eq_ConsE) (erule zip_eq_ConsE, auto intro: Cons.hyps(1) simp add: ac_simps) qed show "map2 (\<^bold>*) xs ys = map2 (\<^bold>*) ys xs" for xs ys :: "'a list" proof (induction "zip xs ys" arbitrary: xs ys) case Nil then show ?case by (auto simp add: zip_eq_Nil_iff dest: sym) next case (Cons xy xys) from Cons.hyps(2) [symmetric] show ?case by (rule zip_eq_ConsE) (auto intro: Cons.hyps(1) simp add: ac_simps) qed show "map2 (\<^bold>*) xs xs = xs" for xs :: "'a list" by (induction xs) simp_all qed qed lemma pair_list_eqI: assumes "map fst xs = map fst ys" and "map snd xs = map snd ys" shows "xs = ys" proof - from assms(1) have "length xs = length ys" by (rule map_eq_imp_length_eq) from this assms show ?thesis by (induct xs ys rule: list_induct2) (simp_all add: prod_eqI) qed lemma hd_zip: \hd (zip xs ys) = (hd xs, hd ys)\ if \xs \ []\ and \ys \ []\ using that by (cases xs; cases ys) simp_all lemma last_zip: \last (zip xs ys) = (last xs, last ys)\ if \xs \ []\ and \ys \ []\ and \length xs = length ys\ using that by (cases xs rule: rev_cases; cases ys rule: rev_cases) simp_all subsubsection \\<^const>\list_all2\\ lemma list_all2_lengthD [intro?]: "list_all2 P xs ys \ length xs = length ys" by (simp add: list_all2_iff) lemma list_all2_Nil [iff, code]: "list_all2 P [] ys = (ys = [])" by (simp add: list_all2_iff) lemma list_all2_Nil2 [iff, code]: "list_all2 P xs [] = (xs = [])" by (simp add: list_all2_iff) lemma list_all2_Cons [iff, code]: "list_all2 P (x # xs) (y # ys) = (P x y \ list_all2 P xs ys)" by (auto simp add: list_all2_iff) lemma list_all2_Cons1: "list_all2 P (x # xs) ys = (\z zs. ys = z # zs \ P x z \ list_all2 P xs zs)" by (cases ys) auto lemma list_all2_Cons2: "list_all2 P xs (y # ys) = (\z zs. xs = z # zs \ P z y \ list_all2 P zs ys)" by (cases xs) auto lemma list_all2_induct [consumes 1, case_names Nil Cons, induct set: list_all2]: assumes P: "list_all2 P xs ys" assumes Nil: "R [] []" assumes Cons: "\x xs y ys. \P x y; list_all2 P xs ys; R xs ys\ \ R (x # xs) (y # ys)" shows "R xs ys" using P by (induct xs arbitrary: ys) (auto simp add: list_all2_Cons1 Nil Cons) lemma list_all2_rev [iff]: "list_all2 P (rev xs) (rev ys) = list_all2 P xs ys" by (simp add: list_all2_iff zip_rev cong: conj_cong) lemma list_all2_rev1: "list_all2 P (rev xs) ys = list_all2 P xs (rev ys)" by (subst list_all2_rev [symmetric]) simp lemma list_all2_append1: "list_all2 P (xs @ ys) zs = (\us vs. zs = us @ vs \ length us = length xs \ length vs = length ys \ list_all2 P xs us \ list_all2 P ys vs)" (is "?lhs = ?rhs") proof assume ?lhs then show ?rhs apply (rule_tac x = "take (length xs) zs" in exI) apply (rule_tac x = "drop (length xs) zs" in exI) apply (force split: nat_diff_split simp add: list_all2_iff zip_append1) done next assume ?rhs then show ?lhs by (auto simp add: list_all2_iff) qed lemma list_all2_append2: "list_all2 P xs (ys @ zs) = (\us vs. xs = us @ vs \ length us = length ys \ length vs = length zs \ list_all2 P us ys \ list_all2 P vs zs)" (is "?lhs = ?rhs") proof assume ?lhs then show ?rhs apply (rule_tac x = "take (length ys) xs" in exI) apply (rule_tac x = "drop (length ys) xs" in exI) apply (force split: nat_diff_split simp add: list_all2_iff zip_append2) done next assume ?rhs then show ?lhs by (auto simp add: list_all2_iff) qed lemma list_all2_append: "length xs = length ys \ list_all2 P (xs@us) (ys@vs) = (list_all2 P xs ys \ list_all2 P us vs)" by (induct rule:list_induct2, simp_all) lemma list_all2_appendI [intro?, trans]: "\ list_all2 P a b; list_all2 P c d \ \ list_all2 P (a@c) (b@d)" by (simp add: list_all2_append list_all2_lengthD) lemma list_all2_conv_all_nth: "list_all2 P xs ys = (length xs = length ys \ (\i < length xs. P (xs!i) (ys!i)))" by (force simp add: list_all2_iff set_zip) lemma list_all2_trans: assumes tr: "!!a b c. P1 a b \ P2 b c \ P3 a c" shows "!!bs cs. list_all2 P1 as bs \ list_all2 P2 bs cs \ list_all2 P3 as cs" (is "!!bs cs. PROP ?Q as bs cs") proof (induct as) fix x xs bs assume I1: "!!bs cs. PROP ?Q xs bs cs" show "!!cs. PROP ?Q (x # xs) bs cs" proof (induct bs) fix y ys cs assume I2: "!!cs. PROP ?Q (x # xs) ys cs" show "PROP ?Q (x # xs) (y # ys) cs" by (induct cs) (auto intro: tr I1 I2) qed simp qed simp lemma list_all2_all_nthI [intro?]: "length a = length b \ (\n. n < length a \ P (a!n) (b!n)) \ list_all2 P a b" by (simp add: list_all2_conv_all_nth) lemma list_all2I: "\x \ set (zip a b). case_prod P x \ length a = length b \ list_all2 P a b" by (simp add: list_all2_iff) lemma list_all2_nthD: "\ list_all2 P xs ys; p < size xs \ \ P (xs!p) (ys!p)" by (simp add: list_all2_conv_all_nth) lemma list_all2_nthD2: "\list_all2 P xs ys; p < size ys\ \ P (xs!p) (ys!p)" by (frule list_all2_lengthD) (auto intro: list_all2_nthD) lemma list_all2_map1: "list_all2 P (map f as) bs = list_all2 (\x y. P (f x) y) as bs" by (simp add: list_all2_conv_all_nth) lemma list_all2_map2: "list_all2 P as (map f bs) = list_all2 (\x y. P x (f y)) as bs" by (auto simp add: list_all2_conv_all_nth) lemma list_all2_refl [intro?]: "(\x. P x x) \ list_all2 P xs xs" by (simp add: list_all2_conv_all_nth) lemma list_all2_update_cong: "\ list_all2 P xs ys; P x y \ \ list_all2 P (xs[i:=x]) (ys[i:=y])" by (cases "i < length ys") (auto simp add: list_all2_conv_all_nth nth_list_update) lemma list_all2_takeI [simp,intro?]: "list_all2 P xs ys \ list_all2 P (take n xs) (take n ys)" proof (induct xs arbitrary: n ys) case (Cons x xs) then show ?case by (cases n) (auto simp: list_all2_Cons1) qed auto lemma list_all2_dropI [simp,intro?]: "list_all2 P xs ys \ list_all2 P (drop n xs) (drop n ys)" proof (induct xs arbitrary: n ys) case (Cons x xs) then show ?case by (cases n) (auto simp: list_all2_Cons1) qed auto lemma list_all2_mono [intro?]: "list_all2 P xs ys \ (\xs ys. P xs ys \ Q xs ys) \ list_all2 Q xs ys" by (rule list.rel_mono_strong) lemma list_all2_eq: "xs = ys \ list_all2 (=) xs ys" by (induct xs ys rule: list_induct2') auto lemma list_eq_iff_zip_eq: "xs = ys \ length xs = length ys \ (\(x,y) \ set (zip xs ys). x = y)" by(auto simp add: set_zip list_all2_eq list_all2_conv_all_nth cong: conj_cong) lemma list_all2_same: "list_all2 P xs xs \ (\x\set xs. P x x)" by(auto simp add: list_all2_conv_all_nth set_conv_nth) lemma zip_assoc: "zip xs (zip ys zs) = map (\((x, y), z). (x, y, z)) (zip (zip xs ys) zs)" by(rule list_all2_all_nthI[where P="(=)", unfolded list.rel_eq]) simp_all lemma zip_commute: "zip xs ys = map (\(x, y). (y, x)) (zip ys xs)" by(rule list_all2_all_nthI[where P="(=)", unfolded list.rel_eq]) simp_all lemma zip_left_commute: "zip xs (zip ys zs) = map (\(y, (x, z)). (x, y, z)) (zip ys (zip xs zs))" by(rule list_all2_all_nthI[where P="(=)", unfolded list.rel_eq]) simp_all lemma zip_replicate2: "zip xs (replicate n y) = map (\x. (x, y)) (take n xs)" by(subst zip_commute)(simp add: zip_replicate1) subsubsection \\<^const>\List.product\ and \<^const>\product_lists\\ lemma product_concat_map: "List.product xs ys = concat (map (\x. map (\y. (x,y)) ys) xs)" by(induction xs) (simp)+ lemma set_product[simp]: "set (List.product xs ys) = set xs \ set ys" by (induct xs) auto lemma length_product [simp]: "length (List.product xs ys) = length xs * length ys" by (induct xs) simp_all lemma product_nth: assumes "n < length xs * length ys" shows "List.product xs ys ! n = (xs ! (n div length ys), ys ! (n mod length ys))" using assms proof (induct xs arbitrary: n) case Nil then show ?case by simp next case (Cons x xs n) then have "length ys > 0" by auto with Cons show ?case by (auto simp add: nth_append not_less le_mod_geq le_div_geq) qed lemma in_set_product_lists_length: "xs \ set (product_lists xss) \ length xs = length xss" by (induct xss arbitrary: xs) auto lemma product_lists_set: "set (product_lists xss) = {xs. list_all2 (\x ys. x \ set ys) xs xss}" (is "?L = Collect ?R") proof (intro equalityI subsetI, unfold mem_Collect_eq) fix xs assume "xs \ ?L" then have "length xs = length xss" by (rule in_set_product_lists_length) from this \xs \ ?L\ show "?R xs" by (induct xs xss rule: list_induct2) auto next fix xs assume "?R xs" then show "xs \ ?L" by induct auto qed subsubsection \\<^const>\fold\ with natural argument order\ lemma fold_simps [code]: \ \eta-expanded variant for generated code -- enables tail-recursion optimisation in Scala\ "fold f [] s = s" "fold f (x # xs) s = fold f xs (f x s)" by simp_all lemma fold_remove1_split: "\ \x y. x \ set xs \ y \ set xs \ f x \ f y = f y \ f x; x \ set xs \ \ fold f xs = fold f (remove1 x xs) \ f x" by (induct xs) (auto simp add: comp_assoc) lemma fold_cong [fundef_cong]: "a = b \ xs = ys \ (\x. x \ set xs \ f x = g x) \ fold f xs a = fold g ys b" by (induct ys arbitrary: a b xs) simp_all lemma fold_id: "(\x. x \ set xs \ f x = id) \ fold f xs = id" by (induct xs) simp_all lemma fold_commute: "(\x. x \ set xs \ h \ g x = f x \ h) \ h \ fold g xs = fold f xs \ h" by (induct xs) (simp_all add: fun_eq_iff) lemma fold_commute_apply: assumes "\x. x \ set xs \ h \ g x = f x \ h" shows "h (fold g xs s) = fold f xs (h s)" proof - from assms have "h \ fold g xs = fold f xs \ h" by (rule fold_commute) then show ?thesis by (simp add: fun_eq_iff) qed lemma fold_invariant: "\ \x. x \ set xs \ Q x; P s; \x s. Q x \ P s \ P (f x s) \ \ P (fold f xs s)" by (induct xs arbitrary: s) simp_all lemma fold_append [simp]: "fold f (xs @ ys) = fold f ys \ fold f xs" by (induct xs) simp_all lemma fold_map [code_unfold]: "fold g (map f xs) = fold (g \ f) xs" by (induct xs) simp_all lemma fold_filter: "fold f (filter P xs) = fold (\x. if P x then f x else id) xs" by (induct xs) simp_all lemma fold_rev: "(\x y. x \ set xs \ y \ set xs \ f y \ f x = f x \ f y) \ fold f (rev xs) = fold f xs" by (induct xs) (simp_all add: fold_commute_apply fun_eq_iff) lemma fold_Cons_rev: "fold Cons xs = append (rev xs)" by (induct xs) simp_all lemma rev_conv_fold [code]: "rev xs = fold Cons xs []" by (simp add: fold_Cons_rev) lemma fold_append_concat_rev: "fold append xss = append (concat (rev xss))" by (induct xss) simp_all text \\<^const>\Finite_Set.fold\ and \<^const>\fold\\ -lemma (in comp_fun_commute) fold_set_fold_remdups: - "Finite_Set.fold f y (set xs) = fold f (remdups xs) y" - by (rule sym, induct xs arbitrary: y) (simp_all add: fold_fun_left_comm insert_absorb) - -lemma (in comp_fun_idem) fold_set_fold: - "Finite_Set.fold f y (set xs) = fold f xs y" - by (rule sym, induct xs arbitrary: y) (simp_all add: fold_fun_left_comm) +lemma (in comp_fun_commute_on) fold_set_fold_remdups: + assumes "set xs \ S" + shows "Finite_Set.fold f y (set xs) = fold f (remdups xs) y" + by (rule sym, use assms in \induct xs arbitrary: y\) + (simp_all add: insert_absorb fold_fun_left_comm) + +lemma (in comp_fun_idem_on) fold_set_fold: + assumes "set xs \ S" + shows "Finite_Set.fold f y (set xs) = fold f xs y" + by (rule sym, use assms in \induct xs arbitrary: y\) (simp_all add: fold_fun_left_comm) lemma union_set_fold [code]: "set xs \ A = fold Set.insert xs A" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) show ?thesis by (simp add: union_fold_insert fold_set_fold) qed lemma union_coset_filter [code]: "List.coset xs \ A = List.coset (List.filter (\x. x \ A) xs)" by auto lemma minus_set_fold [code]: "A - set xs = fold Set.remove xs A" proof - interpret comp_fun_idem Set.remove by (fact comp_fun_idem_remove) show ?thesis by (simp add: minus_fold_remove [of _ A] fold_set_fold) qed lemma minus_coset_filter [code]: "A - List.coset xs = set (List.filter (\x. x \ A) xs)" by auto lemma inter_set_filter [code]: "A \ set xs = set (List.filter (\x. x \ A) xs)" by auto lemma inter_coset_fold [code]: "A \ List.coset xs = fold Set.remove xs A" by (simp add: Diff_eq [symmetric] minus_set_fold) lemma (in semilattice_set) set_eq_fold [code]: "F (set (x # xs)) = fold f xs x" proof - interpret comp_fun_idem f by standard (simp_all add: fun_eq_iff left_commute) show ?thesis by (simp add: eq_fold fold_set_fold) qed lemma (in complete_lattice) Inf_set_fold: "Inf (set xs) = fold inf xs top" proof - interpret comp_fun_idem "inf :: 'a \ 'a \ 'a" by (fact comp_fun_idem_inf) show ?thesis by (simp add: Inf_fold_inf fold_set_fold inf_commute) qed declare Inf_set_fold [where 'a = "'a set", code] lemma (in complete_lattice) Sup_set_fold: "Sup (set xs) = fold sup xs bot" proof - interpret comp_fun_idem "sup :: 'a \ 'a \ 'a" by (fact comp_fun_idem_sup) show ?thesis by (simp add: Sup_fold_sup fold_set_fold sup_commute) qed declare Sup_set_fold [where 'a = "'a set", code] lemma (in complete_lattice) INF_set_fold: "\(f ` set xs) = fold (inf \ f) xs top" using Inf_set_fold [of "map f xs"] by (simp add: fold_map) lemma (in complete_lattice) SUP_set_fold: "\(f ` set xs) = fold (sup \ f) xs bot" using Sup_set_fold [of "map f xs"] by (simp add: fold_map) subsubsection \Fold variants: \<^const>\foldr\ and \<^const>\foldl\\ text \Correspondence\ lemma foldr_conv_fold [code_abbrev]: "foldr f xs = fold f (rev xs)" by (induct xs) simp_all lemma foldl_conv_fold: "foldl f s xs = fold (\x s. f s x) xs s" by (induct xs arbitrary: s) simp_all lemma foldr_conv_foldl: \ \The ``Third Duality Theorem'' in Bird \& Wadler:\ "foldr f xs a = foldl (\x y. f y x) a (rev xs)" by (simp add: foldr_conv_fold foldl_conv_fold) lemma foldl_conv_foldr: "foldl f a xs = foldr (\x y. f y x) (rev xs) a" by (simp add: foldr_conv_fold foldl_conv_fold) lemma foldr_fold: "(\x y. x \ set xs \ y \ set xs \ f y \ f x = f x \ f y) \ foldr f xs = fold f xs" unfolding foldr_conv_fold by (rule fold_rev) lemma foldr_cong [fundef_cong]: "a = b \ l = k \ (\a x. x \ set l \ f x a = g x a) \ foldr f l a = foldr g k b" by (auto simp add: foldr_conv_fold intro!: fold_cong) lemma foldl_cong [fundef_cong]: "a = b \ l = k \ (\a x. x \ set l \ f a x = g a x) \ foldl f a l = foldl g b k" by (auto simp add: foldl_conv_fold intro!: fold_cong) lemma foldr_append [simp]: "foldr f (xs @ ys) a = foldr f xs (foldr f ys a)" by (simp add: foldr_conv_fold) lemma foldl_append [simp]: "foldl f a (xs @ ys) = foldl f (foldl f a xs) ys" by (simp add: foldl_conv_fold) lemma foldr_map [code_unfold]: "foldr g (map f xs) a = foldr (g \ f) xs a" by (simp add: foldr_conv_fold fold_map rev_map) lemma foldr_filter: "foldr f (filter P xs) = foldr (\x. if P x then f x else id) xs" by (simp add: foldr_conv_fold rev_filter fold_filter) lemma foldl_map [code_unfold]: "foldl g a (map f xs) = foldl (\a x. g a (f x)) a xs" by (simp add: foldl_conv_fold fold_map comp_def) lemma concat_conv_foldr [code]: "concat xss = foldr append xss []" by (simp add: fold_append_concat_rev foldr_conv_fold) subsubsection \\<^const>\upt\\ lemma upt_rec[code]: "[i.. \simp does not terminate!\ by (induct j) auto lemmas upt_rec_numeral[simp] = upt_rec[of "numeral m" "numeral n"] for m n lemma upt_conv_Nil [simp]: "j \ i \ [i.. j \ i)" by(induct j)simp_all lemma upt_eq_Cons_conv: "([i.. i = x \ [i+1.. j \ [i..<(Suc j)] = [i.. \Only needed if \upt_Suc\ is deleted from the simpset.\ by simp lemma upt_conv_Cons: "i < j \ [i.. \no precondition\ "m # n # ns = [m.. n # ns = [Suc m.. [i.. \LOOPS as a simprule, since \j \ j\.\ by (induct k) auto lemma length_upt [simp]: "length [i.. [i.. hd[i.. last[i.. n \ take m [i..i. i + n) [0.. (map f [m..n. n - Suc 0) [Suc m..i. f (Suc i)) [0 ..< n]" by (induct n arbitrary: f) auto lemma nth_take_lemma: "k \ length xs \ k \ length ys \ (\i. i < k \ xs!i = ys!i) \ take k xs = take k ys" proof (induct k arbitrary: xs ys) case (Suc k) then show ?case apply (simp add: less_Suc_eq_0_disj) by (simp add: Suc.prems(3) take_Suc_conv_app_nth) qed simp lemma nth_equalityI: "\length xs = length ys; \i. i < length xs \ xs!i = ys!i\ \ xs = ys" by (frule nth_take_lemma [OF le_refl eq_imp_le]) simp_all lemma map_nth: "map (\i. xs ! i) [0.. (\x y. \P x y; Q y x\ \ x = y); list_all2 P xs ys; list_all2 Q ys xs \ \ xs = ys" by (simp add: list_all2_conv_all_nth nth_equalityI) lemma take_equalityI: "(\i. take i xs = take i ys) \ xs = ys" \ \The famous take-lemma.\ by (metis length_take min.commute order_refl take_all) lemma take_Cons': "take n (x # xs) = (if n = 0 then [] else x # take (n - 1) xs)" by (cases n) simp_all lemma drop_Cons': "drop n (x # xs) = (if n = 0 then x # xs else drop (n - 1) xs)" by (cases n) simp_all lemma nth_Cons': "(x # xs)!n = (if n = 0 then x else xs!(n - 1))" by (cases n) simp_all lemma take_Cons_numeral [simp]: "take (numeral v) (x # xs) = x # take (numeral v - 1) xs" by (simp add: take_Cons') lemma drop_Cons_numeral [simp]: "drop (numeral v) (x # xs) = drop (numeral v - 1) xs" by (simp add: drop_Cons') lemma nth_Cons_numeral [simp]: "(x # xs) ! numeral v = xs ! (numeral v - 1)" by (simp add: nth_Cons') lemma map_upt_eqI: \map f [m.. if \length xs = n - m\ \\i. i < length xs \ xs ! i = f (m + i)\ proof (rule nth_equalityI) from \length xs = n - m\ show \length (map f [m.. by simp next fix i assume \i < length (map f [m.. then have \i < n - m\ by simp with that have \xs ! i = f (m + i)\ by simp with \i < n - m\ show \map f [m.. by simp qed subsubsection \\upto\: interval-list on \<^typ>\int\\ function upto :: "int \ int \ int list" ("(1[_../_])") where "upto i j = (if i \ j then i # [i+1..j] else [])" by auto termination by(relation "measure(%(i::int,j). nat(j - i + 1))") auto declare upto.simps[simp del] lemmas upto_rec_numeral [simp] = upto.simps[of "numeral m" "numeral n"] upto.simps[of "numeral m" "- numeral n"] upto.simps[of "- numeral m" "numeral n"] upto.simps[of "- numeral m" "- numeral n"] for m n lemma upto_empty[simp]: "j < i \ [i..j] = []" by(simp add: upto.simps) lemma upto_single[simp]: "[i..i] = [i]" by(simp add: upto.simps) lemma upto_Nil[simp]: "[i..j] = [] \ j < i" by (simp add: upto.simps) lemma upto_Nil2[simp]: "[] = [i..j] \ j < i" by (simp add: upto.simps) lemma upto_rec1: "i \ j \ [i..j] = i#[i+1..j]" by(simp add: upto.simps) lemma upto_rec2: "i \ j \ [i..j] = [i..j - 1]@[j]" proof(induct "nat(j-i)" arbitrary: i j) case 0 thus ?case by(simp add: upto.simps) next case (Suc n) hence "n = nat (j - (i + 1))" "i < j" by linarith+ from this(2) Suc.hyps(1)[OF this(1)] Suc(2,3) upto_rec1 show ?case by simp qed lemma length_upto[simp]: "length [i..j] = nat(j - i + 1)" by(induction i j rule: upto.induct) (auto simp: upto.simps) lemma set_upto[simp]: "set[i..j] = {i..j}" proof(induct i j rule:upto.induct) case (1 i j) from this show ?case unfolding upto.simps[of i j] by auto qed lemma nth_upto[simp]: "i + int k \ j \ [i..j] ! k = i + int k" proof(induction i j arbitrary: k rule: upto.induct) case (1 i j) then show ?case by (auto simp add: upto_rec1 [of i j] nth_Cons') qed lemma upto_split1: "i \ j \ j \ k \ [i..k] = [i..j-1] @ [j..k]" proof (induction j rule: int_ge_induct) case base thus ?case by (simp add: upto_rec1) next case step thus ?case using upto_rec1 upto_rec2 by simp qed lemma upto_split2: "i \ j \ j \ k \ [i..k] = [i..j] @ [j+1..k]" using upto_rec1 upto_rec2 upto_split1 by auto lemma upto_split3: "\ i \ j; j \ k \ \ [i..k] = [i..j-1] @ j # [j+1..k]" using upto_rec1 upto_split1 by auto text\Tail recursive version for code generation:\ definition upto_aux :: "int \ int \ int list \ int list" where "upto_aux i j js = [i..j] @ js" lemma upto_aux_rec [code]: "upto_aux i j js = (if j\<^const>\successively\\ lemma successively_Cons: "successively P (x # xs) \ xs = [] \ P x (hd xs) \ successively P xs" by (cases xs) auto lemma successively_cong [cong]: assumes "\x y. x \ set xs \ y \ set xs \ P x y \ Q x y" "xs = ys" shows "successively P xs \ successively Q ys" unfolding assms(2) [symmetric] using assms(1) by (induction xs) (auto simp: successively_Cons) lemma successively_append_iff: "successively P (xs @ ys) \ successively P xs \ successively P ys \ (xs = [] \ ys = [] \ P (last xs) (hd ys))" by (induction xs) (auto simp: successively_Cons) lemma successively_if_sorted_wrt: "sorted_wrt P xs \ successively P xs" by (induction xs rule: induct_list012) auto lemma successively_iff_sorted_wrt_strong: assumes "\x y z. x \ set xs \ y \ set xs \ z \ set xs \ P x y \ P y z \ P x z" shows "successively P xs \ sorted_wrt P xs" proof assume "successively P xs" from this and assms show "sorted_wrt P xs" proof (induction xs rule: induct_list012) case (3 x y xs) from "3.prems" have "P x y" by auto have IH: "sorted_wrt P (y # xs)" using "3.prems" by(intro "3.IH"(2) list.set_intros(2))(simp, blast intro: list.set_intros(2)) have "P x z" if asm: "z \ set xs" for z proof - from IH and asm have "P y z" by auto with \P x y\ show "P x z" using "3.prems" asm by auto qed with IH and \P x y\ show ?case by auto qed auto qed (use successively_if_sorted_wrt in blast) lemma successively_conv_sorted_wrt: assumes "transp P" shows "successively P xs \ sorted_wrt P xs" using assms unfolding transp_def by (intro successively_iff_sorted_wrt_strong) blast lemma successively_rev [simp]: "successively P (rev xs) \ successively (\x y. P y x) xs" by (induction xs rule: remdups_adj.induct) (auto simp: successively_append_iff successively_Cons) lemma successively_map: "successively P (map f xs) \ successively (\x y. P (f x) (f y)) xs" by (induction xs rule: induct_list012) auto lemma successively_mono: assumes "successively P xs" assumes "\x y. x \ set xs \ y \ set xs \ P x y \ Q x y" shows "successively Q xs" using assms by (induction Q xs rule: successively.induct) auto lemma successively_altdef: "successively = (\P. rec_list True (\x xs b. case xs of [] \ True | y # _ \ P x y \ b))" proof (intro ext) fix P and xs :: "'a list" show "successively P xs = rec_list True (\x xs b. case xs of [] \ True | y # _ \ P x y \ b) xs" by (induction xs) (auto simp: successively_Cons split: list.splits) qed subsubsection \\<^const>\distinct\ and \<^const>\remdups\ and \<^const>\remdups_adj\\ lemma distinct_tl: "distinct xs \ distinct (tl xs)" by (cases xs) simp_all lemma distinct_append [simp]: "distinct (xs @ ys) = (distinct xs \ distinct ys \ set xs \ set ys = {})" by (induct xs) auto lemma distinct_rev[simp]: "distinct(rev xs) = distinct xs" by(induct xs) auto lemma set_remdups [simp]: "set (remdups xs) = set xs" by (induct xs) (auto simp add: insert_absorb) lemma distinct_remdups [iff]: "distinct (remdups xs)" by (induct xs) auto lemma distinct_remdups_id: "distinct xs \ remdups xs = xs" by (induct xs, auto) lemma remdups_id_iff_distinct [simp]: "remdups xs = xs \ distinct xs" by (metis distinct_remdups distinct_remdups_id) lemma finite_distinct_list: "finite A \ \xs. set xs = A \ distinct xs" by (metis distinct_remdups finite_list set_remdups) lemma remdups_eq_nil_iff [simp]: "(remdups x = []) = (x = [])" by (induct x, auto) lemma remdups_eq_nil_right_iff [simp]: "([] = remdups x) = (x = [])" by (induct x, auto) lemma length_remdups_leq[iff]: "length(remdups xs) \ length xs" by (induct xs) auto lemma length_remdups_eq[iff]: "(length (remdups xs) = length xs) = (remdups xs = xs)" proof (induct xs) case (Cons a xs) then show ?case by simp (metis Suc_n_not_le_n impossible_Cons length_remdups_leq) qed auto lemma remdups_filter: "remdups(filter P xs) = filter P (remdups xs)" by (induct xs) auto lemma distinct_map: "distinct(map f xs) = (distinct xs \ inj_on f (set xs))" by (induct xs) auto lemma distinct_map_filter: "distinct (map f xs) \ distinct (map f (filter P xs))" by (induct xs) auto lemma distinct_filter [simp]: "distinct xs \ distinct (filter P xs)" by (induct xs) auto lemma distinct_upt[simp]: "distinct[i.. distinct (take i xs)" proof (induct xs arbitrary: i) case (Cons a xs) then show ?case by (metis Cons.prems append_take_drop_id distinct_append) qed auto lemma distinct_drop[simp]: "distinct xs \ distinct (drop i xs)" proof (induct xs arbitrary: i) case (Cons a xs) then show ?case by (metis Cons.prems append_take_drop_id distinct_append) qed auto lemma distinct_list_update: assumes d: "distinct xs" and a: "a \ set xs - {xs!i}" shows "distinct (xs[i:=a])" proof (cases "i < length xs") case True with a have anot: "a \ set (take i xs @ xs ! i # drop (Suc i) xs) - {xs!i}" by simp (metis in_set_dropD in_set_takeD) show ?thesis proof (cases "a = xs!i") case True with d show ?thesis by auto next case False have "set (take i xs) \ set (drop (Suc i) xs) = {}" by (metis True d disjoint_insert(1) distinct_append id_take_nth_drop list.set(2)) then show ?thesis using d False anot \i < length xs\ by (simp add: upd_conv_take_nth_drop) qed next case False with d show ?thesis by auto qed lemma distinct_concat: "\ distinct xs; \ ys. ys \ set xs \ distinct ys; \ ys zs. \ ys \ set xs ; zs \ set xs ; ys \ zs \ \ set ys \ set zs = {} \ \ distinct (concat xs)" by (induct xs) auto text \An iff-version of @{thm distinct_concat} is available further down as \distinct_concat_iff\.\ text \It is best to avoid the following indexed version of distinct, but sometimes it is useful.\ lemma distinct_conv_nth: "distinct xs = (\i < size xs. \j < size xs. i \ j \ xs!i \ xs!j)" proof (induct xs) case (Cons x xs) show ?case apply (auto simp add: Cons nth_Cons split: nat.split_asm) apply (metis Suc_less_eq2 in_set_conv_nth less_not_refl zero_less_Suc)+ done qed auto lemma nth_eq_iff_index_eq: "\ distinct xs; i < length xs; j < length xs \ \ (xs!i = xs!j) = (i = j)" by(auto simp: distinct_conv_nth) lemma distinct_Ex1: "distinct xs \ x \ set xs \ (\!i. i < length xs \ xs ! i = x)" by (auto simp: in_set_conv_nth nth_eq_iff_index_eq) lemma inj_on_nth: "distinct xs \ \i \ I. i < length xs \ inj_on (nth xs) I" by (rule inj_onI) (simp add: nth_eq_iff_index_eq) lemma bij_betw_nth: assumes "distinct xs" "A = {.. distinct xs; n < length xs \ \ set(xs[n := x]) = insert x (set xs - {xs!n})" by(auto simp: set_eq_iff in_set_conv_nth nth_list_update nth_eq_iff_index_eq) lemma distinct_swap[simp]: "\ i < size xs; j < size xs\ \ distinct(xs[i := xs!j, j := xs!i]) = distinct xs" apply (simp add: distinct_conv_nth nth_list_update) apply (safe; metis) done lemma set_swap[simp]: "\ i < size xs; j < size xs \ \ set(xs[i := xs!j, j := xs!i]) = set xs" by(simp add: set_conv_nth nth_list_update) metis lemma distinct_card: "distinct xs \ card (set xs) = size xs" by (induct xs) auto lemma card_distinct: "card (set xs) = size xs \ distinct xs" proof (induct xs) case (Cons x xs) show ?case proof (cases "x \ set xs") case False with Cons show ?thesis by simp next case True with Cons.prems have "card (set xs) = Suc (length xs)" by (simp add: card_insert_if split: if_split_asm) moreover have "card (set xs) \ length xs" by (rule card_length) ultimately have False by simp thus ?thesis .. qed qed simp lemma distinct_length_filter: "distinct xs \ length (filter P xs) = card ({x. P x} Int set xs)" by (induct xs) (auto) lemma not_distinct_decomp: "\ distinct ws \ \xs ys zs y. ws = xs@[y]@ys@[y]@zs" proof (induct n == "length ws" arbitrary:ws) case (Suc n ws) then show ?case using length_Suc_conv [of ws n] apply (auto simp: eq_commute) apply (metis append_Nil in_set_conv_decomp_first) by (metis append_Cons) qed simp lemma not_distinct_conv_prefix: defines "dec as xs y ys \ y \ set xs \ distinct xs \ as = xs @ y # ys" shows "\distinct as \ (\xs y ys. dec as xs y ys)" (is "?L = ?R") proof assume "?L" then show "?R" proof (induct "length as" arbitrary: as rule: less_induct) case less obtain xs ys zs y where decomp: "as = (xs @ y # ys) @ y # zs" using not_distinct_decomp[OF less.prems] by auto show ?case proof (cases "distinct (xs @ y # ys)") case True with decomp have "dec as (xs @ y # ys) y zs" by (simp add: dec_def) then show ?thesis by blast next case False with less decomp obtain xs' y' ys' where "dec (xs @ y # ys) xs' y' ys'" by atomize_elim auto with decomp have "dec as xs' y' (ys' @ y # zs)" by (simp add: dec_def) then show ?thesis by blast qed qed qed (auto simp: dec_def) lemma distinct_product: "distinct xs \ distinct ys \ distinct (List.product xs ys)" by (induct xs) (auto intro: inj_onI simp add: distinct_map) lemma distinct_product_lists: assumes "\xs \ set xss. distinct xs" shows "distinct (product_lists xss)" using assms proof (induction xss) case (Cons xs xss) note * = this then show ?case proof (cases "product_lists xss") case Nil then show ?thesis by (induct xs) simp_all next case (Cons ps pss) with * show ?thesis by (auto intro!: inj_onI distinct_concat simp add: distinct_map) qed qed simp lemma length_remdups_concat: "length (remdups (concat xss)) = card (\xs\set xss. set xs)" by (simp add: distinct_card [symmetric]) lemma remdups_append2: "remdups (xs @ remdups ys) = remdups (xs @ ys)" by(induction xs) auto lemma length_remdups_card_conv: "length(remdups xs) = card(set xs)" proof - have xs: "concat[xs] = xs" by simp from length_remdups_concat[of "[xs]"] show ?thesis unfolding xs by simp qed lemma remdups_remdups: "remdups (remdups xs) = remdups xs" by (induct xs) simp_all lemma distinct_butlast: assumes "distinct xs" shows "distinct (butlast xs)" proof (cases "xs = []") case False from \xs \ []\ obtain ys y where "xs = ys @ [y]" by (cases xs rule: rev_cases) auto with \distinct xs\ show ?thesis by simp qed (auto) lemma remdups_map_remdups: "remdups (map f (remdups xs)) = remdups (map f xs)" by (induct xs) simp_all lemma distinct_zipI1: assumes "distinct xs" shows "distinct (zip xs ys)" proof (rule zip_obtain_same_length) fix xs' :: "'a list" and ys' :: "'b list" and n assume "length xs' = length ys'" assume "xs' = take n xs" with assms have "distinct xs'" by simp with \length xs' = length ys'\ show "distinct (zip xs' ys')" by (induct xs' ys' rule: list_induct2) (auto elim: in_set_zipE) qed lemma distinct_zipI2: assumes "distinct ys" shows "distinct (zip xs ys)" proof (rule zip_obtain_same_length) fix xs' :: "'b list" and ys' :: "'a list" and n assume "length xs' = length ys'" assume "ys' = take n ys" with assms have "distinct ys'" by simp with \length xs' = length ys'\ show "distinct (zip xs' ys')" by (induct xs' ys' rule: list_induct2) (auto elim: in_set_zipE) qed lemma set_take_disj_set_drop_if_distinct: "distinct vs \ i \ j \ set (take i vs) \ set (drop j vs) = {}" by (auto simp: in_set_conv_nth distinct_conv_nth) (* The next two lemmas help Sledgehammer. *) lemma distinct_singleton: "distinct [x]" by simp lemma distinct_length_2_or_more: "distinct (a # b # xs) \ (a \ b \ distinct (a # xs) \ distinct (b # xs))" by force lemma remdups_adj_altdef: "(remdups_adj xs = ys) \ (\f::nat => nat. mono f \ f ` {0 ..< size xs} = {0 ..< size ys} \ (\i < size xs. xs!i = ys!(f i)) \ (\i. i + 1 < size xs \ (xs!i = xs!(i+1) \ f i = f(i+1))))" (is "?L \ (\f. ?p f xs ys)") proof assume ?L then show "\f. ?p f xs ys" proof (induct xs arbitrary: ys rule: remdups_adj.induct) case (1 ys) thus ?case by (intro exI[of _ id]) (auto simp: mono_def) next case (2 x ys) thus ?case by (intro exI[of _ id]) (auto simp: mono_def) next case (3 x1 x2 xs ys) let ?xs = "x1 # x2 # xs" let ?cond = "x1 = x2" define zs where "zs = remdups_adj (x2 # xs)" from 3(1-2)[of zs] obtain f where p: "?p f (x2 # xs) zs" unfolding zs_def by (cases ?cond) auto then have f0: "f 0 = 0" by (intro mono_image_least[where f=f]) blast+ from p have mono: "mono f" and f_xs_zs: "f ` {0.. []" unfolding zs_def by (induct xs) auto let ?Succ = "if ?cond then id else Suc" let ?x1 = "if ?cond then id else Cons x1" let ?f = "\ i. if i = 0 then 0 else ?Succ (f (i - 1))" have ys: "ys = ?x1 zs" unfolding ys by (cases ?cond, auto) have mono: "mono ?f" using \mono f\ unfolding mono_def by auto show ?case unfolding ys proof (intro exI[of _ ?f] conjI allI impI) show "mono ?f" by fact next fix i assume i: "i < length ?xs" with p show "?xs ! i = ?x1 zs ! (?f i)" using zs0 by auto next fix i assume i: "i + 1 < length ?xs" with p show "(?xs ! i = ?xs ! (i + 1)) = (?f i = ?f (i + 1))" by (cases i) (auto simp: f0) next have id: "{0 ..< length (?x1 zs)} = insert 0 (?Succ ` {0 ..< length zs})" using zsne by (cases ?cond, auto) { fix i assume "i < Suc (length xs)" hence "Suc i \ {0.. Collect ((<) 0)" by auto from imageI[OF this, of "\i. ?Succ (f (i - Suc 0))"] have "?Succ (f i) \ (\i. ?Succ (f (i - Suc 0))) ` ({0.. Collect ((<) 0))" by auto } then show "?f ` {0 ..< length ?xs} = {0 ..< length (?x1 zs)}" unfolding id f_xs_zs[symmetric] by auto qed qed next assume "\ f. ?p f xs ys" then show ?L proof (induct xs arbitrary: ys rule: remdups_adj.induct) case 1 then show ?case by auto next case (2 x) then obtain f where f_img: "f ` {0 ..< size [x]} = {0 ..< size ys}" and f_nth: "\i. i < size [x] \ [x]!i = ys!(f i)" by blast have "length ys = card (f ` {0 ..< size [x]})" using f_img by auto then have *: "length ys = 1" by auto then have "f 0 = 0" using f_img by auto with * show ?case using f_nth by (cases ys) auto next case (3 x1 x2 xs) from "3.prems" obtain f where f_mono: "mono f" and f_img: "f ` {0..i. i < length (x1 # x2 # xs) \ (x1 # x2 # xs) ! i = ys ! f i" "\i. i + 1 < length (x1 # x2 #xs) \ ((x1 # x2 # xs) ! i = (x1 # x2 # xs) ! (i + 1)) = (f i = f (i + 1))" by blast show ?case proof cases assume "x1 = x2" let ?f' = "f \ Suc" have "remdups_adj (x1 # xs) = ys" proof (intro "3.hyps" exI conjI impI allI) show "mono ?f'" using f_mono by (simp add: mono_iff_le_Suc) next have "?f' ` {0 ..< length (x1 # xs)} = f ` {Suc 0 ..< length (x1 # x2 # xs)}" using less_Suc_eq_0_disj by auto also have "\ = f ` {0 ..< length (x1 # x2 # xs)}" proof - have "f 0 = f (Suc 0)" using \x1 = x2\ f_nth[of 0] by simp then show ?thesis using less_Suc_eq_0_disj by auto qed also have "\ = {0 ..< length ys}" by fact finally show "?f' ` {0 ..< length (x1 # xs)} = {0 ..< length ys}" . qed (insert f_nth[of "Suc i" for i], auto simp: \x1 = x2\) then show ?thesis using \x1 = x2\ by simp next assume "x1 \ x2" have two: "Suc (Suc 0) \ length ys" proof - have "2 = card {f 0, f 1}" using \x1 \ x2\ f_nth[of 0] by auto also have "\ \ card (f ` {0..< length (x1 # x2 # xs)})" by (rule card_mono) auto finally show ?thesis using f_img by simp qed have "f 0 = 0" using f_mono f_img by (rule mono_image_least) simp have "f (Suc 0) = Suc 0" proof (rule ccontr) assume "f (Suc 0) \ Suc 0" then have "Suc 0 < f (Suc 0)" using f_nth[of 0] \x1 \ x2\ \f 0 = 0\ by auto then have "\i. Suc 0 < f (Suc i)" using f_mono by (meson Suc_le_mono le0 less_le_trans monoD) then have "Suc 0 \ f i" for i using \f 0 = 0\ by (cases i) fastforce+ then have "Suc 0 \ f ` {0 ..< length (x1 # x2 # xs)}" by auto then show False using f_img two by auto qed obtain ys' where "ys = x1 # x2 # ys'" using two f_nth[of 0] f_nth[of 1] by (auto simp: Suc_le_length_iff \f 0 = 0\ \f (Suc 0) = Suc 0\) have Suc0_le_f_Suc: "Suc 0 \ f (Suc i)" for i by (metis Suc_le_mono \f (Suc 0) = Suc 0\ f_mono le0 mono_def) define f' where "f' x = f (Suc x) - 1" for x have f_Suc: "f (Suc i) = Suc (f' i)" for i using Suc0_le_f_Suc[of i] by (auto simp: f'_def) have "remdups_adj (x2 # xs) = (x2 # ys')" proof (intro "3.hyps" exI conjI impI allI) show "mono f'" using Suc0_le_f_Suc f_mono by (auto simp: f'_def mono_iff_le_Suc le_diff_iff) next have "f' ` {0 ..< length (x2 # xs)} = (\x. f x - 1) ` {0 ..< length (x1 # x2 #xs)}" by (auto simp: f'_def \f 0 = 0\ \f (Suc 0) = Suc 0\ image_def Bex_def less_Suc_eq_0_disj) also have "\ = (\x. x - 1) ` f ` {0 ..< length (x1 # x2 #xs)}" by (auto simp: image_comp) also have "\ = (\x. x - 1) ` {0 ..< length ys}" by (simp only: f_img) also have "\ = {0 ..< length (x2 # ys')}" using \ys = _\ by (fastforce intro: rev_image_eqI) finally show "f' ` {0 ..< length (x2 # xs)} = {0 ..< length (x2 # ys')}" . qed (insert f_nth[of "Suc i" for i] \x1 \ x2\, auto simp add: f_Suc \ys = _\) then show ?case using \ys = _\ \x1 \ x2\ by simp qed qed qed lemma hd_remdups_adj[simp]: "hd (remdups_adj xs) = hd xs" by (induction xs rule: remdups_adj.induct) simp_all lemma remdups_adj_Cons: "remdups_adj (x # xs) = (case remdups_adj xs of [] \ [x] | y # xs \ if x = y then y # xs else x # y # xs)" by (induct xs arbitrary: x) (auto split: list.splits) lemma remdups_adj_append_two: "remdups_adj (xs @ [x,y]) = remdups_adj (xs @ [x]) @ (if x = y then [] else [y])" by (induct xs rule: remdups_adj.induct, simp_all) lemma remdups_adj_adjacent: "Suc i < length (remdups_adj xs) \ remdups_adj xs ! i \ remdups_adj xs ! Suc i" proof (induction xs arbitrary: i rule: remdups_adj.induct) case (3 x y xs i) thus ?case by (cases i, cases "x = y") (simp, auto simp: hd_conv_nth[symmetric]) qed simp_all lemma remdups_adj_rev[simp]: "remdups_adj (rev xs) = rev (remdups_adj xs)" by (induct xs rule: remdups_adj.induct, simp_all add: remdups_adj_append_two) lemma remdups_adj_length[simp]: "length (remdups_adj xs) \ length xs" by (induct xs rule: remdups_adj.induct, auto) lemma remdups_adj_length_ge1[simp]: "xs \ [] \ length (remdups_adj xs) \ Suc 0" by (induct xs rule: remdups_adj.induct, simp_all) lemma remdups_adj_Nil_iff[simp]: "remdups_adj xs = [] \ xs = []" by (induct xs rule: remdups_adj.induct, simp_all) lemma remdups_adj_set[simp]: "set (remdups_adj xs) = set xs" by (induct xs rule: remdups_adj.induct, simp_all) lemma last_remdups_adj [simp]: "last (remdups_adj xs) = last xs" by (induction xs rule: remdups_adj.induct) auto lemma remdups_adj_Cons_alt[simp]: "x # tl (remdups_adj (x # xs)) = remdups_adj (x # xs)" by (induct xs rule: remdups_adj.induct, auto) lemma remdups_adj_distinct: "distinct xs \ remdups_adj xs = xs" by (induct xs rule: remdups_adj.induct, simp_all) lemma remdups_adj_append: "remdups_adj (xs\<^sub>1 @ x # xs\<^sub>2) = remdups_adj (xs\<^sub>1 @ [x]) @ tl (remdups_adj (x # xs\<^sub>2))" by (induct xs\<^sub>1 rule: remdups_adj.induct, simp_all) lemma remdups_adj_singleton: "remdups_adj xs = [x] \ xs = replicate (length xs) x" by (induct xs rule: remdups_adj.induct, auto split: if_split_asm) lemma remdups_adj_map_injective: assumes "inj f" shows "remdups_adj (map f xs) = map f (remdups_adj xs)" by (induct xs rule: remdups_adj.induct) (auto simp add: injD[OF assms]) lemma remdups_adj_replicate: "remdups_adj (replicate n x) = (if n = 0 then [] else [x])" by (induction n) (auto simp: remdups_adj_Cons) lemma remdups_upt [simp]: "remdups [m.. n") case False then show ?thesis by simp next case True then obtain q where "n = m + q" by (auto simp add: le_iff_add) moreover have "remdups [m.. successively P (remdups_adj xs)" by (induction xs rule: remdups_adj.induct) (auto simp: successively_Cons) lemma successively_remdups_adj_iff: "(\x. x \ set xs \ P x x) \ successively P (remdups_adj xs) \ successively P xs" by (induction xs rule: remdups_adj.induct)(auto simp: successively_Cons) lemma remdups_adj_Cons': "remdups_adj (x # xs) = x # remdups_adj (dropWhile (\y. y = x) xs)" by (induction xs) auto lemma remdups_adj_singleton_iff: "length (remdups_adj xs) = Suc 0 \ xs \ [] \ xs = replicate (length xs) (hd xs)" proof safe assume *: "xs = replicate (length xs) (hd xs)" and [simp]: "xs \ []" show "length (remdups_adj xs) = Suc 0" by (subst *) (auto simp: remdups_adj_replicate) next assume "length (remdups_adj xs) = Suc 0" thus "xs = replicate (length xs) (hd xs)" by (induction xs rule: remdups_adj.induct) (auto split: if_splits) qed auto lemma tl_remdups_adj: "ys \ [] \ tl (remdups_adj ys) = remdups_adj (dropWhile (\x. x = hd ys) (tl ys))" by (cases ys) (simp_all add: remdups_adj_Cons') lemma remdups_adj_append_dropWhile: "remdups_adj (xs @ y # ys) = remdups_adj (xs @ [y]) @ remdups_adj (dropWhile (\x. x = y) ys)" by (subst remdups_adj_append) (simp add: tl_remdups_adj) lemma remdups_adj_append': assumes "xs = [] \ ys = [] \ last xs \ hd ys" shows "remdups_adj (xs @ ys) = remdups_adj xs @ remdups_adj ys" proof - have ?thesis if [simp]: "xs \ []" "ys \ []" and "last xs \ hd ys" proof - obtain x xs' where xs: "xs = xs' @ [x]" by (cases xs rule: rev_cases) auto have "remdups_adj (xs' @ x # ys) = remdups_adj (xs' @ [x]) @ remdups_adj ys" using \last xs \ hd ys\ unfolding xs by (metis (full_types) dropWhile_eq_self_iff last_snoc remdups_adj_append_dropWhile) thus ?thesis by (simp add: xs) qed thus ?thesis using assms by (cases "xs = []"; cases "ys = []") auto qed lemma remdups_adj_append'': "xs \ [] \ remdups_adj (xs @ ys) = remdups_adj xs @ remdups_adj (dropWhile (\y. y = last xs) ys)" by (induction xs rule: remdups_adj.induct) (auto simp: remdups_adj_Cons') subsection \@{const distinct_adj}\ lemma distinct_adj_Nil [simp]: "distinct_adj []" and distinct_adj_singleton [simp]: "distinct_adj [x]" and distinct_adj_Cons_Cons [simp]: "distinct_adj (x # y # xs) \ x \ y \ distinct_adj (y # xs)" by (auto simp: distinct_adj_def) lemma distinct_adj_Cons: "distinct_adj (x # xs) \ xs = [] \ x \ hd xs \ distinct_adj xs" by (cases xs) auto lemma distinct_adj_ConsD: "distinct_adj (x # xs) \ distinct_adj xs" by (cases xs) auto lemma distinct_adj_remdups_adj[simp]: "distinct_adj (remdups_adj xs)" by (induction xs rule: remdups_adj.induct) (auto simp: distinct_adj_Cons) lemma distinct_adj_altdef: "distinct_adj xs \ remdups_adj xs = xs" proof assume "remdups_adj xs = xs" with distinct_adj_remdups_adj[of xs] show "distinct_adj xs" by simp next assume "distinct_adj xs" thus "remdups_adj xs = xs" by (induction xs rule: induct_list012) auto qed lemma distinct_adj_rev [simp]: "distinct_adj (rev xs) \ distinct_adj xs" by (simp add: distinct_adj_def eq_commute) lemma distinct_adj_append_iff: "distinct_adj (xs @ ys) \ distinct_adj xs \ distinct_adj ys \ (xs = [] \ ys = [] \ last xs \ hd ys)" by (auto simp: distinct_adj_def successively_append_iff) lemma distinct_adj_appendD1 [dest]: "distinct_adj (xs @ ys) \ distinct_adj xs" and distinct_adj_appendD2 [dest]: "distinct_adj (xs @ ys) \ distinct_adj ys" by (auto simp: distinct_adj_append_iff) lemma distinct_adj_mapI: "distinct_adj xs \ inj_on f (set xs) \ distinct_adj (map f xs)" unfolding distinct_adj_def successively_map by (erule successively_mono) (auto simp: inj_on_def) lemma distinct_adj_mapD: "distinct_adj (map f xs) \ distinct_adj xs" unfolding distinct_adj_def successively_map by (erule successively_mono) auto lemma distinct_adj_map_iff: "inj_on f (set xs) \ distinct_adj (map f xs) \ distinct_adj xs" using distinct_adj_mapD distinct_adj_mapI by blast subsubsection \\<^const>\insert\\ lemma in_set_insert [simp]: "x \ set xs \ List.insert x xs = xs" by (simp add: List.insert_def) lemma not_in_set_insert [simp]: "x \ set xs \ List.insert x xs = x # xs" by (simp add: List.insert_def) lemma insert_Nil [simp]: "List.insert x [] = [x]" by simp lemma set_insert [simp]: "set (List.insert x xs) = insert x (set xs)" by (auto simp add: List.insert_def) lemma distinct_insert [simp]: "distinct (List.insert x xs) = distinct xs" by (simp add: List.insert_def) lemma insert_remdups: "List.insert x (remdups xs) = remdups (List.insert x xs)" by (simp add: List.insert_def) subsubsection \\<^const>\List.union\\ text\This is all one should need to know about union:\ lemma set_union[simp]: "set (List.union xs ys) = set xs \ set ys" unfolding List.union_def by(induct xs arbitrary: ys) simp_all lemma distinct_union[simp]: "distinct(List.union xs ys) = distinct ys" unfolding List.union_def by(induct xs arbitrary: ys) simp_all subsubsection \\<^const>\List.find\\ lemma find_None_iff: "List.find P xs = None \ \ (\x. x \ set xs \ P x)" proof (induction xs) case Nil thus ?case by simp next case (Cons x xs) thus ?case by (fastforce split: if_splits) qed lemma find_Some_iff: "List.find P xs = Some x \ (\i x = xs!i \ (\j P (xs!j)))" proof (induction xs) case Nil thus ?case by simp next case (Cons x xs) thus ?case apply(auto simp: nth_Cons' split: if_splits) using diff_Suc_1[unfolded One_nat_def] less_Suc_eq_0_disj by fastforce qed lemma find_cong[fundef_cong]: assumes "xs = ys" and "\x. x \ set ys \ P x = Q x" shows "List.find P xs = List.find Q ys" proof (cases "List.find P xs") case None thus ?thesis by (metis find_None_iff assms) next case (Some x) hence "List.find Q ys = Some x" using assms by (auto simp add: find_Some_iff) thus ?thesis using Some by auto qed lemma find_dropWhile: "List.find P xs = (case dropWhile (Not \ P) xs of [] \ None | x # _ \ Some x)" by (induct xs) simp_all subsubsection \\<^const>\count_list\\ lemma count_notin[simp]: "x \ set xs \ count_list xs x = 0" by (induction xs) auto lemma count_le_length: "count_list xs x \ length xs" by (induction xs) auto lemma sum_count_set: "set xs \ X \ finite X \ sum (count_list xs) X = length xs" proof (induction xs arbitrary: X) case (Cons x xs) then show ?case using sum.remove [of X x "count_list xs"] by (auto simp: sum.If_cases simp flip: diff_eq) qed simp subsubsection \\<^const>\List.extract\\ lemma extract_None_iff: "List.extract P xs = None \ \ (\ x\set xs. P x)" by(auto simp: extract_def dropWhile_eq_Cons_conv split: list.splits) (metis in_set_conv_decomp) lemma extract_SomeE: "List.extract P xs = Some (ys, y, zs) \ xs = ys @ y # zs \ P y \ \ (\ y \ set ys. P y)" by(auto simp: extract_def dropWhile_eq_Cons_conv split: list.splits) lemma extract_Some_iff: "List.extract P xs = Some (ys, y, zs) \ xs = ys @ y # zs \ P y \ \ (\ y \ set ys. P y)" by(auto simp: extract_def dropWhile_eq_Cons_conv dest: set_takeWhileD split: list.splits) lemma extract_Nil_code[code]: "List.extract P [] = None" by(simp add: extract_def) lemma extract_Cons_code[code]: "List.extract P (x # xs) = (if P x then Some ([], x, xs) else (case List.extract P xs of None \ None | Some (ys, y, zs) \ Some (x#ys, y, zs)))" by(auto simp add: extract_def comp_def split: list.splits) (metis dropWhile_eq_Nil_conv list.distinct(1)) subsubsection \\<^const>\remove1\\ lemma remove1_append: "remove1 x (xs @ ys) = (if x \ set xs then remove1 x xs @ ys else xs @ remove1 x ys)" by (induct xs) auto lemma remove1_commute: "remove1 x (remove1 y zs) = remove1 y (remove1 x zs)" by (induct zs) auto lemma in_set_remove1[simp]: "a \ b \ a \ set(remove1 b xs) = (a \ set xs)" by (induct xs) auto lemma set_remove1_subset: "set(remove1 x xs) \ set xs" by (induct xs) auto lemma set_remove1_eq [simp]: "distinct xs \ set(remove1 x xs) = set xs - {x}" by (induct xs) auto lemma length_remove1: "length(remove1 x xs) = (if x \ set xs then length xs - 1 else length xs)" by (induct xs) (auto dest!:length_pos_if_in_set) lemma remove1_filter_not[simp]: "\ P x \ remove1 x (filter P xs) = filter P xs" by(induct xs) auto lemma filter_remove1: "filter Q (remove1 x xs) = remove1 x (filter Q xs)" by (induct xs) auto lemma notin_set_remove1[simp]: "x \ set xs \ x \ set(remove1 y xs)" by(insert set_remove1_subset) fast lemma distinct_remove1[simp]: "distinct xs \ distinct(remove1 x xs)" by (induct xs) simp_all lemma remove1_remdups: "distinct xs \ remove1 x (remdups xs) = remdups (remove1 x xs)" by (induct xs) simp_all lemma remove1_idem: "x \ set xs \ remove1 x xs = xs" by (induct xs) simp_all lemma remove1_split: "a \ set xs \ remove1 a xs = ys \ (\ls rs. xs = ls @ a # rs \ a \ set ls \ ys = ls @ rs)" by (metis remove1.simps(2) remove1_append split_list_first) subsubsection \\<^const>\removeAll\\ lemma removeAll_filter_not_eq: "removeAll x = filter (\y. x \ y)" proof fix xs show "removeAll x xs = filter (\y. x \ y) xs" by (induct xs) auto qed lemma removeAll_append[simp]: "removeAll x (xs @ ys) = removeAll x xs @ removeAll x ys" by (induct xs) auto lemma set_removeAll[simp]: "set(removeAll x xs) = set xs - {x}" by (induct xs) auto lemma removeAll_id[simp]: "x \ set xs \ removeAll x xs = xs" by (induct xs) auto (* Needs count:: 'a \ 'a list \ nat lemma length_removeAll: "length(removeAll x xs) = length xs - count x xs" *) lemma removeAll_filter_not[simp]: "\ P x \ removeAll x (filter P xs) = filter P xs" by(induct xs) auto lemma distinct_removeAll: "distinct xs \ distinct (removeAll x xs)" by (simp add: removeAll_filter_not_eq) lemma distinct_remove1_removeAll: "distinct xs \ remove1 x xs = removeAll x xs" by (induct xs) simp_all lemma map_removeAll_inj_on: "inj_on f (insert x (set xs)) \ map f (removeAll x xs) = removeAll (f x) (map f xs)" by (induct xs) (simp_all add:inj_on_def) lemma map_removeAll_inj: "inj f \ map f (removeAll x xs) = removeAll (f x) (map f xs)" by (rule map_removeAll_inj_on, erule subset_inj_on, rule subset_UNIV) lemma length_removeAll_less_eq [simp]: "length (removeAll x xs) \ length xs" by (simp add: removeAll_filter_not_eq) lemma length_removeAll_less [termination_simp]: "x \ set xs \ length (removeAll x xs) < length xs" by (auto dest: length_filter_less simp add: removeAll_filter_not_eq) lemma distinct_concat_iff: "distinct (concat xs) \ distinct (removeAll [] xs) \ (\ys. ys \ set xs \ distinct ys) \ (\ys zs. ys \ set xs \ zs \ set xs \ ys \ zs \ set ys \ set zs = {})" apply (induct xs) apply(simp_all, safe, auto) by (metis Int_iff UN_I empty_iff equals0I set_empty) subsubsection \\<^const>\replicate\\ lemma length_replicate [simp]: "length (replicate n x) = n" by (induct n) auto lemma replicate_eqI: assumes "length xs = n" and "\y. y \ set xs \ y = x" shows "xs = replicate n x" using assms proof (induct xs arbitrary: n) case Nil then show ?case by simp next case (Cons x xs) then show ?case by (cases n) simp_all qed lemma Ex_list_of_length: "\xs. length xs = n" by (rule exI[of _ "replicate n undefined"]) simp lemma map_replicate [simp]: "map f (replicate n x) = replicate n (f x)" by (induct n) auto lemma map_replicate_const: "map (\ x. k) lst = replicate (length lst) k" by (induct lst) auto lemma replicate_app_Cons_same: "(replicate n x) @ (x # xs) = x # replicate n x @ xs" by (induct n) auto lemma rev_replicate [simp]: "rev (replicate n x) = replicate n x" by (induct n) (auto simp: replicate_app_Cons_same) lemma replicate_add: "replicate (n + m) x = replicate n x @ replicate m x" by (induct n) auto text\Courtesy of Matthias Daum:\ lemma append_replicate_commute: "replicate n x @ replicate k x = replicate k x @ replicate n x" by (metis add.commute replicate_add) text\Courtesy of Andreas Lochbihler:\ lemma filter_replicate: "filter P (replicate n x) = (if P x then replicate n x else [])" by(induct n) auto lemma hd_replicate [simp]: "n \ 0 \ hd (replicate n x) = x" by (induct n) auto lemma tl_replicate [simp]: "tl (replicate n x) = replicate (n - 1) x" by (induct n) auto lemma last_replicate [simp]: "n \ 0 \ last (replicate n x) = x" by (atomize (full), induct n) auto lemma nth_replicate[simp]: "i < n \ (replicate n x)!i = x" by (induct n arbitrary: i)(auto simp: nth_Cons split: nat.split) text\Courtesy of Matthias Daum (2 lemmas):\ lemma take_replicate[simp]: "take i (replicate k x) = replicate (min i k) x" proof (cases "k \ i") case True then show ?thesis by (simp add: min_def) next case False then have "replicate k x = replicate i x @ replicate (k - i) x" by (simp add: replicate_add [symmetric]) then show ?thesis by (simp add: min_def) qed lemma drop_replicate[simp]: "drop i (replicate k x) = replicate (k-i) x" proof (induct k arbitrary: i) case (Suc k) then show ?case by (simp add: drop_Cons') qed simp lemma set_replicate_Suc: "set (replicate (Suc n) x) = {x}" by (induct n) auto lemma set_replicate [simp]: "n \ 0 \ set (replicate n x) = {x}" by (fast dest!: not0_implies_Suc intro!: set_replicate_Suc) lemma set_replicate_conv_if: "set (replicate n x) = (if n = 0 then {} else {x})" by auto lemma in_set_replicate[simp]: "(x \ set (replicate n y)) = (x = y \ n \ 0)" by (simp add: set_replicate_conv_if) lemma Ball_set_replicate[simp]: "(\x \ set(replicate n a). P x) = (P a \ n=0)" by(simp add: set_replicate_conv_if) lemma Bex_set_replicate[simp]: "(\x \ set(replicate n a). P x) = (P a \ n\0)" by(simp add: set_replicate_conv_if) lemma replicate_append_same: "replicate i x @ [x] = x # replicate i x" by (induct i) simp_all lemma map_replicate_trivial: "map (\i. x) [0.. n=0" by (induct n) auto lemma empty_replicate[simp]: "([] = replicate n x) \ n=0" by (induct n) auto lemma replicate_eq_replicate[simp]: "(replicate m x = replicate n y) \ (m=n \ (m\0 \ x=y))" proof (induct m arbitrary: n) case (Suc m n) then show ?case by (induct n) auto qed simp lemma takeWhile_replicate[simp]: "takeWhile P (replicate n x) = (if P x then replicate n x else [])" using takeWhile_eq_Nil_iff by fastforce lemma dropWhile_replicate[simp]: "dropWhile P (replicate n x) = (if P x then [] else replicate n x)" using dropWhile_eq_self_iff by fastforce lemma replicate_length_filter: "replicate (length (filter (\y. x = y) xs)) x = filter (\y. x = y) xs" by (induct xs) auto lemma comm_append_are_replicate: "xs @ ys = ys @ xs \ \m n zs. concat (replicate m zs) = xs \ concat (replicate n zs) = ys" proof (induction "length (xs @ ys) + length xs" arbitrary: xs ys rule: less_induct) case less consider (1) "length ys < length xs" | (2) "xs = []" | (3) "length xs \ length ys \ xs \ []" by linarith then show ?case proof (cases) case 1 then show ?thesis using less.hyps[OF _ less.prems[symmetric]] nat_add_left_cancel_less by auto next case 2 then have "concat (replicate 0 ys) = xs \ concat (replicate 1 ys) = ys" by simp then show ?thesis by blast next case 3 then have "length xs \ length ys" and "xs \ []" by blast+ from \length xs \ length ys\ and \xs @ ys = ys @ xs\ obtain ws where "ys = xs @ ws" by (auto simp: append_eq_append_conv2) from this and \xs \ []\ have "length ws < length ys" by simp from \xs @ ys = ys @ xs\[unfolded \ys = xs @ ws\] have "xs @ ws = ws @ xs" by simp from less.hyps[OF _ this] \length ws < length ys\ obtain m n' zs where "concat (replicate m zs) = xs" and "concat (replicate n' zs) = ws" by auto then have "concat (replicate (m+n') zs) = ys" using \ys = xs @ ws\ by (simp add: replicate_add) then show ?thesis using \concat (replicate m zs) = xs\ by blast qed qed lemma comm_append_is_replicate: fixes xs ys :: "'a list" assumes "xs \ []" "ys \ []" assumes "xs @ ys = ys @ xs" shows "\n zs. n > 1 \ concat (replicate n zs) = xs @ ys" proof - obtain m n zs where "concat (replicate m zs) = xs" and "concat (replicate n zs) = ys" using comm_append_are_replicate[OF assms(3)] by blast then have "m + n > 1" and "concat (replicate (m+n) zs) = xs @ ys" using \xs \ []\ and \ys \ []\ by (auto simp: replicate_add) then show ?thesis by blast qed lemma Cons_replicate_eq: "x # xs = replicate n y \ x = y \ n > 0 \ xs = replicate (n - 1) x" by (induct n) auto lemma replicate_length_same: "(\y\set xs. y = x) \ replicate (length xs) x = xs" by (induct xs) simp_all lemma foldr_replicate [simp]: "foldr f (replicate n x) = f x ^^ n" by (induct n) (simp_all) lemma fold_replicate [simp]: "fold f (replicate n x) = f x ^^ n" by (subst foldr_fold [symmetric]) simp_all subsubsection \\<^const>\enumerate\\ lemma enumerate_simps [simp, code]: "enumerate n [] = []" "enumerate n (x # xs) = (n, x) # enumerate (Suc n) xs" by (simp_all add: enumerate_eq_zip upt_rec) lemma length_enumerate [simp]: "length (enumerate n xs) = length xs" by (simp add: enumerate_eq_zip) lemma map_fst_enumerate [simp]: "map fst (enumerate n xs) = [n.. set (enumerate n xs) \ n \ fst p \ fst p < length xs + n \ nth xs (fst p - n) = snd p" proof - { fix m assume "n \ m" moreover assume "m < length xs + n" ultimately have "[n.. xs ! (m - n) = xs ! (m - n) \ m - n < length xs" by auto then have "\q. [n.. xs ! q = xs ! (m - n) \ q < length xs" .. } then show ?thesis by (cases p) (auto simp add: enumerate_eq_zip in_set_zip) qed lemma nth_enumerate_eq: "m < length xs \ enumerate n xs ! m = (n + m, xs ! m)" by (simp add: enumerate_eq_zip) lemma enumerate_replicate_eq: "enumerate n (replicate m a) = map (\q. (q, a)) [n..k. (k, f k)) [n.. m") (simp_all add: zip_map2 zip_same_conv_map enumerate_eq_zip) subsubsection \\<^const>\rotate1\ and \<^const>\rotate\\ lemma rotate0[simp]: "rotate 0 = id" by(simp add:rotate_def) lemma rotate_Suc[simp]: "rotate (Suc n) xs = rotate1(rotate n xs)" by(simp add:rotate_def) lemma rotate_add: "rotate (m+n) = rotate m \ rotate n" by(simp add:rotate_def funpow_add) lemma rotate_rotate: "rotate m (rotate n xs) = rotate (m+n) xs" by(simp add:rotate_add) lemma rotate1_map: "rotate1 (map f xs) = map f (rotate1 xs)" by(cases xs) simp_all lemma rotate1_rotate_swap: "rotate1 (rotate n xs) = rotate n (rotate1 xs)" by(simp add:rotate_def funpow_swap1) lemma rotate1_length01[simp]: "length xs \ 1 \ rotate1 xs = xs" by(cases xs) simp_all lemma rotate_length01[simp]: "length xs \ 1 \ rotate n xs = xs" by (induct n) (simp_all add:rotate_def) lemma rotate1_hd_tl: "xs \ [] \ rotate1 xs = tl xs @ [hd xs]" by (cases xs) simp_all lemma rotate_drop_take: "rotate n xs = drop (n mod length xs) xs @ take (n mod length xs) xs" proof (induct n) case (Suc n) show ?case proof (cases "xs = []") case False then show ?thesis proof (cases "n mod length xs = 0") case True then show ?thesis by (auto simp add: mod_Suc False Suc.hyps drop_Suc rotate1_hd_tl take_Suc Suc_length_conv) next case False with \xs \ []\ Suc show ?thesis by (simp add: rotate_def mod_Suc rotate1_hd_tl drop_Suc[symmetric] drop_tl[symmetric] take_hd_drop linorder_not_le) qed qed simp qed simp lemma rotate_conv_mod: "rotate n xs = rotate (n mod length xs) xs" by(simp add:rotate_drop_take) lemma rotate_id[simp]: "n mod length xs = 0 \ rotate n xs = xs" by(simp add:rotate_drop_take) lemma length_rotate1[simp]: "length(rotate1 xs) = length xs" by (cases xs) simp_all lemma length_rotate[simp]: "length(rotate n xs) = length xs" by (induct n arbitrary: xs) (simp_all add:rotate_def) lemma distinct1_rotate[simp]: "distinct(rotate1 xs) = distinct xs" by (cases xs) auto lemma distinct_rotate[simp]: "distinct(rotate n xs) = distinct xs" by (induct n) (simp_all add:rotate_def) lemma rotate_map: "rotate n (map f xs) = map f (rotate n xs)" by(simp add:rotate_drop_take take_map drop_map) lemma set_rotate1[simp]: "set(rotate1 xs) = set xs" by (cases xs) auto lemma set_rotate[simp]: "set(rotate n xs) = set xs" by (induct n) (simp_all add:rotate_def) lemma rotate1_is_Nil_conv[simp]: "(rotate1 xs = []) = (xs = [])" by (cases xs) auto lemma rotate_is_Nil_conv[simp]: "(rotate n xs = []) = (xs = [])" by (induct n) (simp_all add:rotate_def) lemma rotate_rev: "rotate n (rev xs) = rev(rotate (length xs - (n mod length xs)) xs)" proof (cases "length xs = 0 \ n mod length xs = 0") case False then show ?thesis by(simp add:rotate_drop_take rev_drop rev_take) qed force lemma hd_rotate_conv_nth: assumes "xs \ []" shows "hd(rotate n xs) = xs!(n mod length xs)" proof - have "n mod length xs < length xs" using assms by simp then show ?thesis by (metis drop_eq_Nil hd_append2 hd_drop_conv_nth leD rotate_drop_take) qed lemma rotate_append: "rotate (length l) (l @ q) = q @ l" by (induct l arbitrary: q) (auto simp add: rotate1_rotate_swap) lemma nth_rotate: \rotate m xs ! n = xs ! ((m + n) mod length xs)\ if \n < length xs\ using that apply (auto simp add: rotate_drop_take nth_append not_less less_diff_conv ac_simps dest!: le_Suc_ex) apply (metis add.commute mod_add_right_eq mod_less) apply (metis (no_types, lifting) Nat.diff_diff_right add.commute add_diff_cancel_right' diff_le_self dual_order.strict_trans2 length_greater_0_conv less_nat_zero_code list.size(3) mod_add_right_eq mod_add_self2 mod_le_divisor mod_less) done lemma nth_rotate1: \rotate1 xs ! n = xs ! (Suc n mod length xs)\ if \n < length xs\ using that nth_rotate [of n xs 1] by simp subsubsection \\<^const>\nths\ --- a generalization of \<^const>\nth\ to sets\ lemma nths_empty [simp]: "nths xs {} = []" by (auto simp add: nths_def) lemma nths_nil [simp]: "nths [] A = []" by (auto simp add: nths_def) lemma nths_all: "\i < length xs. i \ I \ nths xs I = xs" apply (simp add: nths_def) apply (subst filter_True) apply (auto simp: in_set_zip subset_iff) done lemma length_nths: "length (nths xs I) = card{i. i < length xs \ i \ I}" by(simp add: nths_def length_filter_conv_card cong:conj_cong) lemma nths_shift_lemma_Suc: "map fst (filter (\p. P(Suc(snd p))) (zip xs is)) = map fst (filter (\p. P(snd p)) (zip xs (map Suc is)))" proof (induct xs arbitrary: "is") case (Cons x xs "is") show ?case by (cases "is") (auto simp add: Cons.hyps) qed simp lemma nths_shift_lemma: "map fst (filter (\p. snd p \ A) (zip xs [i..p. snd p + i \ A) (zip xs [0.. A}" unfolding nths_def proof (induct l' rule: rev_induct) case (snoc x xs) then show ?case by (simp add: upt_add_eq_append[of 0] nths_shift_lemma add.commute) qed auto lemma nths_Cons: "nths (x # l) A = (if 0 \ A then [x] else []) @ nths l {j. Suc j \ A}" proof (induct l rule: rev_induct) case (snoc x xs) then show ?case by (simp flip: append_Cons add: nths_append) qed (auto simp: nths_def) lemma nths_map: "nths (map f xs) I = map f (nths xs I)" by(induction xs arbitrary: I) (simp_all add: nths_Cons) lemma set_nths: "set(nths xs I) = {xs!i|i. i i \ I}" by (induct xs arbitrary: I) (auto simp: nths_Cons nth_Cons split:nat.split dest!: gr0_implies_Suc) lemma set_nths_subset: "set(nths xs I) \ set xs" by(auto simp add:set_nths) lemma notin_set_nthsI[simp]: "x \ set xs \ x \ set(nths xs I)" by(auto simp add:set_nths) lemma in_set_nthsD: "x \ set(nths xs I) \ x \ set xs" by(auto simp add:set_nths) lemma nths_singleton [simp]: "nths [x] A = (if 0 \ A then [x] else [])" by (simp add: nths_Cons) lemma distinct_nthsI[simp]: "distinct xs \ distinct (nths xs I)" by (induct xs arbitrary: I) (auto simp: nths_Cons) lemma nths_upt_eq_take [simp]: "nths l {.. A. \j \ B. card {i' \ A. i' < i} = j}" by (induction xs arbitrary: A B) (auto simp add: nths_Cons card_less_Suc card_less_Suc2) lemma drop_eq_nths: "drop n xs = nths xs {i. i \ n}" by (induction xs arbitrary: n) (auto simp add: nths_Cons nths_all drop_Cons' intro: arg_cong2[where f=nths, OF refl]) lemma nths_drop: "nths (drop n xs) I = nths xs ((+) n ` I)" by(force simp: drop_eq_nths nths_nths simp flip: atLeastLessThan_iff intro: arg_cong2[where f=nths, OF refl]) lemma filter_eq_nths: "filter P xs = nths xs {i. i P(xs!i)}" by(induction xs) (auto simp: nths_Cons) lemma filter_in_nths: "distinct xs \ filter (%x. x \ set (nths xs s)) xs = nths xs s" proof (induct xs arbitrary: s) case Nil thus ?case by simp next case (Cons a xs) then have "\x. x \ set xs \ x \ a" by auto with Cons show ?case by(simp add: nths_Cons cong:filter_cong) qed subsubsection \\<^const>\subseqs\ and \<^const>\List.n_lists\\ lemma length_subseqs: "length (subseqs xs) = 2 ^ length xs" by (induct xs) (simp_all add: Let_def) lemma subseqs_powset: "set ` set (subseqs xs) = Pow (set xs)" proof - have aux: "\x A. set ` Cons x ` A = insert x ` set ` A" by (auto simp add: image_def) have "set (map set (subseqs xs)) = Pow (set xs)" by (induct xs) (simp_all add: aux Let_def Pow_insert Un_commute comp_def del: map_map) then show ?thesis by simp qed lemma distinct_set_subseqs: assumes "distinct xs" shows "distinct (map set (subseqs xs))" proof (rule card_distinct) have "finite (set xs)" .. then have "card (Pow (set xs)) = 2 ^ card (set xs)" by (rule card_Pow) with assms distinct_card [of xs] have "card (Pow (set xs)) = 2 ^ length xs" by simp then show "card (set (map set (subseqs xs))) = length (map set (subseqs xs))" by (simp add: subseqs_powset length_subseqs) qed lemma n_lists_Nil [simp]: "List.n_lists n [] = (if n = 0 then [[]] else [])" by (induct n) simp_all lemma length_n_lists_elem: "ys \ set (List.n_lists n xs) \ length ys = n" by (induct n arbitrary: ys) auto lemma set_n_lists: "set (List.n_lists n xs) = {ys. length ys = n \ set ys \ set xs}" proof (rule set_eqI) fix ys :: "'a list" show "ys \ set (List.n_lists n xs) \ ys \ {ys. length ys = n \ set ys \ set xs}" proof - have "ys \ set (List.n_lists n xs) \ length ys = n" by (induct n arbitrary: ys) auto moreover have "\x. ys \ set (List.n_lists n xs) \ x \ set ys \ x \ set xs" by (induct n arbitrary: ys) auto moreover have "set ys \ set xs \ ys \ set (List.n_lists (length ys) xs)" by (induct ys) auto ultimately show ?thesis by auto qed qed lemma subseqs_refl: "xs \ set (subseqs xs)" by (induct xs) (simp_all add: Let_def) lemma subset_subseqs: "X \ set xs \ X \ set ` set (subseqs xs)" unfolding subseqs_powset by simp lemma Cons_in_subseqsD: "y # ys \ set (subseqs xs) \ ys \ set (subseqs xs)" by (induct xs) (auto simp: Let_def) lemma subseqs_distinctD: "\ ys \ set (subseqs xs); distinct xs \ \ distinct ys" proof (induct xs arbitrary: ys) case (Cons x xs ys) then show ?case by (auto simp: Let_def) (metis Pow_iff contra_subsetD image_eqI subseqs_powset) qed simp subsubsection \\<^const>\splice\\ lemma splice_Nil2 [simp]: "splice xs [] = xs" by (cases xs) simp_all lemma length_splice[simp]: "length(splice xs ys) = length xs + length ys" by (induct xs ys rule: splice.induct) auto lemma split_Nil_iff[simp]: "splice xs ys = [] \ xs = [] \ ys = []" by (induct xs ys rule: splice.induct) auto lemma splice_replicate[simp]: "splice (replicate m x) (replicate n x) = replicate (m+n) x" proof (induction "replicate m x" "replicate n x" arbitrary: m n rule: splice.induct) case (2 x xs) then show ?case by (auto simp add: Cons_replicate_eq dest: gr0_implies_Suc) qed auto subsubsection \\<^const>\shuffles\\ lemma shuffles_commutes: "shuffles xs ys = shuffles ys xs" by (induction xs ys rule: shuffles.induct) (simp_all add: Un_commute) lemma Nil_in_shuffles[simp]: "[] \ shuffles xs ys \ xs = [] \ ys = []" by (induct xs ys rule: shuffles.induct) auto lemma shufflesE: "zs \ shuffles xs ys \ (zs = xs \ ys = [] \ P) \ (zs = ys \ xs = [] \ P) \ (\x xs' z zs'. xs = x # xs' \ zs = z # zs' \ x = z \ zs' \ shuffles xs' ys \ P) \ (\y ys' z zs'. ys = y # ys' \ zs = z # zs' \ y = z \ zs' \ shuffles xs ys' \ P) \ P" by (induct xs ys rule: shuffles.induct) auto lemma Cons_in_shuffles_iff: "z # zs \ shuffles xs ys \ (xs \ [] \ hd xs = z \ zs \ shuffles (tl xs) ys \ ys \ [] \ hd ys = z \ zs \ shuffles xs (tl ys))" by (induct xs ys rule: shuffles.induct) auto lemma splice_in_shuffles [simp, intro]: "splice xs ys \ shuffles xs ys" by (induction xs ys rule: splice.induct) (simp_all add: Cons_in_shuffles_iff shuffles_commutes) lemma Nil_in_shufflesI: "xs = [] \ ys = [] \ [] \ shuffles xs ys" by simp lemma Cons_in_shuffles_leftI: "zs \ shuffles xs ys \ z # zs \ shuffles (z # xs) ys" by (cases ys) auto lemma Cons_in_shuffles_rightI: "zs \ shuffles xs ys \ z # zs \ shuffles xs (z # ys)" by (cases xs) auto lemma finite_shuffles [simp, intro]: "finite (shuffles xs ys)" by (induction xs ys rule: shuffles.induct) simp_all lemma length_shuffles: "zs \ shuffles xs ys \ length zs = length xs + length ys" by (induction xs ys arbitrary: zs rule: shuffles.induct) auto lemma set_shuffles: "zs \ shuffles xs ys \ set zs = set xs \ set ys" by (induction xs ys arbitrary: zs rule: shuffles.induct) auto lemma distinct_disjoint_shuffles: assumes "distinct xs" "distinct ys" "set xs \ set ys = {}" "zs \ shuffles xs ys" shows "distinct zs" using assms proof (induction xs ys arbitrary: zs rule: shuffles.induct) case (3 x xs y ys) show ?case proof (cases zs) case (Cons z zs') with "3.prems" and "3.IH"[of zs'] show ?thesis by (force dest: set_shuffles) qed simp_all qed simp_all lemma Cons_shuffles_subset1: "(#) x ` shuffles xs ys \ shuffles (x # xs) ys" by (cases ys) auto lemma Cons_shuffles_subset2: "(#) y ` shuffles xs ys \ shuffles xs (y # ys)" by (cases xs) auto lemma filter_shuffles: "filter P ` shuffles xs ys = shuffles (filter P xs) (filter P ys)" proof - have *: "filter P ` (#) x ` A = (if P x then (#) x ` filter P ` A else filter P ` A)" for x A by (auto simp: image_image) show ?thesis by (induction xs ys rule: shuffles.induct) (simp_all split: if_splits add: image_Un * Un_absorb1 Un_absorb2 Cons_shuffles_subset1 Cons_shuffles_subset2) qed lemma filter_shuffles_disjoint1: assumes "set xs \ set ys = {}" "zs \ shuffles xs ys" shows "filter (\x. x \ set xs) zs = xs" (is "filter ?P _ = _") and "filter (\x. x \ set xs) zs = ys" (is "filter ?Q _ = _") using assms proof - from assms have "filter ?P zs \ filter ?P ` shuffles xs ys" by blast also have "filter ?P ` shuffles xs ys = shuffles (filter ?P xs) (filter ?P ys)" by (rule filter_shuffles) also have "filter ?P xs = xs" by (rule filter_True) simp_all also have "filter ?P ys = []" by (rule filter_False) (insert assms(1), auto) also have "shuffles xs [] = {xs}" by simp finally show "filter ?P zs = xs" by simp next from assms have "filter ?Q zs \ filter ?Q ` shuffles xs ys" by blast also have "filter ?Q ` shuffles xs ys = shuffles (filter ?Q xs) (filter ?Q ys)" by (rule filter_shuffles) also have "filter ?Q ys = ys" by (rule filter_True) (insert assms(1), auto) also have "filter ?Q xs = []" by (rule filter_False) (insert assms(1), auto) also have "shuffles [] ys = {ys}" by simp finally show "filter ?Q zs = ys" by simp qed lemma filter_shuffles_disjoint2: assumes "set xs \ set ys = {}" "zs \ shuffles xs ys" shows "filter (\x. x \ set ys) zs = ys" "filter (\x. x \ set ys) zs = xs" using filter_shuffles_disjoint1[of ys xs zs] assms by (simp_all add: shuffles_commutes Int_commute) lemma partition_in_shuffles: "xs \ shuffles (filter P xs) (filter (\x. \P x) xs)" proof (induction xs) case (Cons x xs) show ?case proof (cases "P x") case True hence "x # xs \ (#) x ` shuffles (filter P xs) (filter (\x. \P x) xs)" by (intro imageI Cons.IH) also have "\ \ shuffles (filter P (x # xs)) (filter (\x. \P x) (x # xs))" by (simp add: True Cons_shuffles_subset1) finally show ?thesis . next case False hence "x # xs \ (#) x ` shuffles (filter P xs) (filter (\x. \P x) xs)" by (intro imageI Cons.IH) also have "\ \ shuffles (filter P (x # xs)) (filter (\x. \P x) (x # xs))" by (simp add: False Cons_shuffles_subset2) finally show ?thesis . qed qed auto lemma inv_image_partition: assumes "\x. x \ set xs \ P x" "\y. y \ set ys \ \P y" shows "partition P -` {(xs, ys)} = shuffles xs ys" proof (intro equalityI subsetI) fix zs assume zs: "zs \ shuffles xs ys" hence [simp]: "set zs = set xs \ set ys" by (rule set_shuffles) from assms have "filter P zs = filter (\x. x \ set xs) zs" "filter (\x. \P x) zs = filter (\x. x \ set ys) zs" by (intro filter_cong refl; force)+ moreover from assms have "set xs \ set ys = {}" by auto ultimately show "zs \ partition P -` {(xs, ys)}" using zs by (simp add: o_def filter_shuffles_disjoint1 filter_shuffles_disjoint2) next fix zs assume "zs \ partition P -` {(xs, ys)}" thus "zs \ shuffles xs ys" using partition_in_shuffles[of zs] by (auto simp: o_def) qed subsubsection \Transpose\ function transpose where "transpose [] = []" | "transpose ([] # xss) = transpose xss" | "transpose ((x#xs) # xss) = (x # [h. (h#t) \ xss]) # transpose (xs # [t. (h#t) \ xss])" by pat_completeness auto lemma transpose_aux_filter_head: "concat (map (case_list [] (\h t. [h])) xss) = map (\xs. hd xs) (filter (\ys. ys \ []) xss)" by (induct xss) (auto split: list.split) lemma transpose_aux_filter_tail: "concat (map (case_list [] (\h t. [t])) xss) = map (\xs. tl xs) (filter (\ys. ys \ []) xss)" by (induct xss) (auto split: list.split) lemma transpose_aux_max: "max (Suc (length xs)) (foldr (\xs. max (length xs)) xss 0) = Suc (max (length xs) (foldr (\x. max (length x - Suc 0)) (filter (\ys. ys \ []) xss) 0))" (is "max _ ?foldB = Suc (max _ ?foldA)") proof (cases "(filter (\ys. ys \ []) xss) = []") case True hence "foldr (\xs. max (length xs)) xss 0 = 0" proof (induct xss) case (Cons x xs) then have "x = []" by (cases x) auto with Cons show ?case by auto qed simp thus ?thesis using True by simp next case False have foldA: "?foldA = foldr (\x. max (length x)) (filter (\ys. ys \ []) xss) 0 - 1" by (induct xss) auto have foldB: "?foldB = foldr (\x. max (length x)) (filter (\ys. ys \ []) xss) 0" by (induct xss) auto have "0 < ?foldB" proof - from False obtain z zs where zs: "(filter (\ys. ys \ []) xss) = z#zs" by (auto simp: neq_Nil_conv) hence "z \ set (filter (\ys. ys \ []) xss)" by auto hence "z \ []" by auto thus ?thesis unfolding foldB zs by (auto simp: max_def intro: less_le_trans) qed thus ?thesis unfolding foldA foldB max_Suc_Suc[symmetric] by simp qed termination transpose by (relation "measure (\xs. foldr (\xs. max (length xs)) xs 0 + length xs)") (auto simp: transpose_aux_filter_tail foldr_map comp_def transpose_aux_max less_Suc_eq_le) lemma transpose_empty: "(transpose xs = []) \ (\x \ set xs. x = [])" by (induct rule: transpose.induct) simp_all lemma length_transpose: fixes xs :: "'a list list" shows "length (transpose xs) = foldr (\xs. max (length xs)) xs 0" by (induct rule: transpose.induct) (auto simp: transpose_aux_filter_tail foldr_map comp_def transpose_aux_max max_Suc_Suc[symmetric] simp del: max_Suc_Suc) lemma nth_transpose: fixes xs :: "'a list list" assumes "i < length (transpose xs)" shows "transpose xs ! i = map (\xs. xs ! i) (filter (\ys. i < length ys) xs)" using assms proof (induct arbitrary: i rule: transpose.induct) case (3 x xs xss) define XS where "XS = (x # xs) # xss" hence [simp]: "XS \ []" by auto thus ?case proof (cases i) case 0 thus ?thesis by (simp add: transpose_aux_filter_head hd_conv_nth) next case (Suc j) have *: "\xss. xs # map tl xss = map tl ((x#xs)#xss)" by simp have **: "\xss. (x#xs) # filter (\ys. ys \ []) xss = filter (\ys. ys \ []) ((x#xs)#xss)" by simp { fix x have "Suc j < length x \ x \ [] \ j < length x - Suc 0" by (cases x) simp_all } note *** = this have j_less: "j < length (transpose (xs # concat (map (case_list [] (\h t. [t])) xss)))" using "3.prems" by (simp add: transpose_aux_filter_tail length_transpose Suc) show ?thesis unfolding transpose.simps \i = Suc j\ nth_Cons_Suc "3.hyps"[OF j_less] apply (auto simp: transpose_aux_filter_tail filter_map comp_def length_transpose * ** *** XS_def[symmetric]) by (simp add: nth_tl) qed qed simp_all lemma transpose_map_map: "transpose (map (map f) xs) = map (map f) (transpose xs)" proof (rule nth_equalityI) have [simp]: "length (transpose (map (map f) xs)) = length (transpose xs)" by (simp add: length_transpose foldr_map comp_def) show "length (transpose (map (map f) xs)) = length (map (map f) (transpose xs))" by simp fix i assume "i < length (transpose (map (map f) xs))" thus "transpose (map (map f) xs) ! i = map (map f) (transpose xs) ! i" by (simp add: nth_transpose filter_map comp_def) qed subsubsection \\<^const>\min\ and \<^const>\arg_min\\ lemma min_list_Min: "xs \ [] \ min_list xs = Min (set xs)" by (induction xs rule: induct_list012)(auto) lemma f_arg_min_list_f: "xs \ [] \ f (arg_min_list f xs) = Min (f ` (set xs))" by(induction f xs rule: arg_min_list.induct) (auto simp: min_def intro!: antisym) lemma arg_min_list_in: "xs \ [] \ arg_min_list f xs \ set xs" by(induction xs rule: induct_list012) (auto simp: Let_def) subsubsection \(In)finiteness\ lemma finite_maxlen: "finite (M::'a list set) \ \n. \s\M. size s < n" proof (induct rule: finite.induct) case emptyI show ?case by simp next case (insertI M xs) then obtain n where "\s\M. length s < n" by blast hence "\s\insert xs M. size s < max n (size xs) + 1" by auto thus ?case .. qed lemma lists_length_Suc_eq: "{xs. set xs \ A \ length xs = Suc n} = (\(xs, n). n#xs) ` ({xs. set xs \ A \ length xs = n} \ A)" by (auto simp: length_Suc_conv) lemma assumes "finite A" shows finite_lists_length_eq: "finite {xs. set xs \ A \ length xs = n}" and card_lists_length_eq: "card {xs. set xs \ A \ length xs = n} = (card A)^n" using \finite A\ by (induct n) (auto simp: card_image inj_split_Cons lists_length_Suc_eq cong: conj_cong) lemma finite_lists_length_le: assumes "finite A" shows "finite {xs. set xs \ A \ length xs \ n}" (is "finite ?S") proof- have "?S = (\n\{0..n}. {xs. set xs \ A \ length xs = n})" by auto thus ?thesis by (auto intro!: finite_lists_length_eq[OF \finite A\] simp only:) qed lemma card_lists_length_le: assumes "finite A" shows "card {xs. set xs \ A \ length xs \ n} = (\i\n. card A^i)" proof - have "(\i\n. card A^i) = card (\i\n. {xs. set xs \ A \ length xs = i})" using \finite A\ by (subst card_UN_disjoint) (auto simp add: card_lists_length_eq finite_lists_length_eq) also have "(\i\n. {xs. set xs \ A \ length xs = i}) = {xs. set xs \ A \ length xs \ n}" by auto finally show ?thesis by simp qed lemma finite_lists_distinct_length_eq [intro]: assumes "finite A" shows "finite {xs. length xs = n \ distinct xs \ set xs \ A}" (is "finite ?S") proof - have "finite {xs. set xs \ A \ length xs = n}" using \finite A\ by (rule finite_lists_length_eq) moreover have "?S \ {xs. set xs \ A \ length xs = n}" by auto ultimately show ?thesis using finite_subset by auto qed lemma card_lists_distinct_length_eq: assumes "finite A" "k \ card A" shows "card {xs. length xs = k \ distinct xs \ set xs \ A} = \{card A - k + 1 .. card A}" using assms proof (induct k) case 0 then have "{xs. length xs = 0 \ distinct xs \ set xs \ A} = {[]}" by auto then show ?case by simp next case (Suc k) let "?k_list" = "\k xs. length xs = k \ distinct xs \ set xs \ A" have inj_Cons: "\A. inj_on (\(xs, n). n # xs) A" by (rule inj_onI) auto from Suc have "k \ card A" by simp moreover note \finite A\ moreover have "finite {xs. ?k_list k xs}" by (rule finite_subset) (use finite_lists_length_eq[OF \finite A\, of k] in auto) moreover have "\i j. i \ j \ {i} \ (A - set i) \ {j} \ (A - set j) = {}" by auto moreover have "\i. i \ {xs. ?k_list k xs} \ card (A - set i) = card A - k" by (simp add: card_Diff_subset distinct_card) moreover have "{xs. ?k_list (Suc k) xs} = (\(xs, n). n#xs) ` \((\xs. {xs} \ (A - set xs)) ` {xs. ?k_list k xs})" by (auto simp: length_Suc_conv) moreover have "Suc (card A - Suc k) = card A - k" using Suc.prems by simp then have "(card A - k) * \{Suc (card A - k)..card A} = \{Suc (card A - Suc k)..card A}" by (subst prod.insert[symmetric]) (simp add: atLeastAtMost_insertL)+ ultimately show ?case by (simp add: card_image inj_Cons card_UN_disjoint Suc.hyps algebra_simps) qed lemma card_lists_distinct_length_eq': assumes "k < card A" shows "card {xs. length xs = k \ distinct xs \ set xs \ A} = \{card A - k + 1 .. card A}" proof - from \k < card A\ have "finite A" and "k \ card A" using card.infinite by force+ from this show ?thesis by (rule card_lists_distinct_length_eq) qed lemma infinite_UNIV_listI: "\ finite(UNIV::'a list set)" by (metis UNIV_I finite_maxlen length_replicate less_irrefl) lemma same_length_different: assumes "xs \ ys" and "length xs = length ys" shows "\pre x xs' y ys'. x\y \ xs = pre @ [x] @ xs' \ ys = pre @ [y] @ ys'" using assms proof (induction xs arbitrary: ys) case Nil then show ?case by auto next case (Cons x xs) then obtain z zs where ys: "ys = Cons z zs" by (metis length_Suc_conv) show ?case proof (cases "x=z") case True then have "xs \ zs" "length xs = length zs" using Cons.prems ys by auto then obtain pre u xs' v ys' where "u\v" and xs: "xs = pre @ [u] @ xs'" and zs: "zs = pre @ [v] @ys'" using Cons.IH by meson then have "x # xs = (z#pre) @ [u] @ xs' \ ys = (z#pre) @ [v] @ ys'" by (simp add: True ys) with \u\v\ show ?thesis by blast next case False then have "x # xs = [] @ [x] @ xs \ ys = [] @ [z] @ zs" by (simp add: ys) then show ?thesis using False by blast qed qed subsection \Sorting\ subsubsection \\<^const>\sorted_wrt\\ text \Sometimes the second equation in the definition of \<^const>\sorted_wrt\ is too aggressive because it relates each list element to \emph{all} its successors. Then this equation should be removed and \sorted_wrt2_simps\ should be added instead.\ lemma sorted_wrt1: "sorted_wrt P [x] = True" by(simp) lemma sorted_wrt2: "transp P \ sorted_wrt P (x # y # zs) = (P x y \ sorted_wrt P (y # zs))" proof (induction zs arbitrary: x y) case (Cons z zs) then show ?case by simp (meson transpD)+ qed auto lemmas sorted_wrt2_simps = sorted_wrt1 sorted_wrt2 lemma sorted_wrt_true [simp]: "sorted_wrt (\_ _. True) xs" by (induction xs) simp_all lemma sorted_wrt_append: "sorted_wrt P (xs @ ys) \ sorted_wrt P xs \ sorted_wrt P ys \ (\x\set xs. \y\set ys. P x y)" by (induction xs) auto lemma sorted_wrt_map: "sorted_wrt R (map f xs) = sorted_wrt (\x y. R (f x) (f y)) xs" by (induction xs) simp_all lemma assumes "sorted_wrt f xs" shows sorted_wrt_take: "sorted_wrt f (take n xs)" and sorted_wrt_drop: "sorted_wrt f (drop n xs)" proof - from assms have "sorted_wrt f (take n xs @ drop n xs)" by simp thus "sorted_wrt f (take n xs)" and "sorted_wrt f (drop n xs)" unfolding sorted_wrt_append by simp_all qed lemma sorted_wrt_filter: "sorted_wrt f xs \ sorted_wrt f (filter P xs)" by (induction xs) auto lemma sorted_wrt_rev: "sorted_wrt P (rev xs) = sorted_wrt (\x y. P y x) xs" by (induction xs) (auto simp add: sorted_wrt_append) lemma sorted_wrt_mono_rel: "(\x y. \ x \ set xs; y \ set xs; P x y \ \ Q x y) \ sorted_wrt P xs \ sorted_wrt Q xs" by(induction xs)(auto) lemma sorted_wrt01: "length xs \ 1 \ sorted_wrt P xs" by(auto simp: le_Suc_eq length_Suc_conv) lemma sorted_wrt_iff_nth_less: "sorted_wrt P xs = (\i j. i < j \ j < length xs \ P (xs ! i) (xs ! j))" by (induction xs) (auto simp add: in_set_conv_nth Ball_def nth_Cons split: nat.split) lemma sorted_wrt_nth_less: "\ sorted_wrt P xs; i < j; j < length xs \ \ P (xs ! i) (xs ! j)" by(auto simp: sorted_wrt_iff_nth_less) lemma sorted_wrt_iff_nth_Suc_transp: assumes "transp P" shows "sorted_wrt P xs \ (\i. Suc i < length xs \ P (xs!i) (xs!(Suc i)))" (is "?L = ?R") proof assume ?L thus ?R by (simp add: sorted_wrt_iff_nth_less) next assume ?R have "i < j \ j < length xs \ P (xs ! i) (xs ! j)" for i j by(induct i j rule: less_Suc_induct)(simp add: \?R\, meson assms transpE transp_less) thus ?L by (simp add: sorted_wrt_iff_nth_less) qed lemma sorted_wrt_upt[simp]: "sorted_wrt (<) [m..Each element is greater or equal to its index:\ lemma sorted_wrt_less_idx: "sorted_wrt (<) ns \ i < length ns \ i \ ns!i" proof (induction ns arbitrary: i rule: rev_induct) case Nil thus ?case by simp next case snoc thus ?case by (auto simp: nth_append sorted_wrt_append) (metis less_antisym not_less nth_mem) qed subsubsection \\<^const>\sorted\\ context linorder begin text \Sometimes the second equation in the definition of \<^const>\sorted\ is too aggressive because it relates each list element to \emph{all} its successors. Then this equation should be removed and \sorted2_simps\ should be added instead. Executable code is one such use case.\ lemma sorted0: "sorted [] = True" by simp lemma sorted1: "sorted [x] = True" by simp lemma sorted2: "sorted (x # y # zs) = (x \ y \ sorted (y # zs))" by(induction zs) auto lemmas sorted2_simps = sorted1 sorted2 lemmas [code] = sorted0 sorted2_simps lemma sorted_append: "sorted (xs@ys) = (sorted xs \ sorted ys \ (\x \ set xs. \y \ set ys. x\y))" by (simp add: sorted_wrt_append) lemma sorted_map: "sorted (map f xs) = sorted_wrt (\x y. f x \ f y) xs" by (simp add: sorted_wrt_map) lemma sorted01: "length xs \ 1 \ sorted xs" by (simp add: sorted_wrt01) lemma sorted_tl: "sorted xs \ sorted (tl xs)" by (cases xs) (simp_all) lemma sorted_iff_nth_mono_less: "sorted xs = (\i j. i < j \ j < length xs \ xs ! i \ xs ! j)" by (simp add: sorted_wrt_iff_nth_less) lemma sorted_iff_nth_mono: "sorted xs = (\i j. i \ j \ j < length xs \ xs ! i \ xs ! j)" by (auto simp: sorted_iff_nth_mono_less nat_less_le) lemma sorted_nth_mono: "sorted xs \ i \ j \ j < length xs \ xs!i \ xs!j" by (auto simp: sorted_iff_nth_mono) lemma sorted_iff_nth_Suc: "sorted xs \ (\i. Suc i < length xs \ xs!i \ xs!(Suc i))" by(simp add: sorted_wrt_iff_nth_Suc_transp) lemma sorted_rev_nth_mono: "sorted (rev xs) \ i \ j \ j < length xs \ xs!j \ xs!i" using sorted_nth_mono[ of "rev xs" "length xs - j - 1" "length xs - i - 1"] rev_nth[of "length xs - i - 1" "xs"] rev_nth[of "length xs - j - 1" "xs"] by auto lemma sorted_rev_iff_nth_mono: "sorted (rev xs) \ (\ i j. i \ j \ j < length xs \ xs!j \ xs!i)" (is "?L = ?R") proof assume ?L thus ?R by (blast intro: sorted_rev_nth_mono) next assume ?R have "rev xs ! k \ rev xs ! l" if asms: "k \ l" "l < length(rev xs)" for k l proof - have "k < length xs" "l < length xs" "length xs - Suc l \ length xs - Suc k" "length xs - Suc k < length xs" using asms by auto thus "rev xs ! k \ rev xs ! l" using \?R\ \k \ l\ unfolding rev_nth[OF \k < length xs\] rev_nth[OF \l < length xs\] by blast qed thus ?L by (simp add: sorted_iff_nth_mono) qed lemma sorted_rev_iff_nth_Suc: "sorted (rev xs) \ (\i. Suc i < length xs \ xs!(Suc i) \ xs!i)" proof- interpret dual: linorder "(\x y. y \ x)" "(\x y. y < x)" using dual_linorder . show ?thesis using dual_linorder dual.sorted_iff_nth_Suc dual.sorted_iff_nth_mono unfolding sorted_rev_iff_nth_mono by simp qed lemma sorted_map_remove1: "sorted (map f xs) \ sorted (map f (remove1 x xs))" by (induct xs) (auto) lemma sorted_remove1: "sorted xs \ sorted (remove1 a xs)" using sorted_map_remove1 [of "\x. x"] by simp lemma sorted_butlast: assumes "xs \ []" and "sorted xs" shows "sorted (butlast xs)" proof - from \xs \ []\ obtain ys y where "xs = ys @ [y]" by (cases xs rule: rev_cases) auto with \sorted xs\ show ?thesis by (simp add: sorted_append) qed lemma sorted_replicate [simp]: "sorted(replicate n x)" by(induction n) (auto) lemma sorted_remdups[simp]: "sorted xs \ sorted (remdups xs)" by (induct xs) (auto) lemma sorted_remdups_adj[simp]: "sorted xs \ sorted (remdups_adj xs)" by (induct xs rule: remdups_adj.induct, simp_all split: if_split_asm) lemma sorted_nths: "sorted xs \ sorted (nths xs I)" by(induction xs arbitrary: I)(auto simp: nths_Cons) lemma sorted_distinct_set_unique: assumes "sorted xs" "distinct xs" "sorted ys" "distinct ys" "set xs = set ys" shows "xs = ys" proof - from assms have 1: "length xs = length ys" by (auto dest!: distinct_card) from assms show ?thesis proof(induct rule:list_induct2[OF 1]) case 1 show ?case by simp next case (2 x xs y ys) then show ?case by (cases \x = y\) (auto simp add: insert_eq_iff) qed qed lemma map_sorted_distinct_set_unique: assumes "inj_on f (set xs \ set ys)" assumes "sorted (map f xs)" "distinct (map f xs)" "sorted (map f ys)" "distinct (map f ys)" assumes "set xs = set ys" shows "xs = ys" proof - from assms have "map f xs = map f ys" by (simp add: sorted_distinct_set_unique) with \inj_on f (set xs \ set ys)\ show "xs = ys" by (blast intro: map_inj_on) qed lemma assumes "sorted xs" shows sorted_take: "sorted (take n xs)" and sorted_drop: "sorted (drop n xs)" proof - from assms have "sorted (take n xs @ drop n xs)" by simp then show "sorted (take n xs)" and "sorted (drop n xs)" unfolding sorted_append by simp_all qed lemma sorted_dropWhile: "sorted xs \ sorted (dropWhile P xs)" by (auto dest: sorted_drop simp add: dropWhile_eq_drop) lemma sorted_takeWhile: "sorted xs \ sorted (takeWhile P xs)" by (subst takeWhile_eq_take) (auto dest: sorted_take) lemma sorted_filter: "sorted (map f xs) \ sorted (map f (filter P xs))" by (induct xs) simp_all lemma foldr_max_sorted: assumes "sorted (rev xs)" shows "foldr max xs y = (if xs = [] then y else max (xs ! 0) y)" using assms proof (induct xs) case (Cons x xs) then have "sorted (rev xs)" using sorted_append by auto with Cons show ?case by (cases xs) (auto simp add: sorted_append max_def) qed simp lemma filter_equals_takeWhile_sorted_rev: assumes sorted: "sorted (rev (map f xs))" shows "filter (\x. t < f x) xs = takeWhile (\ x. t < f x) xs" (is "filter ?P xs = ?tW") proof (rule takeWhile_eq_filter[symmetric]) let "?dW" = "dropWhile ?P xs" fix x assume "x \ set ?dW" then obtain i where i: "i < length ?dW" and nth_i: "x = ?dW ! i" unfolding in_set_conv_nth by auto hence "length ?tW + i < length (?tW @ ?dW)" unfolding length_append by simp hence i': "length (map f ?tW) + i < length (map f xs)" by simp have "(map f ?tW @ map f ?dW) ! (length (map f ?tW) + i) \ (map f ?tW @ map f ?dW) ! (length (map f ?tW) + 0)" using sorted_rev_nth_mono[OF sorted _ i', of "length ?tW"] unfolding map_append[symmetric] by simp hence "f x \ f (?dW ! 0)" unfolding nth_append_length_plus nth_i using i preorder_class.le_less_trans[OF le0 i] by simp also have "... \ t" using hd_dropWhile[of "?P" xs] le0[THEN preorder_class.le_less_trans, OF i] using hd_conv_nth[of "?dW"] by simp finally show "\ t < f x" by simp qed lemma sorted_map_same: "sorted (map f (filter (\x. f x = g xs) xs))" proof (induct xs arbitrary: g) case Nil then show ?case by simp next case (Cons x xs) then have "sorted (map f (filter (\y. f y = (\xs. f x) xs) xs))" . moreover from Cons have "sorted (map f (filter (\y. f y = (g \ Cons x) xs) xs))" . ultimately show ?case by simp_all qed lemma sorted_same: "sorted (filter (\x. x = g xs) xs)" using sorted_map_same [of "\x. x"] by simp end lemma sorted_upt[simp]: "sorted [m..Sorting functions\ text\Currently it is not shown that \<^const>\sort\ returns a permutation of its input because the nicest proof is via multisets, which are not part of Main. Alternatively one could define a function that counts the number of occurrences of an element in a list and use that instead of multisets to state the correctness property.\ context linorder begin lemma set_insort_key: "set (insort_key f x xs) = insert x (set xs)" by (induct xs) auto lemma length_insort [simp]: "length (insort_key f x xs) = Suc (length xs)" by (induct xs) simp_all lemma insort_key_left_comm: assumes "f x \ f y" shows "insort_key f y (insort_key f x xs) = insort_key f x (insort_key f y xs)" by (induct xs) (auto simp add: assms dest: order.antisym) lemma insort_left_comm: "insort x (insort y xs) = insort y (insort x xs)" by (cases "x = y") (auto intro: insort_key_left_comm) lemma comp_fun_commute_insort: "comp_fun_commute insort" proof qed (simp add: insort_left_comm fun_eq_iff) lemma sort_key_simps [simp]: "sort_key f [] = []" "sort_key f (x#xs) = insort_key f x (sort_key f xs)" by (simp_all add: sort_key_def) lemma sort_key_conv_fold: assumes "inj_on f (set xs)" shows "sort_key f xs = fold (insort_key f) xs []" proof - have "fold (insort_key f) (rev xs) = fold (insort_key f) xs" proof (rule fold_rev, rule ext) fix zs fix x y assume "x \ set xs" "y \ set xs" with assms have *: "f y = f x \ y = x" by (auto dest: inj_onD) have **: "x = y \ y = x" by auto show "(insort_key f y \ insort_key f x) zs = (insort_key f x \ insort_key f y) zs" by (induct zs) (auto intro: * simp add: **) qed then show ?thesis by (simp add: sort_key_def foldr_conv_fold) qed lemma sort_conv_fold: "sort xs = fold insort xs []" by (rule sort_key_conv_fold) simp lemma length_sort[simp]: "length (sort_key f xs) = length xs" by (induct xs, auto) lemma set_sort[simp]: "set(sort_key f xs) = set xs" by (induct xs) (simp_all add: set_insort_key) lemma distinct_insort: "distinct (insort_key f x xs) = (x \ set xs \ distinct xs)" by(induct xs)(auto simp: set_insort_key) +lemma distinct_insort_key: + "distinct (map f (insort_key f x xs)) = (f x \ f ` set xs \ (distinct (map f xs)))" +by (induct xs) (auto simp: set_insort_key) + lemma distinct_sort[simp]: "distinct (sort_key f xs) = distinct xs" by (induct xs) (simp_all add: distinct_insort) lemma sorted_insort_key: "sorted (map f (insort_key f x xs)) = sorted (map f xs)" by (induct xs) (auto simp: set_insort_key) lemma sorted_insort: "sorted (insort x xs) = sorted xs" using sorted_insort_key [where f="\x. x"] by simp theorem sorted_sort_key [simp]: "sorted (map f (sort_key f xs))" by (induct xs) (auto simp:sorted_insort_key) theorem sorted_sort [simp]: "sorted (sort xs)" using sorted_sort_key [where f="\x. x"] by simp lemma insort_not_Nil [simp]: "insort_key f a xs \ []" by (induction xs) simp_all lemma insort_is_Cons: "\x\set xs. f a \ f x \ insort_key f a xs = a # xs" by (cases xs) auto lemma sorted_sort_id: "sorted xs \ sort xs = xs" by (induct xs) (auto simp add: insort_is_Cons) lemma insort_key_remove1: assumes "a \ set xs" and "sorted (map f xs)" and "hd (filter (\x. f a = f x) xs) = a" shows "insort_key f a (remove1 a xs) = xs" using assms proof (induct xs) case (Cons x xs) then show ?case proof (cases "x = a") case False then have "f x \ f a" using Cons.prems by auto then have "f x < f a" using Cons.prems by auto with \f x \ f a\ show ?thesis using Cons by (auto simp: insort_is_Cons) qed (auto simp: insort_is_Cons) qed simp lemma insort_remove1: assumes "a \ set xs" and "sorted xs" shows "insort a (remove1 a xs) = xs" proof (rule insort_key_remove1) define n where "n = length (filter ((=) a) xs) - 1" from \a \ set xs\ show "a \ set xs" . from \sorted xs\ show "sorted (map (\x. x) xs)" by simp from \a \ set xs\ have "a \ set (filter ((=) a) xs)" by auto then have "set (filter ((=) a) xs) \ {}" by auto then have "filter ((=) a) xs \ []" by (auto simp only: set_empty) then have "length (filter ((=) a) xs) > 0" by simp then have n: "Suc n = length (filter ((=) a) xs)" by (simp add: n_def) moreover have "replicate (Suc n) a = a # replicate n a" by simp ultimately show "hd (filter ((=) a) xs) = a" by (simp add: replicate_length_filter) qed lemma finite_sorted_distinct_unique: assumes "finite A" shows "\!xs. set xs = A \ sorted xs \ distinct xs" proof - obtain xs where "distinct xs" "A = set xs" using finite_distinct_list [OF assms] by metis then show ?thesis by (rule_tac a="sort xs" in ex1I) (auto simp: sorted_distinct_set_unique) qed lemma insort_insert_key_triv: "f x \ f ` set xs \ insort_insert_key f x xs = xs" by (simp add: insort_insert_key_def) lemma insort_insert_triv: "x \ set xs \ insort_insert x xs = xs" using insort_insert_key_triv [of "\x. x"] by simp lemma insort_insert_insort_key: "f x \ f ` set xs \ insort_insert_key f x xs = insort_key f x xs" by (simp add: insort_insert_key_def) lemma insort_insert_insort: "x \ set xs \ insort_insert x xs = insort x xs" using insort_insert_insort_key [of "\x. x"] by simp lemma set_insort_insert: "set (insort_insert x xs) = insert x (set xs)" by (auto simp add: insort_insert_key_def set_insort_key) lemma distinct_insort_insert: assumes "distinct xs" shows "distinct (insort_insert_key f x xs)" using assms by (induct xs) (auto simp add: insort_insert_key_def set_insort_key) lemma sorted_insort_insert_key: assumes "sorted (map f xs)" shows "sorted (map f (insort_insert_key f x xs))" using assms by (simp add: insort_insert_key_def sorted_insort_key) lemma sorted_insort_insert: assumes "sorted xs" shows "sorted (insort_insert x xs)" using assms sorted_insort_insert_key [of "\x. x"] by simp lemma filter_insort_triv: "\ P x \ filter P (insort_key f x xs) = filter P xs" by (induct xs) simp_all lemma filter_insort: "sorted (map f xs) \ P x \ filter P (insort_key f x xs) = insort_key f x (filter P xs)" by (induct xs) (auto, subst insort_is_Cons, auto) lemma filter_sort: "filter P (sort_key f xs) = sort_key f (filter P xs)" by (induct xs) (simp_all add: filter_insort_triv filter_insort) -lemma remove1_insort [simp]: - "remove1 x (insort x xs) = xs" +lemma remove1_insort_key [simp]: + "remove1 x (insort_key f x xs) = xs" by (induct xs) simp_all end lemma sort_upt [simp]: "sort [m.. \x \ set xs. P x \ List.find P xs = Some (Min {x\set xs. P x})" proof (induct xs) case Nil then show ?case by simp next case (Cons x xs) show ?case proof (cases "P x") case True with Cons show ?thesis by (auto intro: Min_eqI [symmetric]) next case False then have "{y. (y = x \ y \ set xs) \ P y} = {y \ set xs. P y}" by auto with Cons False show ?thesis by (simp_all) qed qed lemma sorted_enumerate [simp]: "sorted (map fst (enumerate n xs))" by (simp add: enumerate_eq_zip) text \Stability of \<^const>\sort_key\:\ lemma sort_key_stable: "filter (\y. f y = k) (sort_key f xs) = filter (\y. f y = k) xs" by (induction xs) (auto simp: filter_insort insort_is_Cons filter_insort_triv) corollary stable_sort_key_sort_key: "stable_sort_key sort_key" by(simp add: stable_sort_key_def sort_key_stable) lemma sort_key_const: "sort_key (\x. c) xs = xs" by (metis (mono_tags) filter_True sort_key_stable) subsubsection \\<^const>\transpose\ on sorted lists\ lemma sorted_transpose[simp]: "sorted (rev (map length (transpose xs)))" by (auto simp: sorted_iff_nth_mono rev_nth nth_transpose length_filter_conv_card intro: card_mono) lemma transpose_max_length: "foldr (\xs. max (length xs)) (transpose xs) 0 = length (filter (\x. x \ []) xs)" (is "?L = ?R") proof (cases "transpose xs = []") case False have "?L = foldr max (map length (transpose xs)) 0" by (simp add: foldr_map comp_def) also have "... = length (transpose xs ! 0)" using False sorted_transpose by (simp add: foldr_max_sorted) finally show ?thesis using False by (simp add: nth_transpose) next case True hence "filter (\x. x \ []) xs = []" by (auto intro!: filter_False simp: transpose_empty) thus ?thesis by (simp add: transpose_empty True) qed lemma length_transpose_sorted: fixes xs :: "'a list list" assumes sorted: "sorted (rev (map length xs))" shows "length (transpose xs) = (if xs = [] then 0 else length (xs ! 0))" proof (cases "xs = []") case False thus ?thesis using foldr_max_sorted[OF sorted] False unfolding length_transpose foldr_map comp_def by simp qed simp lemma nth_nth_transpose_sorted[simp]: fixes xs :: "'a list list" assumes sorted: "sorted (rev (map length xs))" and i: "i < length (transpose xs)" and j: "j < length (filter (\ys. i < length ys) xs)" shows "transpose xs ! i ! j = xs ! j ! i" using j filter_equals_takeWhile_sorted_rev[OF sorted, of i] nth_transpose[OF i] nth_map[OF j] by (simp add: takeWhile_nth) lemma transpose_column_length: fixes xs :: "'a list list" assumes sorted: "sorted (rev (map length xs))" and "i < length xs" shows "length (filter (\ys. i < length ys) (transpose xs)) = length (xs ! i)" proof - have "xs \ []" using \i < length xs\ by auto note filter_equals_takeWhile_sorted_rev[OF sorted, simp] { fix j assume "j \ i" note sorted_rev_nth_mono[OF sorted, of j i, simplified, OF this \i < length xs\] } note sortedE = this[consumes 1] have "{j. j < length (transpose xs) \ i < length (transpose xs ! j)} = {..< length (xs ! i)}" proof safe fix j assume "j < length (transpose xs)" and "i < length (transpose xs ! j)" with this(2) nth_transpose[OF this(1)] have "i < length (takeWhile (\ys. j < length ys) xs)" by simp from nth_mem[OF this] takeWhile_nth[OF this] show "j < length (xs ! i)" by (auto dest: set_takeWhileD) next fix j assume "j < length (xs ! i)" thus "j < length (transpose xs)" using foldr_max_sorted[OF sorted] \xs \ []\ sortedE[OF le0] by (auto simp: length_transpose comp_def foldr_map) have "Suc i \ length (takeWhile (\ys. j < length ys) xs)" using \i < length xs\ \j < length (xs ! i)\ less_Suc_eq_le by (auto intro!: length_takeWhile_less_P_nth dest!: sortedE) with nth_transpose[OF \j < length (transpose xs)\] show "i < length (transpose xs ! j)" by simp qed thus ?thesis by (simp add: length_filter_conv_card) qed lemma transpose_column: fixes xs :: "'a list list" assumes sorted: "sorted (rev (map length xs))" and "i < length xs" shows "map (\ys. ys ! i) (filter (\ys. i < length ys) (transpose xs)) = xs ! i" (is "?R = _") proof (rule nth_equalityI) show length: "length ?R = length (xs ! i)" using transpose_column_length[OF assms] by simp fix j assume j: "j < length ?R" note * = less_le_trans[OF this, unfolded length_map, OF length_filter_le] from j have j_less: "j < length (xs ! i)" using length by simp have i_less_tW: "Suc i \ length (takeWhile (\ys. Suc j \ length ys) xs)" proof (rule length_takeWhile_less_P_nth) show "Suc i \ length xs" using \i < length xs\ by simp fix k assume "k < Suc i" hence "k \ i" by auto with sorted_rev_nth_mono[OF sorted this] \i < length xs\ have "length (xs ! i) \ length (xs ! k)" by simp thus "Suc j \ length (xs ! k)" using j_less by simp qed have i_less_filter: "i < length (filter (\ys. j < length ys) xs) " unfolding filter_equals_takeWhile_sorted_rev[OF sorted, of j] using i_less_tW by (simp_all add: Suc_le_eq) from j show "?R ! j = xs ! i ! j" unfolding filter_equals_takeWhile_sorted_rev[OF sorted_transpose, of i] by (simp add: takeWhile_nth nth_nth_transpose_sorted[OF sorted * i_less_filter]) qed lemma transpose_transpose: fixes xs :: "'a list list" assumes sorted: "sorted (rev (map length xs))" shows "transpose (transpose xs) = takeWhile (\x. x \ []) xs" (is "?L = ?R") proof - have len: "length ?L = length ?R" unfolding length_transpose transpose_max_length using filter_equals_takeWhile_sorted_rev[OF sorted, of 0] by simp { fix i assume "i < length ?R" with less_le_trans[OF _ length_takeWhile_le[of _ xs]] have "i < length xs" by simp } note * = this show ?thesis by (rule nth_equalityI) (simp_all add: len nth_transpose transpose_column[OF sorted] * takeWhile_nth) qed theorem transpose_rectangle: assumes "xs = [] \ n = 0" assumes rect: "\ i. i < length xs \ length (xs ! i) = n" shows "transpose xs = map (\ i. map (\ j. xs ! j ! i) [0..ys. i < length ys) xs = xs" using rect by (auto simp: in_set_conv_nth intro!: filter_True) } ultimately show "\i. i < length (transpose xs) \ ?trans ! i = ?map ! i" by (auto simp: nth_transpose intro: nth_equalityI) qed -subsubsection \\sorted_list_of_set\\ - -text\This function maps (finite) linearly ordered sets to sorted -lists. Warning: in most cases it is not a good idea to convert from -sets to lists but one should convert in the other direction (via -\<^const>\set\).\ - -context linorder +subsubsection \\sorted_key_list_of_set\\ + +text\ + This function maps (finite) linearly ordered sets to sorted lists. + The linear order is obtained by a key function that maps the elements of the set to a type + that is linearly ordered. + Warning: in most cases it is not a good idea to convert from + sets to lists but one should convert in the other direction (via \<^const>\set\). + + Note: this is a generalisation of the older \sorted_list_of_set\ that is obtained by setting + the key function to the identity. Consequently, new theorems should be added to the locale + below. They should also be aliased to more convenient names for use with \sorted_list_of_set\ + as seen further below. +\ + +definition (in linorder) sorted_key_list_of_set :: "('b \ 'a) \ 'b set \ 'b list" + where "sorted_key_list_of_set f \ folding_on.F (insort_key f) []" + +locale folding_insort_key = lo?: linorder "less_eq :: 'a \ 'a \ bool" less + for less_eq (infix "\" 50) and less (infix "\" 50) + + fixes S + fixes f :: "'b \ 'a" + assumes inj_on: "inj_on f S" begin -definition sorted_list_of_set :: "'a set \ 'a list" where - "sorted_list_of_set = folding.F insort []" - -sublocale sorted_list_of_set: folding insort Nil -rewrites - "folding.F insort [] = sorted_list_of_set" +lemma insort_key_commute: + "x \ S \ y \ S \ insort_key f y o insort_key f x = insort_key f x o insort_key f y" +proof(rule ext, goal_cases) + case (1 xs) + with inj_on show ?case by (induction xs) (auto simp: inj_onD) +qed + +sublocale fold_insort_key: folding_on S "insort_key f" "[]" + rewrites "folding_on.F (insort_key f) [] = sorted_key_list_of_set f" proof - - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) - show "folding insort" by standard (fact comp_fun_commute) - show "folding.F insort [] = sorted_list_of_set" by (simp only: sorted_list_of_set_def) -qed - -lemma sorted_list_of_set_empty: - "sorted_list_of_set {} = []" - by (fact sorted_list_of_set.empty) - -lemma sorted_list_of_set_insert [simp]: - "finite A \ sorted_list_of_set (insert x A) = insort x (sorted_list_of_set (A - {x}))" - by (fact sorted_list_of_set.insert_remove) - -lemma sorted_list_of_set_eq_Nil_iff [simp]: - "finite A \ sorted_list_of_set A = [] \ A = {}" - by (auto simp: sorted_list_of_set.remove) - -lemma set_sorted_list_of_set [simp]: - "finite A \ set (sorted_list_of_set A) = A" - by(induct A rule: finite_induct) (simp_all add: set_insort_key) - -lemma sorted_sorted_list_of_set [simp]: "sorted (sorted_list_of_set A)" + show "folding_on S (insort_key f)" + by standard (simp add: insort_key_commute) +qed (simp add: sorted_key_list_of_set_def) + +lemma idem_if_sorted_distinct: + assumes "set xs \ S" and "sorted (map f xs)" "distinct xs" + shows "sorted_key_list_of_set f (set xs) = xs" +proof(cases "S = {}") + case True + then show ?thesis using \set xs \ S\ by auto +next + case False + with assms show ?thesis + proof(induction xs) + case (Cons a xs) + with Cons show ?case by (cases xs) auto + qed simp +qed + +lemma sorted_key_list_of_set_empty: + "sorted_key_list_of_set f {} = []" + by (fact fold_insort_key.empty) + +lemma sorted_key_list_of_set_insert: + assumes "insert x A \ S" and "finite A" "x \ A" + shows "sorted_key_list_of_set f (insert x A) + = insort_key f x (sorted_key_list_of_set f A)" + using assms by (fact fold_insort_key.insert) + +lemma sorted_key_list_of_set_insert_remove [simp]: + assumes "insert x A \ S" and "finite A" + shows "sorted_key_list_of_set f (insert x A) + = insort_key f x (sorted_key_list_of_set f (A - {x}))" + using assms by (fact fold_insort_key.insert_remove) + +lemma sorted_key_list_of_set_eq_Nil_iff [simp]: + assumes "A \ S" and "finite A" + shows "sorted_key_list_of_set f A = [] \ A = {}" + using assms by (auto simp: fold_insort_key.remove) + +lemma set_sorted_key_list_of_set [simp]: + assumes "A \ S" and "finite A" + shows "set (sorted_key_list_of_set f A) = A" + using assms(2,1) + by (induct A rule: finite_induct) (simp_all add: set_insort_key) + +lemma sorted_sorted_key_list_of_set [simp]: + assumes "A \ S" + shows "sorted (map f (sorted_key_list_of_set f A))" proof (cases "finite A") - case True thus ?thesis by(induction A) (simp_all add: sorted_insort) + case True thus ?thesis using \A \ S\ + by (induction A) (simp_all add: sorted_insort_key) next case False thus ?thesis by simp qed -lemma distinct_sorted_list_of_set [simp]: "distinct (sorted_list_of_set A)" +lemma distinct_if_distinct_map: "distinct (map f xs) \ distinct xs" + using inj_on by (simp add: distinct_map) + +lemma distinct_sorted_key_list_of_set [simp]: + assumes "A \ S" + shows "distinct (map f (sorted_key_list_of_set f A))" proof (cases "finite A") - case True thus ?thesis by(induction A) (simp_all add: distinct_insort) -next + case True thus ?thesis using \A \ S\ inj_on + by (induction A) (force simp: distinct_insort_key dest: inj_onD)+ + next case False thus ?thesis by simp qed -lemma length_sorted_list_of_set [simp]: "length (sorted_list_of_set A) = card A" +lemma length_sorted_key_list_of_set [simp]: + assumes "A \ S" + shows "length (sorted_key_list_of_set f A) = card A" proof (cases "finite A") case True - then show ?thesis - by(metis distinct_card distinct_sorted_list_of_set set_sorted_list_of_set) + with assms inj_on show ?thesis + using distinct_card[symmetric, OF distinct_sorted_key_list_of_set] + by (auto simp: subset_inj_on intro!: card_image) qed auto -lemmas sorted_list_of_set = set_sorted_list_of_set sorted_sorted_list_of_set distinct_sorted_list_of_set - -lemma sorted_list_of_set_sort_remdups [code]: - "sorted_list_of_set (set xs) = sort (remdups xs)" -proof - - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) - show ?thesis by (simp add: sorted_list_of_set.eq_fold sort_conv_fold fold_set_fold_remdups) -qed - -lemma sorted_list_of_set_remove: - assumes "finite A" - shows "sorted_list_of_set (A - {x}) = remove1 x (sorted_list_of_set A)" +lemmas sorted_key_list_of_set = + set_sorted_key_list_of_set sorted_sorted_key_list_of_set distinct_sorted_key_list_of_set + +lemma sorted_key_list_of_set_remove: + assumes "insert x A \ S" and "finite A" + shows "sorted_key_list_of_set f (A - {x}) = remove1 x (sorted_key_list_of_set f A)" proof (cases "x \ A") - case False with assms have "x \ set (sorted_list_of_set A)" by simp + case False with assms have "x \ set (sorted_key_list_of_set f A)" by simp with False show ?thesis by (simp add: remove1_idem) next case True then obtain B where A: "A = insert x B" by (rule Set.set_insert) with assms show ?thesis by simp qed -lemma strict_sorted_list_of_set [simp]: "sorted_wrt (<) (sorted_list_of_set A)" - by (simp add: strict_sorted_iff) +lemma strict_sorted_key_list_of_set [simp]: + "A \ S \ sorted_wrt (\) (map f (sorted_key_list_of_set f A))" + by (cases "finite A") (auto simp: strict_sorted_iff subset_inj_on[OF inj_on]) lemma finite_set_strict_sorted: - assumes "finite A" - obtains l where "sorted_wrt (<) l" "set l = A" "length l = card A" - by (metis assms distinct_card distinct_sorted_list_of_set set_sorted_list_of_set strict_sorted_list_of_set) - -lemma strict_sorted_equal: + assumes "A \ S" and "finite A" + obtains l where "sorted_wrt (\) (map f l)" "set l = A" "length l = card A" + using assms + by (meson length_sorted_key_list_of_set set_sorted_key_list_of_set strict_sorted_key_list_of_set) + +lemma (in linorder) strict_sorted_equal: assumes "sorted_wrt (<) xs" - and "sorted_wrt (<) ys" - and "set ys = set xs" - shows "ys = xs" + and "sorted_wrt (<) ys" + and "set ys = set xs" + shows "ys = xs" using assms proof (induction xs arbitrary: ys) case (Cons x xs) show ?case proof (cases ys) case Nil then show ?thesis using Cons.prems by auto next case (Cons y ys') then have "xs = ys'" by (metis Cons.prems list.inject sorted_distinct_set_unique strict_sorted_iff) moreover have "x = y" using Cons.prems \xs = ys'\ local.Cons by fastforce ultimately show ?thesis using local.Cons by blast qed qed auto - -lemma strict_sorted_equal_Uniq: "\\<^sub>\\<^sub>1xs. sorted_wrt (<) xs \ set xs = A" + +lemma (in linorder) strict_sorted_equal_Uniq: "\\<^sub>\\<^sub>1xs. sorted_wrt (<) xs \ set xs = A" by (simp add: Uniq_def strict_sorted_equal) -lemma sorted_list_of_set_inject: - assumes "sorted_list_of_set A = sorted_list_of_set B" "finite A" "finite B" +lemma sorted_key_list_of_set_inject: + assumes "A \ S" "B \ S" + assumes "sorted_key_list_of_set f A = sorted_key_list_of_set f B" "finite A" "finite B" shows "A = B" - using assms set_sorted_list_of_set by fastforce - -lemma sorted_list_of_set_unique: - assumes "finite A" - shows "sorted_wrt (<) l \ set l = A \ length l = card A \ sorted_list_of_set A = l" - using assms strict_sorted_equal by force + using assms set_sorted_key_list_of_set by metis + +lemma sorted_key_list_of_set_unique: + assumes "A \ S" and "finite A" + shows "sorted_wrt (\) (map f l) \ set l = A \ length l = card A + \ sorted_key_list_of_set f A = l" + using assms + by (auto simp: strict_sorted_iff card_distinct idem_if_sorted_distinct) end +context linorder +begin + +definition "sorted_list_of_set \ sorted_key_list_of_set (\x::'a. x)" + +text \ + We abuse the \rewrites\ functionality of locales to remove trivial assumptions that result + from instantiating the key function to the identity. +\ +sublocale sorted_list_of_set: folding_insort_key "(\)" "(<)" UNIV "(\x. x)" + rewrites "sorted_key_list_of_set (\x. x) = sorted_list_of_set" + and "\xs. map (\x. x) xs \ xs" + and "\X. (X \ UNIV) \ True" + and "\x. x \ UNIV \ True" + and "\P. (True \ P) \ Trueprop P" + and "\P Q. (True \ PROP P \ PROP Q) \ (PROP P \ True \ PROP Q)" +proof - + show "folding_insort_key (\) (<) UNIV (\x. x)" + by standard simp +qed (simp_all add: sorted_list_of_set_def) + +text \Alias theorems for backwards compatibility and ease of use.\ +lemmas sorted_list_of_set = sorted_list_of_set.sorted_key_list_of_set and + sorted_list_of_set_empty = sorted_list_of_set.sorted_key_list_of_set_empty and + sorted_list_of_set_insert = sorted_list_of_set.sorted_key_list_of_set_insert and + sorted_list_of_set_insert_remove = sorted_list_of_set.sorted_key_list_of_set_insert_remove and + sorted_list_of_set_eq_Nil_iff = sorted_list_of_set.sorted_key_list_of_set_eq_Nil_iff and + set_sorted_list_of_set = sorted_list_of_set.set_sorted_key_list_of_set and + sorted_sorted_list_of_set = sorted_list_of_set.sorted_sorted_key_list_of_set and + distinct_sorted_list_of_set = sorted_list_of_set.distinct_sorted_key_list_of_set and + length_sorted_list_of_set = sorted_list_of_set.length_sorted_key_list_of_set and + sorted_list_of_set_remove = sorted_list_of_set.sorted_key_list_of_set_remove and + strict_sorted_list_of_set = sorted_list_of_set.strict_sorted_key_list_of_set and + sorted_list_of_set_inject = sorted_list_of_set.sorted_key_list_of_set_inject and + sorted_list_of_set_unique = sorted_list_of_set.sorted_key_list_of_set_unique and + finite_set_strict_sorted = sorted_list_of_set.finite_set_strict_sorted + +lemma sorted_list_of_set_sort_remdups [code]: + "sorted_list_of_set (set xs) = sort (remdups xs)" +proof - + interpret comp_fun_commute insort by (fact comp_fun_commute_insort) + show ?thesis + by (simp add: sorted_list_of_set.fold_insort_key.eq_fold sort_conv_fold fold_set_fold_remdups) +qed + +end + + lemma sorted_list_of_set_range [simp]: "sorted_list_of_set {m.. {}" shows "sorted_list_of_set A = Min A # sorted_list_of_set (A - {Min A})" - using assms by (auto simp: less_le simp flip: sorted_list_of_set_unique intro: Min_in) + using assms + by (auto simp: less_le simp flip: sorted_list_of_set.sorted_key_list_of_set_unique intro: Min_in) lemma sorted_list_of_set_greaterThanLessThan: assumes "Suc i < j" shows "sorted_list_of_set {i<.. j" shows "sorted_list_of_set {i<..j} = Suc i # sorted_list_of_set {Suc i<..j}" using sorted_list_of_set_greaterThanLessThan [of i "Suc j"] by (metis assms greaterThanAtMost_def greaterThanLessThan_eq le_imp_less_Suc lessThan_Suc_atMost) lemma nth_sorted_list_of_set_greaterThanLessThan: "n < j - Suc i \ sorted_list_of_set {i<.. sorted_list_of_set {i<..j} ! n = Suc (i+n)" using nth_sorted_list_of_set_greaterThanLessThan [of n "Suc j" i] by (simp add: greaterThanAtMost_def greaterThanLessThan_eq lessThan_Suc_atMost) subsubsection \\lists\: the list-forming operator over sets\ inductive_set lists :: "'a set => 'a list set" for A :: "'a set" where Nil [intro!, simp]: "[] \ lists A" | Cons [intro!, simp]: "\a \ A; l \ lists A\ \ a#l \ lists A" inductive_cases listsE [elim!]: "x#l \ lists A" inductive_cases listspE [elim!]: "listsp A (x # l)" inductive_simps listsp_simps[code]: "listsp A []" "listsp A (x # xs)" lemma listsp_mono [mono]: "A \ B \ listsp A \ listsp B" by (rule predicate1I, erule listsp.induct, blast+) lemmas lists_mono = listsp_mono [to_set] lemma listsp_infI: assumes l: "listsp A l" shows "listsp B l \ listsp (inf A B) l" using l by induct blast+ lemmas lists_IntI = listsp_infI [to_set] lemma listsp_inf_eq [simp]: "listsp (inf A B) = inf (listsp A) (listsp B)" proof (rule mono_inf [where f=listsp, THEN order_antisym]) show "mono listsp" by (simp add: mono_def listsp_mono) show "inf (listsp A) (listsp B) \ listsp (inf A B)" by (blast intro!: listsp_infI) qed lemmas listsp_conj_eq [simp] = listsp_inf_eq [simplified inf_fun_def inf_bool_def] lemmas lists_Int_eq [simp] = listsp_inf_eq [to_set] lemma Cons_in_lists_iff[simp]: "x#xs \ lists A \ x \ A \ xs \ lists A" by auto lemma append_in_listsp_conv [iff]: "(listsp A (xs @ ys)) = (listsp A xs \ listsp A ys)" by (induct xs) auto lemmas append_in_lists_conv [iff] = append_in_listsp_conv [to_set] lemma in_listsp_conv_set: "(listsp A xs) = (\x \ set xs. A x)" \ \eliminate \listsp\ in favour of \set\\ by (induct xs) auto lemmas in_lists_conv_set [code_unfold] = in_listsp_conv_set [to_set] lemma in_listspD [dest!]: "listsp A xs \ \x\set xs. A x" by (rule in_listsp_conv_set [THEN iffD1]) lemmas in_listsD [dest!] = in_listspD [to_set] lemma in_listspI [intro!]: "\x\set xs. A x \ listsp A xs" by (rule in_listsp_conv_set [THEN iffD2]) lemmas in_listsI [intro!] = in_listspI [to_set] lemma lists_eq_set: "lists A = {xs. set xs \ A}" by auto lemma lists_empty [simp]: "lists {} = {[]}" by auto lemma lists_UNIV [simp]: "lists UNIV = UNIV" by auto lemma lists_image: "lists (f`A) = map f ` lists A" proof - { fix xs have "\x\set xs. x \ f ` A \ xs \ map f ` lists A" by (induct xs) (auto simp del: list.map simp add: list.map[symmetric] intro!: imageI) } then show ?thesis by auto qed subsubsection \Inductive definition for membership\ inductive ListMem :: "'a \ 'a list \ bool" where elem: "ListMem x (x # xs)" | insert: "ListMem x xs \ ListMem x (y # xs)" lemma ListMem_iff: "(ListMem x xs) = (x \ set xs)" proof show "ListMem x xs \ x \ set xs" by (induct set: ListMem) auto show "x \ set xs \ ListMem x xs" by (induct xs) (auto intro: ListMem.intros) qed subsubsection \Lists as Cartesian products\ text\\set_Cons A Xs\: the set of lists with head drawn from \<^term>\A\ and tail drawn from \<^term>\Xs\.\ definition set_Cons :: "'a set \ 'a list set \ 'a list set" where "set_Cons A XS = {z. \x xs. z = x # xs \ x \ A \ xs \ XS}" lemma set_Cons_sing_Nil [simp]: "set_Cons A {[]} = (%x. [x])`A" by (auto simp add: set_Cons_def) text\Yields the set of lists, all of the same length as the argument and with elements drawn from the corresponding element of the argument.\ primrec listset :: "'a set list \ 'a list set" where "listset [] = {[]}" | "listset (A # As) = set_Cons A (listset As)" subsection \Relations on Lists\ subsubsection \Length Lexicographic Ordering\ text\These orderings preserve well-foundedness: shorter lists precede longer lists. These ordering are not used in dictionaries.\ primrec \ \The lexicographic ordering for lists of the specified length\ lexn :: "('a \ 'a) set \ nat \ ('a list \ 'a list) set" where "lexn r 0 = {}" | "lexn r (Suc n) = (map_prod (%(x, xs). x#xs) (%(x, xs). x#xs) ` (r <*lex*> lexn r n)) Int {(xs, ys). length xs = Suc n \ length ys = Suc n}" definition lex :: "('a \ 'a) set \ ('a list \ 'a list) set" where "lex r = (\n. lexn r n)" \ \Holds only between lists of the same length\ definition lenlex :: "('a \ 'a) set => ('a list \ 'a list) set" where "lenlex r = inv_image (less_than <*lex*> lex r) (\xs. (length xs, xs))" \ \Compares lists by their length and then lexicographically\ lemma wf_lexn: assumes "wf r" shows "wf (lexn r n)" proof (induct n) case (Suc n) have inj: "inj (\(x, xs). x # xs)" using assms by (auto simp: inj_on_def) have wf: "wf (map_prod (\(x, xs). x # xs) (\(x, xs). x # xs) ` (r <*lex*> lexn r n))" by (simp add: Suc.hyps assms wf_lex_prod wf_map_prod_image [OF _ inj]) then show ?case by (rule wf_subset) auto qed auto lemma lexn_length: "(xs, ys) \ lexn r n \ length xs = n \ length ys = n" by (induct n arbitrary: xs ys) auto lemma wf_lex [intro!]: assumes "wf r" shows "wf (lex r)" unfolding lex_def proof (rule wf_UN) show "wf (lexn r i)" for i by (simp add: assms wf_lexn) show "\i j. lexn r i \ lexn r j \ Domain (lexn r i) \ Range (lexn r j) = {}" by (metis DomainE Int_emptyI RangeE lexn_length) qed lemma lexn_conv: "lexn r n = {(xs,ys). length xs = n \ length ys = n \ (\xys x y xs' ys'. xs= xys @ x#xs' \ ys= xys @ y # ys' \ (x, y) \ r)}" proof (induction n) case (Suc n) then show ?case apply (simp add: image_Collect lex_prod_def, safe, blast) apply (rule_tac x = "ab # xys" in exI, simp) apply (case_tac xys; force) done qed auto text\By Mathias Fleury:\ proposition lexn_transI: assumes "trans r" shows "trans (lexn r n)" unfolding trans_def proof (intro allI impI) fix as bs cs assume asbs: "(as, bs) \ lexn r n" and bscs: "(bs, cs) \ lexn r n" obtain abs a b as' bs' where n: "length as = n" and "length bs = n" and as: "as = abs @ a # as'" and bs: "bs = abs @ b # bs'" and abr: "(a, b) \ r" using asbs unfolding lexn_conv by blast obtain bcs b' c' cs' bs' where n': "length cs = n" and "length bs = n" and bs': "bs = bcs @ b' # bs'" and cs: "cs = bcs @ c' # cs'" and b'c'r: "(b', c') \ r" using bscs unfolding lexn_conv by blast consider (le) "length bcs < length abs" | (eq) "length bcs = length abs" | (ge) "length bcs > length abs" by linarith thus "(as, cs) \ lexn r n" proof cases let ?k = "length bcs" case le hence "as ! ?k = bs ! ?k" unfolding as bs by (simp add: nth_append) hence "(as ! ?k, cs ! ?k) \ r" using b'c'r unfolding bs' cs by auto moreover have "length bcs < length as" using le unfolding as by simp from id_take_nth_drop[OF this] have "as = take ?k as @ as ! ?k # drop (Suc ?k) as" . moreover have "length bcs < length cs" unfolding cs by simp from id_take_nth_drop[OF this] have "cs = take ?k cs @ cs ! ?k # drop (Suc ?k) cs" . moreover have "take ?k as = take ?k cs" using le arg_cong[OF bs, of "take (length bcs)"] unfolding cs as bs' by auto ultimately show ?thesis using n n' unfolding lexn_conv by auto next let ?k = "length abs" case ge hence "bs ! ?k = cs ! ?k" unfolding bs' cs by (simp add: nth_append) hence "(as ! ?k, cs ! ?k) \ r" using abr unfolding as bs by auto moreover have "length abs < length as" using ge unfolding as by simp from id_take_nth_drop[OF this] have "as = take ?k as @ as ! ?k # drop (Suc ?k) as" . moreover have "length abs < length cs" using n n' unfolding as by simp from id_take_nth_drop[OF this] have "cs = take ?k cs @ cs ! ?k # drop (Suc ?k) cs" . moreover have "take ?k as = take ?k cs" using ge arg_cong[OF bs', of "take (length abs)"] unfolding cs as bs by auto ultimately show ?thesis using n n' unfolding lexn_conv by auto next let ?k = "length abs" case eq hence *: "abs = bcs" "b = b'" using bs bs' by auto hence "(a, c') \ r" using abr b'c'r assms unfolding trans_def by blast with * show ?thesis using n n' unfolding lexn_conv as bs cs by auto qed qed corollary lex_transI: assumes "trans r" shows "trans (lex r)" using lexn_transI [OF assms] by (clarsimp simp add: lex_def trans_def) (metis lexn_length) lemma lex_conv: "lex r = {(xs,ys). length xs = length ys \ (\xys x y xs' ys'. xs = xys @ x # xs' \ ys = xys @ y # ys' \ (x, y) \ r)}" by (force simp add: lex_def lexn_conv) lemma wf_lenlex [intro!]: "wf r \ wf (lenlex r)" by (unfold lenlex_def) blast lemma lenlex_conv: "lenlex r = {(xs,ys). length xs < length ys \ length xs = length ys \ (xs, ys) \ lex r}" by (auto simp add: lenlex_def Id_on_def lex_prod_def inv_image_def) lemma total_lenlex: assumes "total r" shows "total (lenlex r)" proof - have "(xs,ys) \ lexn r (length xs) \ (ys,xs) \ lexn r (length xs)" if "xs \ ys" and len: "length xs = length ys" for xs ys proof - obtain pre x xs' y ys' where "x\y" and xs: "xs = pre @ [x] @ xs'" and ys: "ys = pre @ [y] @ys'" by (meson len \xs \ ys\ same_length_different) then consider "(x,y) \ r" | "(y,x) \ r" by (meson UNIV_I assms total_on_def) then show ?thesis by cases (use len in \(force simp add: lexn_conv xs ys)+\) qed then show ?thesis by (fastforce simp: lenlex_def total_on_def lex_def) qed lemma lenlex_transI [intro]: "trans r \ trans (lenlex r)" unfolding lenlex_def by (meson lex_transI trans_inv_image trans_less_than trans_lex_prod) lemma Nil_notin_lex [iff]: "([], ys) \ lex r" by (simp add: lex_conv) lemma Nil2_notin_lex [iff]: "(xs, []) \ lex r" by (simp add:lex_conv) lemma Cons_in_lex [simp]: "(x # xs, y # ys) \ lex r \ (x, y) \ r \ length xs = length ys \ x = y \ (xs, ys) \ lex r" (is "?lhs = ?rhs") proof assume ?lhs then show ?rhs by (simp add: lex_conv) (metis hd_append list.sel(1) list.sel(3) tl_append2) next assume ?rhs then show ?lhs by (simp add: lex_conv) (blast intro: Cons_eq_appendI) qed lemma Nil_lenlex_iff1 [simp]: "([], ns) \ lenlex r \ ns \ []" and Nil_lenlex_iff2 [simp]: "(ns,[]) \ lenlex r" by (auto simp: lenlex_def) lemma Cons_lenlex_iff: "((m # ms, n # ns) \ lenlex r) \ length ms < length ns \ length ms = length ns \ (m,n) \ r \ (m = n \ (ms,ns) \ lenlex r)" by (auto simp: lenlex_def) lemma lenlex_irreflexive: "(\x. (x,x) \ r) \ (xs,xs) \ lenlex r" by (induction xs) (auto simp add: Cons_lenlex_iff) lemma lenlex_trans: "\(x,y) \ lenlex r; (y,z) \ lenlex r; trans r\ \ (x,z) \ lenlex r" by (meson lenlex_transI transD) lemma lenlex_length: "(ms, ns) \ lenlex r \ length ms \ length ns" by (auto simp: lenlex_def) lemma lex_append_rightI: "(xs, ys) \ lex r \ length vs = length us \ (xs @ us, ys @ vs) \ lex r" by (fastforce simp: lex_def lexn_conv) lemma lex_append_leftI: "(ys, zs) \ lex r \ (xs @ ys, xs @ zs) \ lex r" by (induct xs) auto lemma lex_append_leftD: "\x. (x,x) \ r \ (xs @ ys, xs @ zs) \ lex r \ (ys, zs) \ lex r" by (induct xs) auto lemma lex_append_left_iff: "\x. (x,x) \ r \ (xs @ ys, xs @ zs) \ lex r \ (ys, zs) \ lex r" by(metis lex_append_leftD lex_append_leftI) lemma lex_take_index: assumes "(xs, ys) \ lex r" obtains i where "i < length xs" and "i < length ys" and "take i xs = take i ys" and "(xs ! i, ys ! i) \ r" proof - obtain n us x xs' y ys' where "(xs, ys) \ lexn r n" and "length xs = n" and "length ys = n" and "xs = us @ x # xs'" and "ys = us @ y # ys'" and "(x, y) \ r" using assms by (fastforce simp: lex_def lexn_conv) then show ?thesis by (intro that [of "length us"]) auto qed lemma irrefl_lex: "irrefl r \ irrefl (lex r)" by (meson irrefl_def lex_take_index) lemma lexl_not_refl [simp]: "irrefl r \ (x,x) \ lex r" by (meson irrefl_def lex_take_index) subsubsection \Lexicographic Ordering\ text \Classical lexicographic ordering on lists, ie. "a" < "ab" < "b". This ordering does \emph{not} preserve well-foundedness. Author: N. Voelker, March 2005.\ definition lexord :: "('a \ 'a) set \ ('a list \ 'a list) set" where "lexord r = {(x,y). \ a v. y = x @ a # v \ (\ u a b v w. (a,b) \ r \ x = u @ (a # v) \ y = u @ (b # w))}" lemma lexord_Nil_left[simp]: "([],y) \ lexord r = (\ a x. y = a # x)" by (unfold lexord_def, induct_tac y, auto) lemma lexord_Nil_right[simp]: "(x,[]) \ lexord r" by (unfold lexord_def, induct_tac x, auto) lemma lexord_cons_cons[simp]: "(a # x, b # y) \ lexord r \ (a,b)\ r \ (a = b \ (x,y)\ lexord r)" (is "?lhs = ?rhs") proof assume ?lhs then show ?rhs apply (simp add: lexord_def) apply (metis hd_append list.sel(1) list.sel(3) tl_append2) done qed (auto simp add: lexord_def; (blast | meson Cons_eq_appendI)) lemmas lexord_simps = lexord_Nil_left lexord_Nil_right lexord_cons_cons lemma lexord_same_pref_iff: "(xs @ ys, xs @ zs) \ lexord r \ (\x \ set xs. (x,x) \ r) \ (ys, zs) \ lexord r" by(induction xs) auto lemma lexord_same_pref_if_irrefl[simp]: "irrefl r \ (xs @ ys, xs @ zs) \ lexord r \ (ys, zs) \ lexord r" by (simp add: irrefl_def lexord_same_pref_iff) lemma lexord_append_rightI: "\ b z. y = b # z \ (x, x @ y) \ lexord r" by (metis append_Nil2 lexord_Nil_left lexord_same_pref_iff) lemma lexord_append_left_rightI: "(a,b) \ r \ (u @ a # x, u @ b # y) \ lexord r" by (simp add: lexord_same_pref_iff) lemma lexord_append_leftI: "(u,v) \ lexord r \ (x @ u, x @ v) \ lexord r" by (simp add: lexord_same_pref_iff) lemma lexord_append_leftD: "\(x @ u, x @ v) \ lexord r; (\a. (a,a) \ r) \ \ (u,v) \ lexord r" by (simp add: lexord_same_pref_iff) lemma lexord_take_index_conv: "((x,y) \ lexord r) = ((length x < length y \ take (length x) y = x) \ (\i. i < min(length x)(length y) \ take i x = take i y \ (x!i,y!i) \ r))" proof - have "(\a v. y = x @ a # v) = (length x < length y \ take (length x) y = x)" by (metis Cons_nth_drop_Suc append_eq_conv_conj drop_all list.simps(3) not_le) moreover have "(\u a b. (a, b) \ r \ (\v. x = u @ a # v) \ (\w. y = u @ b # w)) = (\i take i x = take i y \ (x ! i, y ! i) \ r)" apply safe using less_iff_Suc_add apply auto[1] by (metis id_take_nth_drop) ultimately show ?thesis by (auto simp: lexord_def Let_def) qed \ \lexord is extension of partial ordering List.lex\ lemma lexord_lex: "(x,y) \ lex r = ((x,y) \ lexord r \ length x = length y)" proof (induction x arbitrary: y) case (Cons a x y) then show ?case by (cases y) (force+) qed auto lemma lexord_sufI: assumes "(u,w) \ lexord r" "length w \ length u" shows "(u@v,w@z) \ lexord r" proof- from leD[OF assms(2)] assms(1)[unfolded lexord_take_index_conv[of u w r] min_absorb2[OF assms(2)]] obtain i where "take i u = take i w" and "(u!i,w!i) \ r" and "i < length w" by blast hence "((u@v)!i, (w@z)!i) \ r" unfolding nth_append using less_le_trans[OF \i < length w\ assms(2)] \(u!i,w!i) \ r\ by presburger moreover have "i < min (length (u@v)) (length (w@z))" using assms(2) \i < length w\ by simp moreover have "take i (u@v) = take i (w@z)" using assms(2) \i < length w\ \take i u = take i w\ by simp ultimately show ?thesis using lexord_take_index_conv by blast qed lemma lexord_sufE: assumes "(xs@zs,ys@qs) \ lexord r" "xs \ ys" "length xs = length ys" "length zs = length qs" shows "(xs,ys) \ lexord r" proof- obtain i where "i < length (xs@zs)" and "i < length (ys@qs)" and "take i (xs@zs) = take i (ys@qs)" and "((xs@zs) ! i, (ys@qs) ! i) \ r" using assms(1) lex_take_index[unfolded lexord_lex,of "xs @ zs" "ys @ qs" r] length_append[of xs zs, unfolded assms(3,4), folded length_append[of ys qs]] by blast have "length (take i xs) = length (take i ys)" by (simp add: assms(3)) have "i < length xs" using assms(2,3) le_less_linear take_all[of xs i] take_all[of ys i] \take i (xs @ zs) = take i (ys @ qs)\ append_eq_append_conv take_append by metis hence "(xs ! i, ys ! i) \ r" using \((xs @ zs) ! i, (ys @ qs) ! i) \ r\ assms(3) by (simp add: nth_append) moreover have "take i xs = take i ys" using assms(3) \take i (xs @ zs) = take i (ys @ qs)\ by auto ultimately show ?thesis unfolding lexord_take_index_conv using \i < length xs\ assms(3) by fastforce qed lemma lexord_irreflexive: "\x. (x,x) \ r \ (xs,xs) \ lexord r" by (induct xs) auto text\By Ren\'e Thiemann:\ lemma lexord_partial_trans: "(\x y z. x \ set xs \ (x,y) \ r \ (y,z) \ r \ (x,z) \ r) \ (xs,ys) \ lexord r \ (ys,zs) \ lexord r \ (xs,zs) \ lexord r" proof (induct xs arbitrary: ys zs) case Nil from Nil(3) show ?case unfolding lexord_def by (cases zs, auto) next case (Cons x xs yys zzs) from Cons(3) obtain y ys where yys: "yys = y # ys" unfolding lexord_def by (cases yys, auto) note Cons = Cons[unfolded yys] from Cons(3) have one: "(x,y) \ r \ x = y \ (xs,ys) \ lexord r" by auto from Cons(4) obtain z zs where zzs: "zzs = z # zs" unfolding lexord_def by (cases zzs, auto) note Cons = Cons[unfolded zzs] from Cons(4) have two: "(y,z) \ r \ y = z \ (ys,zs) \ lexord r" by auto { assume "(xs,ys) \ lexord r" and "(ys,zs) \ lexord r" from Cons(1)[OF _ this] Cons(2) have "(xs,zs) \ lexord r" by auto } note ind1 = this { assume "(x,y) \ r" and "(y,z) \ r" from Cons(2)[OF _ this] have "(x,z) \ r" by auto } note ind2 = this from one two ind1 ind2 have "(x,z) \ r \ x = z \ (xs,zs) \ lexord r" by blast thus ?case unfolding zzs by auto qed lemma lexord_trans: "\ (x, y) \ lexord r; (y, z) \ lexord r; trans r \ \ (x, z) \ lexord r" by(auto simp: trans_def intro:lexord_partial_trans) lemma lexord_transI: "trans r \ trans (lexord r)" by (meson lexord_trans transI) lemma total_lexord: "total r \ total (lexord r)" unfolding total_on_def proof clarsimp fix x y assume "\x y. x \ y \ (x, y) \ r \ (y, x) \ r" and "(x::'a list) \ y" and "(y, x) \ lexord r" then show "(x, y) \ lexord r" proof (induction x arbitrary: y) case Nil then show ?case by (metis lexord_Nil_left list.exhaust) next case (Cons a x y) then show ?case by (cases y) (force+) qed qed corollary lexord_linear: "(\a b. (a,b) \ r \ a = b \ (b,a) \ r) \ (x,y) \ lexord r \ x = y \ (y,x) \ lexord r" using total_lexord by (metis UNIV_I total_on_def) lemma lexord_irrefl: "irrefl R \ irrefl (lexord R)" by (simp add: irrefl_def lexord_irreflexive) lemma lexord_asym: assumes "asym R" shows "asym (lexord R)" proof fix xs ys assume "(xs, ys) \ lexord R" then show "(ys, xs) \ lexord R" proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case (Cons x xs) then obtain z zs where ys: "ys = z # zs" by (cases ys) auto with assms Cons show ?case by (auto elim: asym.cases) qed qed lemma lexord_asymmetric: assumes "asym R" assumes hyp: "(a, b) \ lexord R" shows "(b, a) \ lexord R" proof - from \asym R\ have "asym (lexord R)" by (rule lexord_asym) then show ?thesis by (rule asym.cases) (auto simp add: hyp) qed lemma asym_lex: "asym R \ asym (lex R)" by (meson asym.simps irrefl_lex lexord_asym lexord_lex) lemma asym_lenlex: "asym R \ asym (lenlex R)" by (simp add: lenlex_def asym_inv_image asym_less_than asym_lex asym_lex_prod) lemma lenlex_append1: assumes len: "(us,xs) \ lenlex R" and eq: "length vs = length ys" shows "(us @ vs, xs @ ys) \ lenlex R" using len proof (induction us) case Nil then show ?case by (simp add: lenlex_def eq) next case (Cons u us) with lex_append_rightI show ?case by (fastforce simp add: lenlex_def eq) qed lemma lenlex_append2 [simp]: assumes "irrefl R" shows "(us @ xs, us @ ys) \ lenlex R \ (xs, ys) \ lenlex R" proof (induction us) case Nil then show ?case by (simp add: lenlex_def) next case (Cons u us) with assms show ?case by (auto simp: lenlex_def irrefl_def) qed text \ Predicate version of lexicographic order integrated with Isabelle's order type classes. Author: Andreas Lochbihler \ context ord begin context notes [[inductive_internals]] begin inductive lexordp :: "'a list \ 'a list \ bool" where Nil: "lexordp [] (y # ys)" | Cons: "x < y \ lexordp (x # xs) (y # ys)" | Cons_eq: "\ \ x < y; \ y < x; lexordp xs ys \ \ lexordp (x # xs) (y # ys)" end lemma lexordp_simps [simp]: "lexordp [] ys = (ys \ [])" "lexordp xs [] = False" "lexordp (x # xs) (y # ys) \ x < y \ \ y < x \ lexordp xs ys" by(subst lexordp.simps, fastforce simp add: neq_Nil_conv)+ inductive lexordp_eq :: "'a list \ 'a list \ bool" where Nil: "lexordp_eq [] ys" | Cons: "x < y \ lexordp_eq (x # xs) (y # ys)" | Cons_eq: "\ \ x < y; \ y < x; lexordp_eq xs ys \ \ lexordp_eq (x # xs) (y # ys)" lemma lexordp_eq_simps [simp]: "lexordp_eq [] ys = True" "lexordp_eq xs [] \ xs = []" "lexordp_eq (x # xs) [] = False" "lexordp_eq (x # xs) (y # ys) \ x < y \ \ y < x \ lexordp_eq xs ys" by(subst lexordp_eq.simps, fastforce)+ lemma lexordp_append_rightI: "ys \ Nil \ lexordp xs (xs @ ys)" by(induct xs)(auto simp add: neq_Nil_conv) lemma lexordp_append_left_rightI: "x < y \ lexordp (us @ x # xs) (us @ y # ys)" by(induct us) auto lemma lexordp_eq_refl: "lexordp_eq xs xs" by(induct xs) simp_all lemma lexordp_append_leftI: "lexordp us vs \ lexordp (xs @ us) (xs @ vs)" by(induct xs) auto lemma lexordp_append_leftD: "\ lexordp (xs @ us) (xs @ vs); \a. \ a < a \ \ lexordp us vs" by(induct xs) auto lemma lexordp_irreflexive: assumes irrefl: "\x. \ x < x" shows "\ lexordp xs xs" proof assume "lexordp xs xs" thus False by(induct xs ys\xs)(simp_all add: irrefl) qed lemma lexordp_into_lexordp_eq: "lexordp xs ys \ lexordp_eq xs ys" by (induction rule: lexordp.induct) simp_all lemma lexordp_eq_pref: "lexordp_eq u (u @ v)" by (metis append_Nil2 lexordp_append_rightI lexordp_eq_refl lexordp_into_lexordp_eq) end declare ord.lexordp_simps [simp, code] declare ord.lexordp_eq_simps [code, simp] context order begin lemma lexordp_antisym: assumes "lexordp xs ys" "lexordp ys xs" shows False using assms by induct auto lemma lexordp_irreflexive': "\ lexordp xs xs" by(rule lexordp_irreflexive) simp end context linorder begin lemma lexordp_cases [consumes 1, case_names Nil Cons Cons_eq, cases pred: lexordp]: assumes "lexordp xs ys" obtains (Nil) y ys' where "xs = []" "ys = y # ys'" | (Cons) x xs' y ys' where "xs = x # xs'" "ys = y # ys'" "x < y" | (Cons_eq) x xs' ys' where "xs = x # xs'" "ys = x # ys'" "lexordp xs' ys'" using assms by cases (fastforce simp add: not_less_iff_gr_or_eq)+ lemma lexordp_induct [consumes 1, case_names Nil Cons Cons_eq, induct pred: lexordp]: assumes major: "lexordp xs ys" and Nil: "\y ys. P [] (y # ys)" and Cons: "\x xs y ys. x < y \ P (x # xs) (y # ys)" and Cons_eq: "\x xs ys. \ lexordp xs ys; P xs ys \ \ P (x # xs) (x # ys)" shows "P xs ys" using major by induct (simp_all add: Nil Cons not_less_iff_gr_or_eq Cons_eq) lemma lexordp_iff: "lexordp xs ys \ (\x vs. ys = xs @ x # vs) \ (\us a b vs ws. a < b \ xs = us @ a # vs \ ys = us @ b # ws)" (is "?lhs = ?rhs") proof assume ?lhs thus ?rhs proof induct case Cons_eq thus ?case by simp (metis append.simps(2)) qed(fastforce intro: disjI2 del: disjCI intro: exI[where x="[]"])+ next assume ?rhs thus ?lhs by(auto intro: lexordp_append_leftI[where us="[]", simplified] lexordp_append_leftI) qed lemma lexordp_conv_lexord: "lexordp xs ys \ (xs, ys) \ lexord {(x, y). x < y}" by(simp add: lexordp_iff lexord_def) lemma lexordp_eq_antisym: assumes "lexordp_eq xs ys" "lexordp_eq ys xs" shows "xs = ys" using assms by induct simp_all lemma lexordp_eq_trans: assumes "lexordp_eq xs ys" and "lexordp_eq ys zs" shows "lexordp_eq xs zs" using assms by (induct arbitrary: zs) (case_tac zs; auto)+ lemma lexordp_trans: assumes "lexordp xs ys" "lexordp ys zs" shows "lexordp xs zs" using assms by (induct arbitrary: zs) (case_tac zs; auto)+ lemma lexordp_linear: "lexordp xs ys \ xs = ys \ lexordp ys xs" by(induct xs arbitrary: ys; case_tac ys; fastforce) lemma lexordp_conv_lexordp_eq: "lexordp xs ys \ lexordp_eq xs ys \ \ lexordp_eq ys xs" (is "?lhs \ ?rhs") proof assume ?lhs hence "\ lexordp_eq ys xs" by induct simp_all with \?lhs\ show ?rhs by (simp add: lexordp_into_lexordp_eq) next assume ?rhs hence "lexordp_eq xs ys" "\ lexordp_eq ys xs" by simp_all thus ?lhs by induct simp_all qed lemma lexordp_eq_conv_lexord: "lexordp_eq xs ys \ xs = ys \ lexordp xs ys" by(auto simp add: lexordp_conv_lexordp_eq lexordp_eq_refl dest: lexordp_eq_antisym) lemma lexordp_eq_linear: "lexordp_eq xs ys \ lexordp_eq ys xs" by (induct xs arbitrary: ys) (case_tac ys; auto)+ lemma lexordp_linorder: "class.linorder lexordp_eq lexordp" by unfold_locales (auto simp add: lexordp_conv_lexordp_eq lexordp_eq_refl lexordp_eq_antisym intro: lexordp_eq_trans del: disjCI intro: lexordp_eq_linear) end lemma sorted_insort_is_snoc: "sorted xs \ \x \ set xs. a \ x \ insort a xs = xs @ [a]" by (induct xs) (auto dest!: insort_is_Cons) subsubsection \Lexicographic combination of measure functions\ text \These are useful for termination proofs\ definition "measures fs = inv_image (lex less_than) (%a. map (%f. f a) fs)" lemma wf_measures[simp]: "wf (measures fs)" unfolding measures_def by blast lemma in_measures[simp]: "(x, y) \ measures [] = False" "(x, y) \ measures (f # fs) = (f x < f y \ (f x = f y \ (x, y) \ measures fs))" unfolding measures_def by auto lemma measures_less: "f x < f y \ (x, y) \ measures (f#fs)" by simp lemma measures_lesseq: "f x \ f y \ (x, y) \ measures fs \ (x, y) \ measures (f#fs)" by auto subsubsection \Lifting Relations to Lists: one element\ definition listrel1 :: "('a \ 'a) set \ ('a list \ 'a list) set" where "listrel1 r = {(xs,ys). \us z z' vs. xs = us @ z # vs \ (z,z') \ r \ ys = us @ z' # vs}" lemma listrel1I: "\ (x, y) \ r; xs = us @ x # vs; ys = us @ y # vs \ \ (xs, ys) \ listrel1 r" unfolding listrel1_def by auto lemma listrel1E: "\ (xs, ys) \ listrel1 r; !!x y us vs. \ (x, y) \ r; xs = us @ x # vs; ys = us @ y # vs \ \ P \ \ P" unfolding listrel1_def by auto lemma not_Nil_listrel1 [iff]: "([], xs) \ listrel1 r" unfolding listrel1_def by blast lemma not_listrel1_Nil [iff]: "(xs, []) \ listrel1 r" unfolding listrel1_def by blast lemma Cons_listrel1_Cons [iff]: "(x # xs, y # ys) \ listrel1 r \ (x,y) \ r \ xs = ys \ x = y \ (xs, ys) \ listrel1 r" by (simp add: listrel1_def Cons_eq_append_conv) (blast) lemma listrel1I1: "(x,y) \ r \ (x # xs, y # xs) \ listrel1 r" by fast lemma listrel1I2: "(xs, ys) \ listrel1 r \ (x # xs, x # ys) \ listrel1 r" by fast lemma append_listrel1I: "(xs, ys) \ listrel1 r \ us = vs \ xs = ys \ (us, vs) \ listrel1 r \ (xs @ us, ys @ vs) \ listrel1 r" unfolding listrel1_def by auto (blast intro: append_eq_appendI)+ lemma Cons_listrel1E1[elim!]: assumes "(x # xs, ys) \ listrel1 r" and "\y. ys = y # xs \ (x, y) \ r \ R" and "\zs. ys = x # zs \ (xs, zs) \ listrel1 r \ R" shows R using assms by (cases ys) blast+ lemma Cons_listrel1E2[elim!]: assumes "(xs, y # ys) \ listrel1 r" and "\x. xs = x # ys \ (x, y) \ r \ R" and "\zs. xs = y # zs \ (zs, ys) \ listrel1 r \ R" shows R using assms by (cases xs) blast+ lemma snoc_listrel1_snoc_iff: "(xs @ [x], ys @ [y]) \ listrel1 r \ (xs, ys) \ listrel1 r \ x = y \ xs = ys \ (x,y) \ r" (is "?L \ ?R") proof assume ?L thus ?R by (fastforce simp: listrel1_def snoc_eq_iff_butlast butlast_append) next assume ?R then show ?L unfolding listrel1_def by force qed lemma listrel1_eq_len: "(xs,ys) \ listrel1 r \ length xs = length ys" unfolding listrel1_def by auto lemma listrel1_mono: "r \ s \ listrel1 r \ listrel1 s" unfolding listrel1_def by blast lemma listrel1_converse: "listrel1 (r\) = (listrel1 r)\" unfolding listrel1_def by blast lemma in_listrel1_converse: "(x,y) \ listrel1 (r\) \ (x,y) \ (listrel1 r)\" unfolding listrel1_def by blast lemma listrel1_iff_update: "(xs,ys) \ (listrel1 r) \ (\y n. (xs ! n, y) \ r \ n < length xs \ ys = xs[n:=y])" (is "?L \ ?R") proof assume "?L" then obtain x y u v where "xs = u @ x # v" "ys = u @ y # v" "(x,y) \ r" unfolding listrel1_def by auto then have "ys = xs[length u := y]" and "length u < length xs" and "(xs ! length u, y) \ r" by auto then show "?R" by auto next assume "?R" then obtain x y n where "(xs!n, y) \ r" "n < size xs" "ys = xs[n:=y]" "x = xs!n" by auto then obtain u v where "xs = u @ x # v" and "ys = u @ y # v" and "(x, y) \ r" by (auto intro: upd_conv_take_nth_drop id_take_nth_drop) then show "?L" by (auto simp: listrel1_def) qed text\Accessible part and wellfoundedness:\ lemma Cons_acc_listrel1I [intro!]: "x \ Wellfounded.acc r \ xs \ Wellfounded.acc (listrel1 r) \ (x # xs) \ Wellfounded.acc (listrel1 r)" apply (induct arbitrary: xs set: Wellfounded.acc) apply (erule thin_rl) apply (erule acc_induct) apply (rule accI) apply (blast) done lemma lists_accD: "xs \ lists (Wellfounded.acc r) \ xs \ Wellfounded.acc (listrel1 r)" proof (induct set: lists) case Nil then show ?case by (meson acc.intros not_listrel1_Nil) next case (Cons a l) then show ?case by blast qed lemma lists_accI: "xs \ Wellfounded.acc (listrel1 r) \ xs \ lists (Wellfounded.acc r)" apply (induct set: Wellfounded.acc) apply clarify apply (rule accI) apply (fastforce dest!: in_set_conv_decomp[THEN iffD1] simp: listrel1_def) done lemma wf_listrel1_iff[simp]: "wf(listrel1 r) = wf r" by (auto simp: wf_acc_iff intro: lists_accD lists_accI[THEN Cons_in_lists_iff[THEN iffD1, THEN conjunct1]]) subsubsection \Lifting Relations to Lists: all elements\ inductive_set listrel :: "('a \ 'b) set \ ('a list \ 'b list) set" for r :: "('a \ 'b) set" where Nil: "([],[]) \ listrel r" | Cons: "\(x,y) \ r; (xs,ys) \ listrel r\ \ (x#xs, y#ys) \ listrel r" inductive_cases listrel_Nil1 [elim!]: "([],xs) \ listrel r" inductive_cases listrel_Nil2 [elim!]: "(xs,[]) \ listrel r" inductive_cases listrel_Cons1 [elim!]: "(y#ys,xs) \ listrel r" inductive_cases listrel_Cons2 [elim!]: "(xs,y#ys) \ listrel r" lemma listrel_eq_len: "(xs, ys) \ listrel r \ length xs = length ys" by(induct rule: listrel.induct) auto lemma listrel_iff_zip [code_unfold]: "(xs,ys) \ listrel r \ length xs = length ys \ (\(x,y) \ set(zip xs ys). (x,y) \ r)" (is "?L \ ?R") proof assume ?L thus ?R by induct (auto intro: listrel_eq_len) next assume ?R thus ?L apply (clarify) by (induct rule: list_induct2) (auto intro: listrel.intros) qed lemma listrel_iff_nth: "(xs,ys) \ listrel r \ length xs = length ys \ (\n < length xs. (xs!n, ys!n) \ r)" (is "?L \ ?R") by (auto simp add: all_set_conv_all_nth listrel_iff_zip) lemma listrel_mono: "r \ s \ listrel r \ listrel s" by (meson listrel_iff_nth subrelI subset_eq) lemma listrel_subset: assumes "r \ A \ A" shows "listrel r \ lists A \ lists A" proof clarify show "a \ lists A \ b \ lists A" if "(a, b) \ listrel r" for a b using that assms by (induction rule: listrel.induct, auto) qed lemma listrel_refl_on: assumes "refl_on A r" shows "refl_on (lists A) (listrel r)" proof - have "l \ lists A \ (l, l) \ listrel r" for l using assms unfolding refl_on_def by (induction l, auto intro: listrel.intros) then show ?thesis by (meson assms listrel_subset refl_on_def) qed lemma listrel_sym: "sym r \ sym (listrel r)" by (simp add: listrel_iff_nth sym_def) lemma listrel_trans: assumes "trans r" shows "trans (listrel r)" proof - have "(x, z) \ listrel r" if "(x, y) \ listrel r" "(y, z) \ listrel r" for x y z using that proof induction case (Cons x y xs ys) then show ?case by clarsimp (metis assms listrel.Cons listrel_iff_nth transD) qed auto then show ?thesis using transI by blast qed theorem equiv_listrel: "equiv A r \ equiv (lists A) (listrel r)" by (simp add: equiv_def listrel_refl_on listrel_sym listrel_trans) lemma listrel_rtrancl_refl[iff]: "(xs,xs) \ listrel(r\<^sup>*)" using listrel_refl_on[of UNIV, OF refl_rtrancl] by(auto simp: refl_on_def) lemma listrel_rtrancl_trans: "\(xs,ys) \ listrel(r\<^sup>*); (ys,zs) \ listrel(r\<^sup>*)\ \ (xs,zs) \ listrel(r\<^sup>*)" by (metis listrel_trans trans_def trans_rtrancl) lemma listrel_Nil [simp]: "listrel r `` {[]} = {[]}" by (blast intro: listrel.intros) lemma listrel_Cons: "listrel r `` {x#xs} = set_Cons (r``{x}) (listrel r `` {xs})" by (auto simp add: set_Cons_def intro: listrel.intros) text \Relating \<^term>\listrel1\, \<^term>\listrel\ and closures:\ lemma listrel1_rtrancl_subset_rtrancl_listrel1: "listrel1 (r\<^sup>*) \ (listrel1 r)\<^sup>*" proof (rule subrelI) fix xs ys assume 1: "(xs,ys) \ listrel1 (r\<^sup>*)" { fix x y us vs have "(x,y) \ r\<^sup>* \ (us @ x # vs, us @ y # vs) \ (listrel1 r)\<^sup>*" proof(induct rule: rtrancl.induct) case rtrancl_refl show ?case by simp next case rtrancl_into_rtrancl thus ?case by (metis listrel1I rtrancl.rtrancl_into_rtrancl) qed } thus "(xs,ys) \ (listrel1 r)\<^sup>*" using 1 by(blast elim: listrel1E) qed lemma rtrancl_listrel1_eq_len: "(x,y) \ (listrel1 r)\<^sup>* \ length x = length y" by (induct rule: rtrancl.induct) (auto intro: listrel1_eq_len) lemma rtrancl_listrel1_ConsI1: "(xs,ys) \ (listrel1 r)\<^sup>* \ (x#xs,x#ys) \ (listrel1 r)\<^sup>*" proof (induction rule: rtrancl.induct) case (rtrancl_into_rtrancl a b c) then show ?case by (metis listrel1I2 rtrancl.rtrancl_into_rtrancl) qed auto lemma rtrancl_listrel1_ConsI2: "(x,y) \ r\<^sup>* \ (xs, ys) \ (listrel1 r)\<^sup>* \ (x # xs, y # ys) \ (listrel1 r)\<^sup>*" by (meson in_mono listrel1I1 listrel1_rtrancl_subset_rtrancl_listrel1 rtrancl_listrel1_ConsI1 rtrancl_trans) lemma listrel1_subset_listrel: "r \ r' \ refl r' \ listrel1 r \ listrel(r')" by(auto elim!: listrel1E simp add: listrel_iff_zip set_zip refl_on_def) lemma listrel_reflcl_if_listrel1: "(xs,ys) \ listrel1 r \ (xs,ys) \ listrel(r\<^sup>*)" by(erule listrel1E)(auto simp add: listrel_iff_zip set_zip) lemma listrel_rtrancl_eq_rtrancl_listrel1: "listrel (r\<^sup>*) = (listrel1 r)\<^sup>*" proof { fix x y assume "(x,y) \ listrel (r\<^sup>*)" then have "(x,y) \ (listrel1 r)\<^sup>*" by induct (auto intro: rtrancl_listrel1_ConsI2) } then show "listrel (r\<^sup>*) \ (listrel1 r)\<^sup>*" by (rule subrelI) next show "listrel (r\<^sup>*) \ (listrel1 r)\<^sup>*" proof(rule subrelI) fix xs ys assume "(xs,ys) \ (listrel1 r)\<^sup>*" then show "(xs,ys) \ listrel (r\<^sup>*)" proof induct case base show ?case by(auto simp add: listrel_iff_zip set_zip) next case (step ys zs) thus ?case by (metis listrel_reflcl_if_listrel1 listrel_rtrancl_trans) qed qed qed lemma rtrancl_listrel1_if_listrel: "(xs,ys) \ listrel r \ (xs,ys) \ (listrel1 r)\<^sup>*" by(metis listrel_rtrancl_eq_rtrancl_listrel1 subsetD[OF listrel_mono] r_into_rtrancl subsetI) lemma listrel_subset_rtrancl_listrel1: "listrel r \ (listrel1 r)\<^sup>*" by(fast intro:rtrancl_listrel1_if_listrel) subsection \Size function\ lemma [measure_function]: "is_measure f \ is_measure (size_list f)" by (rule is_measure_trivial) lemma [measure_function]: "is_measure f \ is_measure (size_option f)" by (rule is_measure_trivial) lemma size_list_estimation[termination_simp]: "x \ set xs \ y < f x \ y < size_list f xs" by (induct xs) auto lemma size_list_estimation'[termination_simp]: "x \ set xs \ y \ f x \ y \ size_list f xs" by (induct xs) auto lemma size_list_map[simp]: "size_list f (map g xs) = size_list (f \ g) xs" by (induct xs) auto lemma size_list_append[simp]: "size_list f (xs @ ys) = size_list f xs + size_list f ys" by (induct xs, auto) lemma size_list_pointwise[termination_simp]: "(\x. x \ set xs \ f x \ g x) \ size_list f xs \ size_list g xs" by (induct xs) force+ subsection \Monad operation\ definition bind :: "'a list \ ('a \ 'b list) \ 'b list" where "bind xs f = concat (map f xs)" hide_const (open) bind lemma bind_simps [simp]: "List.bind [] f = []" "List.bind (x # xs) f = f x @ List.bind xs f" by (simp_all add: bind_def) lemma list_bind_cong [fundef_cong]: assumes "xs = ys" "(\x. x \ set xs \ f x = g x)" shows "List.bind xs f = List.bind ys g" proof - from assms(2) have "List.bind xs f = List.bind xs g" by (induction xs) simp_all with assms(1) show ?thesis by simp qed lemma set_list_bind: "set (List.bind xs f) = (\x\set xs. set (f x))" by (induction xs) simp_all subsection \Code generation\ text\Optional tail recursive version of \<^const>\map\. Can avoid stack overflow in some target languages.\ fun map_tailrec_rev :: "('a \ 'b) \ 'a list \ 'b list \ 'b list" where "map_tailrec_rev f [] bs = bs" | "map_tailrec_rev f (a#as) bs = map_tailrec_rev f as (f a # bs)" lemma map_tailrec_rev: "map_tailrec_rev f as bs = rev(map f as) @ bs" by(induction as arbitrary: bs) simp_all definition map_tailrec :: "('a \ 'b) \ 'a list \ 'b list" where "map_tailrec f as = rev (map_tailrec_rev f as [])" text\Code equation:\ lemma map_eq_map_tailrec: "map = map_tailrec" by(simp add: fun_eq_iff map_tailrec_def map_tailrec_rev) subsubsection \Counterparts for set-related operations\ definition member :: "'a list \ 'a \ bool" where [code_abbrev]: "member xs x \ x \ set xs" text \ Use \member\ only for generating executable code. Otherwise use \<^prop>\x \ set xs\ instead --- it is much easier to reason about. \ lemma member_rec [code]: "member (x # xs) y \ x = y \ member xs y" "member [] y \ False" by (auto simp add: member_def) lemma in_set_member (* FIXME delete candidate *): "x \ set xs \ member xs x" by (simp add: member_def) lemmas list_all_iff [code_abbrev] = fun_cong[OF list.pred_set] definition list_ex :: "('a \ bool) \ 'a list \ bool" where list_ex_iff [code_abbrev]: "list_ex P xs \ Bex (set xs) P" definition list_ex1 :: "('a \ bool) \ 'a list \ bool" where list_ex1_iff [code_abbrev]: "list_ex1 P xs \ (\! x. x \ set xs \ P x)" text \ Usually you should prefer \\x\set xs\, \\x\set xs\ and \\!x. x\set xs \ _\ over \<^const>\list_all\, \<^const>\list_ex\ and \<^const>\list_ex1\ in specifications. \ lemma list_all_simps [code]: "list_all P (x # xs) \ P x \ list_all P xs" "list_all P [] \ True" by (simp_all add: list_all_iff) lemma list_ex_simps [simp, code]: "list_ex P (x # xs) \ P x \ list_ex P xs" "list_ex P [] \ False" by (simp_all add: list_ex_iff) lemma list_ex1_simps [simp, code]: "list_ex1 P [] = False" "list_ex1 P (x # xs) = (if P x then list_all (\y. \ P y \ x = y) xs else list_ex1 P xs)" by (auto simp add: list_ex1_iff list_all_iff) lemma Ball_set_list_all: (* FIXME delete candidate *) "Ball (set xs) P \ list_all P xs" by (simp add: list_all_iff) lemma Bex_set_list_ex: (* FIXME delete candidate *) "Bex (set xs) P \ list_ex P xs" by (simp add: list_ex_iff) lemma list_all_append [simp]: "list_all P (xs @ ys) \ list_all P xs \ list_all P ys" by (auto simp add: list_all_iff) lemma list_ex_append [simp]: "list_ex P (xs @ ys) \ list_ex P xs \ list_ex P ys" by (auto simp add: list_ex_iff) lemma list_all_rev [simp]: "list_all P (rev xs) \ list_all P xs" by (simp add: list_all_iff) lemma list_ex_rev [simp]: "list_ex P (rev xs) \ list_ex P xs" by (simp add: list_ex_iff) lemma list_all_length: "list_all P xs \ (\n < length xs. P (xs ! n))" by (auto simp add: list_all_iff set_conv_nth) lemma list_ex_length: "list_ex P xs \ (\n < length xs. P (xs ! n))" by (auto simp add: list_ex_iff set_conv_nth) lemmas list_all_cong [fundef_cong] = list.pred_cong lemma list_ex_cong [fundef_cong]: "xs = ys \ (\x. x \ set ys \ f x = g x) \ list_ex f xs = list_ex g ys" by (simp add: list_ex_iff) definition can_select :: "('a \ bool) \ 'a set \ bool" where [code_abbrev]: "can_select P A = (\!x\A. P x)" lemma can_select_set_list_ex1 [code]: "can_select P (set A) = list_ex1 P A" by (simp add: list_ex1_iff can_select_def) text \Executable checks for relations on sets\ definition listrel1p :: "('a \ 'a \ bool) \ 'a list \ 'a list \ bool" where "listrel1p r xs ys = ((xs, ys) \ listrel1 {(x, y). r x y})" lemma [code_unfold]: "(xs, ys) \ listrel1 r = listrel1p (\x y. (x, y) \ r) xs ys" unfolding listrel1p_def by auto lemma [code]: "listrel1p r [] xs = False" "listrel1p r xs [] = False" "listrel1p r (x # xs) (y # ys) \ r x y \ xs = ys \ x = y \ listrel1p r xs ys" by (simp add: listrel1p_def)+ definition lexordp :: "('a \ 'a \ bool) \ 'a list \ 'a list \ bool" where "lexordp r xs ys = ((xs, ys) \ lexord {(x, y). r x y})" lemma [code_unfold]: "(xs, ys) \ lexord r = lexordp (\x y. (x, y) \ r) xs ys" unfolding lexordp_def by auto lemma [code]: "lexordp r xs [] = False" "lexordp r [] (y#ys) = True" "lexordp r (x # xs) (y # ys) = (r x y \ (x = y \ lexordp r xs ys))" unfolding lexordp_def by auto text \Bounded quantification and summation over nats.\ lemma atMost_upto [code_unfold]: "{..n} = set [0..m (\m \ {0..m (\m \ {0..m\n::nat. P m) \ (\m \ {0..n}. P m)" by auto lemma ex_nat_less [code_unfold]: "(\m\n::nat. P m) \ (\m \ {0..n}. P m)" by auto text\Bounded \LEAST\ operator:\ definition "Bleast S P = (LEAST x. x \ S \ P x)" definition "abort_Bleast S P = (LEAST x. x \ S \ P x)" declare [[code abort: abort_Bleast]] lemma Bleast_code [code]: "Bleast (set xs) P = (case filter P (sort xs) of x#xs \ x | [] \ abort_Bleast (set xs) P)" proof (cases "filter P (sort xs)") case Nil thus ?thesis by (simp add: Bleast_def abort_Bleast_def) next case (Cons x ys) have "(LEAST x. x \ set xs \ P x) = x" proof (rule Least_equality) show "x \ set xs \ P x" by (metis Cons Cons_eq_filter_iff in_set_conv_decomp set_sort) next fix y assume "y \ set xs \ P y" hence "y \ set (filter P xs)" by auto thus "x \ y" by (metis Cons eq_iff filter_sort set_ConsD set_sort sorted_wrt.simps(2) sorted_sort) qed thus ?thesis using Cons by (simp add: Bleast_def) qed declare Bleast_def[symmetric, code_unfold] text \Summation over ints.\ lemma greaterThanLessThan_upto [code_unfold]: "{i<..Optimizing by rewriting\ definition null :: "'a list \ bool" where [code_abbrev]: "null xs \ xs = []" text \ Efficient emptyness check is implemented by \<^const>\null\. \ lemma null_rec [code]: "null (x # xs) \ False" "null [] \ True" by (simp_all add: null_def) lemma eq_Nil_null: (* FIXME delete candidate *) "xs = [] \ null xs" by (simp add: null_def) lemma equal_Nil_null [code_unfold]: "HOL.equal xs [] \ null xs" "HOL.equal [] = null" by (auto simp add: equal null_def) definition maps :: "('a \ 'b list) \ 'a list \ 'b list" where [code_abbrev]: "maps f xs = concat (map f xs)" definition map_filter :: "('a \ 'b option) \ 'a list \ 'b list" where [code_post]: "map_filter f xs = map (the \ f) (filter (\x. f x \ None) xs)" text \ Operations \<^const>\maps\ and \<^const>\map_filter\ avoid intermediate lists on execution -- do not use for proving. \ lemma maps_simps [code]: "maps f (x # xs) = f x @ maps f xs" "maps f [] = []" by (simp_all add: maps_def) lemma map_filter_simps [code]: "map_filter f (x # xs) = (case f x of None \ map_filter f xs | Some y \ y # map_filter f xs)" "map_filter f [] = []" by (simp_all add: map_filter_def split: option.split) lemma concat_map_maps: (* FIXME delete candidate *) "concat (map f xs) = maps f xs" by (simp add: maps_def) lemma map_filter_map_filter [code_unfold]: "map f (filter P xs) = map_filter (\x. if P x then Some (f x) else None) xs" by (simp add: map_filter_def) text \Optimized code for \\i\{a..b::int}\ and \\n:{a.. and similiarly for \\\.\ definition all_interval_nat :: "(nat \ bool) \ nat \ nat \ bool" where "all_interval_nat P i j \ (\n \ {i.. i \ j \ P i \ all_interval_nat P (Suc i) j" proof - have *: "\n. P i \ \n\{Suc i.. i \ n \ n < j \ P n" proof - fix n assume "P i" "\n\{Suc i.. n" "n < j" then show "P n" by (cases "n = i") simp_all qed show ?thesis by (auto simp add: all_interval_nat_def intro: *) qed lemma list_all_iff_all_interval_nat [code_unfold]: "list_all P [i.. all_interval_nat P i j" by (simp add: list_all_iff all_interval_nat_def) lemma list_ex_iff_not_all_inverval_nat [code_unfold]: "list_ex P [i.. \ (all_interval_nat (Not \ P) i j)" by (simp add: list_ex_iff all_interval_nat_def) definition all_interval_int :: "(int \ bool) \ int \ int \ bool" where "all_interval_int P i j \ (\k \ {i..j}. P k)" lemma [code]: "all_interval_int P i j \ i > j \ P i \ all_interval_int P (i + 1) j" proof - have *: "\k. P i \ \k\{i+1..j}. P k \ i \ k \ k \ j \ P k" proof - fix k assume "P i" "\k\{i+1..j}. P k" "i \ k" "k \ j" then show "P k" by (cases "k = i") simp_all qed show ?thesis by (auto simp add: all_interval_int_def intro: *) qed lemma list_all_iff_all_interval_int [code_unfold]: "list_all P [i..j] \ all_interval_int P i j" by (simp add: list_all_iff all_interval_int_def) lemma list_ex_iff_not_all_inverval_int [code_unfold]: "list_ex P [i..j] \ \ (all_interval_int (Not \ P) i j)" by (simp add: list_ex_iff all_interval_int_def) text \optimized code (tail-recursive) for \<^term>\length\\ definition gen_length :: "nat \ 'a list \ nat" where "gen_length n xs = n + length xs" lemma gen_length_code [code]: "gen_length n [] = n" "gen_length n (x # xs) = gen_length (Suc n) xs" by(simp_all add: gen_length_def) declare list.size(3-4)[code del] lemma length_code [code]: "length = gen_length 0" by(simp add: gen_length_def fun_eq_iff) hide_const (open) member null maps map_filter all_interval_nat all_interval_int gen_length subsubsection \Pretty lists\ ML \ (* Code generation for list literals. *) signature LIST_CODE = sig val add_literal_list: string -> theory -> theory end; structure List_Code : LIST_CODE = struct open Basic_Code_Thingol; fun implode_list t = let fun dest_cons (IConst { sym = Code_Symbol.Constant \<^const_name>\Cons\, ... } `$ t1 `$ t2) = SOME (t1, t2) | dest_cons _ = NONE; val (ts, t') = Code_Thingol.unfoldr dest_cons t; in case t' of IConst { sym = Code_Symbol.Constant \<^const_name>\Nil\, ... } => SOME ts | _ => NONE end; fun print_list (target_fxy, target_cons) pr fxy t1 t2 = Code_Printer.brackify_infix (target_fxy, Code_Printer.R) fxy ( pr (Code_Printer.INFX (target_fxy, Code_Printer.X)) t1, Code_Printer.str target_cons, pr (Code_Printer.INFX (target_fxy, Code_Printer.R)) t2 ); fun add_literal_list target = let fun pretty literals pr _ vars fxy [(t1, _), (t2, _)] = case Option.map (cons t1) (implode_list t2) of SOME ts => Code_Printer.literal_list literals (map (pr vars Code_Printer.NOBR) ts) | NONE => print_list (Code_Printer.infix_cons literals) (pr vars) fxy t1 t2; in Code_Target.set_printings (Code_Symbol.Constant (\<^const_name>\Cons\, [(target, SOME (Code_Printer.complex_const_syntax (2, pretty)))])) end end; \ code_printing type_constructor list \ (SML) "_ list" and (OCaml) "_ list" and (Haskell) "![(_)]" and (Scala) "List[(_)]" | constant Nil \ (SML) "[]" and (OCaml) "[]" and (Haskell) "[]" and (Scala) "!Nil" | class_instance list :: equal \ (Haskell) - | constant "HOL.equal :: 'a list \ 'a list \ bool" \ (Haskell) infix 4 "==" setup \fold (List_Code.add_literal_list) ["SML", "OCaml", "Haskell", "Scala"]\ code_reserved SML list code_reserved OCaml list subsubsection \Use convenient predefined operations\ code_printing constant "(@)" \ (SML) infixr 7 "@" and (OCaml) infixr 6 "@" and (Haskell) infixr 5 "++" and (Scala) infixl 7 "++" | constant map \ (Haskell) "map" | constant filter \ (Haskell) "filter" | constant concat \ (Haskell) "concat" | constant List.maps \ (Haskell) "concatMap" | constant rev \ (Haskell) "reverse" | constant zip \ (Haskell) "zip" | constant List.null \ (Haskell) "null" | constant takeWhile \ (Haskell) "takeWhile" | constant dropWhile \ (Haskell) "dropWhile" | constant list_all \ (Haskell) "all" | constant list_ex \ (Haskell) "any" subsubsection \Implementation of sets by lists\ lemma is_empty_set [code]: "Set.is_empty (set xs) \ List.null xs" by (simp add: Set.is_empty_def null_def) lemma empty_set [code]: "{} = set []" by simp lemma UNIV_coset [code]: "UNIV = List.coset []" by simp lemma compl_set [code]: "- set xs = List.coset xs" by simp lemma compl_coset [code]: "- List.coset xs = set xs" by simp lemma [code]: "x \ set xs \ List.member xs x" "x \ List.coset xs \ \ List.member xs x" by (simp_all add: member_def) lemma insert_code [code]: "insert x (set xs) = set (List.insert x xs)" "insert x (List.coset xs) = List.coset (removeAll x xs)" by simp_all lemma remove_code [code]: "Set.remove x (set xs) = set (removeAll x xs)" "Set.remove x (List.coset xs) = List.coset (List.insert x xs)" by (simp_all add: remove_def Compl_insert) lemma filter_set [code]: "Set.filter P (set xs) = set (filter P xs)" by auto lemma image_set [code]: "image f (set xs) = set (map f xs)" by simp lemma subset_code [code]: "set xs \ B \ (\x\set xs. x \ B)" "A \ List.coset ys \ (\y\set ys. y \ A)" "List.coset [] \ set [] \ False" by auto text \A frequent case -- avoid intermediate sets\ lemma [code_unfold]: "set xs \ set ys \ list_all (\x. x \ set ys) xs" by (auto simp: list_all_iff) lemma Ball_set [code]: "Ball (set xs) P \ list_all P xs" by (simp add: list_all_iff) lemma Bex_set [code]: "Bex (set xs) P \ list_ex P xs" by (simp add: list_ex_iff) lemma card_set [code]: "card (set xs) = length (remdups xs)" proof - have "card (set (remdups xs)) = length (remdups xs)" by (rule distinct_card) simp then show ?thesis by simp qed lemma the_elem_set [code]: "the_elem (set [x]) = x" by simp lemma Pow_set [code]: "Pow (set []) = {{}}" "Pow (set (x # xs)) = (let A = Pow (set xs) in A \ insert x ` A)" by (simp_all add: Pow_insert Let_def) definition map_project :: "('a \ 'b option) \ 'a set \ 'b set" where "map_project f A = {b. \ a \ A. f a = Some b}" lemma [code]: "map_project f (set xs) = set (List.map_filter f xs)" by (auto simp add: map_project_def map_filter_def image_def) hide_const (open) map_project text \Operations on relations\ lemma product_code [code]: "Product_Type.product (set xs) (set ys) = set [(x, y). x \ xs, y \ ys]" by (auto simp add: Product_Type.product_def) lemma Id_on_set [code]: "Id_on (set xs) = set [(x, x). x \ xs]" by (auto simp add: Id_on_def) lemma [code]: "R `` S = List.map_project (\(x, y). if x \ S then Some y else None) R" unfolding map_project_def by (auto split: prod.split if_split_asm) lemma trancl_set_ntrancl [code]: "trancl (set xs) = ntrancl (card (set xs) - 1) (set xs)" by (simp add: finite_trancl_ntranl) lemma set_relcomp [code]: "set xys O set yzs = set ([(fst xy, snd yz). xy \ xys, yz \ yzs, snd xy = fst yz])" by auto (auto simp add: Bex_def image_def) lemma wf_set [code]: "wf (set xs) = acyclic (set xs)" by (simp add: wf_iff_acyclic_if_finite) subsection \Setup for Lifting/Transfer\ subsubsection \Transfer rules for the Transfer package\ context includes lifting_syntax begin lemma tl_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) tl tl" unfolding tl_def[abs_def] by transfer_prover lemma butlast_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) butlast butlast" by (rule rel_funI, erule list_all2_induct, auto) lemma map_rec: "map f xs = rec_list Nil (%x _ y. Cons (f x) y) xs" by (induct xs) auto lemma append_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A ===> list_all2 A) append append" unfolding List.append_def by transfer_prover lemma rev_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) rev rev" unfolding List.rev_def by transfer_prover lemma filter_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> list_all2 A) filter filter" unfolding List.filter_def by transfer_prover lemma fold_transfer [transfer_rule]: "((A ===> B ===> B) ===> list_all2 A ===> B ===> B) fold fold" unfolding List.fold_def by transfer_prover lemma foldr_transfer [transfer_rule]: "((A ===> B ===> B) ===> list_all2 A ===> B ===> B) foldr foldr" unfolding List.foldr_def by transfer_prover lemma foldl_transfer [transfer_rule]: "((B ===> A ===> B) ===> B ===> list_all2 A ===> B) foldl foldl" unfolding List.foldl_def by transfer_prover lemma concat_transfer [transfer_rule]: "(list_all2 (list_all2 A) ===> list_all2 A) concat concat" unfolding List.concat_def by transfer_prover lemma drop_transfer [transfer_rule]: "((=) ===> list_all2 A ===> list_all2 A) drop drop" unfolding List.drop_def by transfer_prover lemma take_transfer [transfer_rule]: "((=) ===> list_all2 A ===> list_all2 A) take take" unfolding List.take_def by transfer_prover lemma list_update_transfer [transfer_rule]: "(list_all2 A ===> (=) ===> A ===> list_all2 A) list_update list_update" unfolding list_update_def by transfer_prover lemma takeWhile_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> list_all2 A) takeWhile takeWhile" unfolding takeWhile_def by transfer_prover lemma dropWhile_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> list_all2 A) dropWhile dropWhile" unfolding dropWhile_def by transfer_prover lemma zip_transfer [transfer_rule]: "(list_all2 A ===> list_all2 B ===> list_all2 (rel_prod A B)) zip zip" unfolding zip_def by transfer_prover lemma product_transfer [transfer_rule]: "(list_all2 A ===> list_all2 B ===> list_all2 (rel_prod A B)) List.product List.product" unfolding List.product_def by transfer_prover lemma product_lists_transfer [transfer_rule]: "(list_all2 (list_all2 A) ===> list_all2 (list_all2 A)) product_lists product_lists" unfolding product_lists_def by transfer_prover lemma insert_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(A ===> list_all2 A ===> list_all2 A) List.insert List.insert" unfolding List.insert_def [abs_def] by transfer_prover lemma find_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> rel_option A) List.find List.find" unfolding List.find_def by transfer_prover lemma those_transfer [transfer_rule]: "(list_all2 (rel_option P) ===> rel_option (list_all2 P)) those those" unfolding List.those_def by transfer_prover lemma remove1_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(A ===> list_all2 A ===> list_all2 A) remove1 remove1" unfolding remove1_def by transfer_prover lemma removeAll_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(A ===> list_all2 A ===> list_all2 A) removeAll removeAll" unfolding removeAll_def by transfer_prover lemma successively_transfer [transfer_rule]: "((A ===> A ===> (=)) ===> list_all2 A ===> (=)) successively successively" unfolding successively_altdef by transfer_prover lemma distinct_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(list_all2 A ===> (=)) distinct distinct" unfolding distinct_def by transfer_prover lemma distinct_adj_transfer [transfer_rule]: assumes "bi_unique A" shows "(list_all2 A ===> (=)) distinct_adj distinct_adj" unfolding rel_fun_def proof (intro allI impI) fix xs ys assume "list_all2 A xs ys" thus "distinct_adj xs \ distinct_adj ys" proof (induction rule: list_all2_induct) case (Cons x xs y ys) note * = this show ?case proof (cases xs) case [simp]: (Cons x' xs') with * obtain y' ys' where [simp]: "ys = y' # ys'" by (cases ys) auto from * show ?thesis using assms by (auto simp: distinct_adj_Cons bi_unique_def) qed (use * in auto) qed auto qed lemma remdups_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(list_all2 A ===> list_all2 A) remdups remdups" unfolding remdups_def by transfer_prover lemma remdups_adj_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows "(list_all2 A ===> list_all2 A) remdups_adj remdups_adj" proof (rule rel_funI, erule list_all2_induct) qed (auto simp: remdups_adj_Cons assms[unfolded bi_unique_def] split: list.splits) lemma replicate_transfer [transfer_rule]: "((=) ===> A ===> list_all2 A) replicate replicate" unfolding replicate_def by transfer_prover lemma length_transfer [transfer_rule]: "(list_all2 A ===> (=)) length length" unfolding size_list_overloaded_def size_list_def by transfer_prover lemma rotate1_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) rotate1 rotate1" unfolding rotate1_def by transfer_prover lemma rotate_transfer [transfer_rule]: "((=) ===> list_all2 A ===> list_all2 A) rotate rotate" unfolding rotate_def [abs_def] by transfer_prover lemma nths_transfer [transfer_rule]: "(list_all2 A ===> rel_set (=) ===> list_all2 A) nths nths" unfolding nths_def [abs_def] by transfer_prover lemma subseqs_transfer [transfer_rule]: "(list_all2 A ===> list_all2 (list_all2 A)) subseqs subseqs" unfolding subseqs_def [abs_def] by transfer_prover lemma partition_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> rel_prod (list_all2 A) (list_all2 A)) partition partition" unfolding partition_def by transfer_prover lemma lists_transfer [transfer_rule]: "(rel_set A ===> rel_set (list_all2 A)) lists lists" proof (rule rel_funI, rule rel_setI) show "\l \ lists X; rel_set A X Y\ \ \y\lists Y. list_all2 A l y" for X Y l proof (induction l rule: lists.induct) case (Cons a l) then show ?case by (simp only: rel_set_def list_all2_Cons1, metis lists.Cons) qed auto show "\l \ lists Y; rel_set A X Y\ \ \x\lists X. list_all2 A x l" for X Y l proof (induction l rule: lists.induct) case (Cons a l) then show ?case by (simp only: rel_set_def list_all2_Cons2, metis lists.Cons) qed auto qed lemma set_Cons_transfer [transfer_rule]: "(rel_set A ===> rel_set (list_all2 A) ===> rel_set (list_all2 A)) set_Cons set_Cons" unfolding rel_fun_def rel_set_def set_Cons_def by (fastforce simp add: list_all2_Cons1 list_all2_Cons2) lemma listset_transfer [transfer_rule]: "(list_all2 (rel_set A) ===> rel_set (list_all2 A)) listset listset" unfolding listset_def by transfer_prover lemma null_transfer [transfer_rule]: "(list_all2 A ===> (=)) List.null List.null" unfolding rel_fun_def List.null_def by auto lemma list_all_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> (=)) list_all list_all" unfolding list_all_iff [abs_def] by transfer_prover lemma list_ex_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> (=)) list_ex list_ex" unfolding list_ex_iff [abs_def] by transfer_prover lemma splice_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A ===> list_all2 A) splice splice" apply (rule rel_funI, erule list_all2_induct, simp add: rel_fun_def, simp) apply (rule rel_funI) apply (erule_tac xs=x in list_all2_induct, simp, simp add: rel_fun_def) done lemma shuffles_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A ===> rel_set (list_all2 A)) shuffles shuffles" proof (intro rel_funI, goal_cases) case (1 xs xs' ys ys') thus ?case proof (induction xs ys arbitrary: xs' ys' rule: shuffles.induct) case (3 x xs y ys xs' ys') from "3.prems" obtain x' xs'' where xs': "xs' = x' # xs''" by (cases xs') auto from "3.prems" obtain y' ys'' where ys': "ys' = y' # ys''" by (cases ys') auto have [transfer_rule]: "A x x'" "A y y'" "list_all2 A xs xs''" "list_all2 A ys ys''" using "3.prems" by (simp_all add: xs' ys') have [transfer_rule]: "rel_set (list_all2 A) (shuffles xs (y # ys)) (shuffles xs'' ys')" and [transfer_rule]: "rel_set (list_all2 A) (shuffles (x # xs) ys) (shuffles xs' ys'')" using "3.prems" by (auto intro!: "3.IH" simp: xs' ys') have "rel_set (list_all2 A) ((#) x ` shuffles xs (y # ys) \ (#) y ` shuffles (x # xs) ys) ((#) x' ` shuffles xs'' ys' \ (#) y' ` shuffles xs' ys'')" by transfer_prover thus ?case by (simp add: xs' ys') qed (auto simp: rel_set_def) qed lemma rtrancl_parametric [transfer_rule]: assumes [transfer_rule]: "bi_unique A" "bi_total A" shows "(rel_set (rel_prod A A) ===> rel_set (rel_prod A A)) rtrancl rtrancl" unfolding rtrancl_def by transfer_prover lemma monotone_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total A" shows "((A ===> A ===> (=)) ===> (B ===> B ===> (=)) ===> (A ===> B) ===> (=)) monotone monotone" unfolding monotone_def[abs_def] by transfer_prover lemma fun_ord_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total C" shows "((A ===> B ===> (=)) ===> (C ===> A) ===> (C ===> B) ===> (=)) fun_ord fun_ord" unfolding fun_ord_def[abs_def] by transfer_prover lemma fun_lub_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total A" "bi_unique A" shows "((rel_set A ===> B) ===> rel_set (C ===> A) ===> C ===> B) fun_lub fun_lub" unfolding fun_lub_def[abs_def] by transfer_prover end end diff --git a/src/HOL/Map.thy b/src/HOL/Map.thy --- a/src/HOL/Map.thy +++ b/src/HOL/Map.thy @@ -1,862 +1,942 @@ (* Title: HOL/Map.thy Author: Tobias Nipkow, based on a theory by David von Oheimb Copyright 1997-2003 TU Muenchen The datatype of "maps"; strongly resembles maps in VDM. *) section \Maps\ theory Map imports List abbrevs "(=" = "\\<^sub>m" begin type_synonym ('a, 'b) "map" = "'a \ 'b option" (infixr "\" 0) abbreviation empty :: "'a \ 'b" where "empty \ \x. None" definition map_comp :: "('b \ 'c) \ ('a \ 'b) \ ('a \ 'c)" (infixl "\\<^sub>m" 55) where "f \\<^sub>m g = (\k. case g k of None \ None | Some v \ f v)" definition map_add :: "('a \ 'b) \ ('a \ 'b) \ ('a \ 'b)" (infixl "++" 100) where "m1 ++ m2 = (\x. case m2 x of None \ m1 x | Some y \ Some y)" definition restrict_map :: "('a \ 'b) \ 'a set \ ('a \ 'b)" (infixl "|`" 110) where "m|`A = (\x. if x \ A then m x else None)" notation (latex output) restrict_map ("_\\<^bsub>_\<^esub>" [111,110] 110) definition dom :: "('a \ 'b) \ 'a set" where "dom m = {a. m a \ None}" definition ran :: "('a \ 'b) \ 'b set" where "ran m = {b. \a. m a = Some b}" definition + graph :: "('a \ 'b) \ ('a \ 'b) set" where + "graph m = {(a, b) | a b. m a = Some b}" + +definition map_le :: "('a \ 'b) \ ('a \ 'b) \ bool" (infix "\\<^sub>m" 50) where "(m\<^sub>1 \\<^sub>m m\<^sub>2) \ (\a \ dom m\<^sub>1. m\<^sub>1 a = m\<^sub>2 a)" nonterminal maplets and maplet syntax "_maplet" :: "['a, 'a] \ maplet" ("_ /\/ _") "_maplets" :: "['a, 'a] \ maplet" ("_ /[\]/ _") "" :: "maplet \ maplets" ("_") "_Maplets" :: "[maplet, maplets] \ maplets" ("_,/ _") "_MapUpd" :: "['a \ 'b, maplets] \ 'a \ 'b" ("_/'(_')" [900, 0] 900) "_Map" :: "maplets \ 'a \ 'b" ("(1[_])") syntax (ASCII) "_maplet" :: "['a, 'a] \ maplet" ("_ /|->/ _") "_maplets" :: "['a, 'a] \ maplet" ("_ /[|->]/ _") translations "_MapUpd m (_Maplets xy ms)" \ "_MapUpd (_MapUpd m xy) ms" "_MapUpd m (_maplet x y)" \ "m(x := CONST Some y)" "_Map ms" \ "_MapUpd (CONST empty) ms" "_Map (_Maplets ms1 ms2)" \ "_MapUpd (_Map ms1) ms2" "_Maplets ms1 (_Maplets ms2 ms3)" \ "_Maplets (_Maplets ms1 ms2) ms3" primrec map_of :: "('a \ 'b) list \ 'a \ 'b" where "map_of [] = empty" | "map_of (p # ps) = (map_of ps)(fst p \ snd p)" definition map_upds :: "('a \ 'b) \ 'a list \ 'b list \ 'a \ 'b" where "map_upds m xs ys = m ++ map_of (rev (zip xs ys))" translations "_MapUpd m (_maplets x y)" \ "CONST map_upds m x y" lemma map_of_Cons_code [code]: "map_of [] k = None" "map_of ((l, v) # ps) k = (if l = k then Some v else map_of ps k)" by simp_all subsection \@{term [source] empty}\ lemma empty_upd_none [simp]: "empty(x := None) = empty" by (rule ext) simp subsection \@{term [source] map_upd}\ lemma map_upd_triv: "t k = Some x \ t(k\x) = t" by (rule ext) simp lemma map_upd_nonempty [simp]: "t(k\x) \ empty" proof assume "t(k \ x) = empty" then have "(t(k \ x)) k = None" by simp then show False by simp qed lemma map_upd_eqD1: assumes "m(a\x) = n(a\y)" shows "x = y" proof - from assms have "(m(a\x)) a = (n(a\y)) a" by simp then show ?thesis by simp qed lemma map_upd_Some_unfold: "((m(a\b)) x = Some y) = (x = a \ b = y \ x \ a \ m x = Some y)" by auto lemma image_map_upd [simp]: "x \ A \ m(x \ y) ` A = m ` A" by auto lemma finite_range_updI: assumes "finite (range f)" shows "finite (range (f(a\b)))" proof - have "range (f(a\b)) \ insert (Some b) (range f)" by auto then show ?thesis by (rule finite_subset) (use assms in auto) qed subsection \@{term [source] map_of}\ lemma map_of_eq_empty_iff [simp]: "map_of xys = empty \ xys = []" proof show "map_of xys = empty \ xys = []" by (induction xys) simp_all qed simp lemma empty_eq_map_of_iff [simp]: "empty = map_of xys \ xys = []" by(subst eq_commute) simp lemma map_of_eq_None_iff: "(map_of xys x = None) = (x \ fst ` (set xys))" by (induct xys) simp_all lemma map_of_eq_Some_iff [simp]: "distinct(map fst xys) \ (map_of xys x = Some y) = ((x,y) \ set xys)" proof (induct xys) case (Cons xy xys) then show ?case by (cases xy) (auto simp flip: map_of_eq_None_iff) qed auto lemma Some_eq_map_of_iff [simp]: "distinct(map fst xys) \ (Some y = map_of xys x) = ((x,y) \ set xys)" by (auto simp del: map_of_eq_Some_iff simp: map_of_eq_Some_iff [symmetric]) lemma map_of_is_SomeI [simp]: "\distinct(map fst xys); (x,y) \ set xys\ \ map_of xys x = Some y" by simp lemma map_of_zip_is_None [simp]: "length xs = length ys \ (map_of (zip xs ys) x = None) = (x \ set xs)" by (induct rule: list_induct2) simp_all lemma map_of_zip_is_Some: assumes "length xs = length ys" shows "x \ set xs \ (\y. map_of (zip xs ys) x = Some y)" using assms by (induct rule: list_induct2) simp_all lemma map_of_zip_upd: fixes x :: 'a and xs :: "'a list" and ys zs :: "'b list" assumes "length ys = length xs" and "length zs = length xs" and "x \ set xs" and "map_of (zip xs ys)(x \ y) = map_of (zip xs zs)(x \ z)" shows "map_of (zip xs ys) = map_of (zip xs zs)" proof fix x' :: 'a show "map_of (zip xs ys) x' = map_of (zip xs zs) x'" proof (cases "x = x'") case True from assms True map_of_zip_is_None [of xs ys x'] have "map_of (zip xs ys) x' = None" by simp moreover from assms True map_of_zip_is_None [of xs zs x'] have "map_of (zip xs zs) x' = None" by simp ultimately show ?thesis by simp next case False from assms have "(map_of (zip xs ys)(x \ y)) x' = (map_of (zip xs zs)(x \ z)) x'" by auto with False show ?thesis by simp qed qed lemma map_of_zip_inject: assumes "length ys = length xs" and "length zs = length xs" and dist: "distinct xs" and map_of: "map_of (zip xs ys) = map_of (zip xs zs)" shows "ys = zs" using assms(1) assms(2)[symmetric] using dist map_of proof (induct ys xs zs rule: list_induct3) case Nil show ?case by simp next case (Cons y ys x xs z zs) from \map_of (zip (x#xs) (y#ys)) = map_of (zip (x#xs) (z#zs))\ have map_of: "map_of (zip xs ys)(x \ y) = map_of (zip xs zs)(x \ z)" by simp from Cons have "length ys = length xs" and "length zs = length xs" and "x \ set xs" by simp_all then have "map_of (zip xs ys) = map_of (zip xs zs)" using map_of by (rule map_of_zip_upd) with Cons.hyps \distinct (x # xs)\ have "ys = zs" by simp moreover from map_of have "y = z" by (rule map_upd_eqD1) ultimately show ?case by simp qed lemma map_of_zip_nth: assumes "length xs = length ys" assumes "distinct xs" assumes "i < length ys" shows "map_of (zip xs ys) (xs ! i) = Some (ys ! i)" using assms proof (induct arbitrary: i rule: list_induct2) case Nil then show ?case by simp next case (Cons x xs y ys) then show ?case using less_Suc_eq_0_disj by auto qed lemma map_of_zip_map: "map_of (zip xs (map f xs)) = (\x. if x \ set xs then Some (f x) else None)" by (induct xs) (simp_all add: fun_eq_iff) lemma finite_range_map_of: "finite (range (map_of xys))" proof (induct xys) case (Cons a xys) then show ?case using finite_range_updI by fastforce qed auto lemma map_of_SomeD: "map_of xs k = Some y \ (k, y) \ set xs" by (induct xs) (auto split: if_splits) lemma map_of_mapk_SomeI: "inj f \ map_of t k = Some x \ map_of (map (case_prod (\k. Pair (f k))) t) (f k) = Some x" by (induct t) (auto simp: inj_eq) lemma weak_map_of_SomeI: "(k, x) \ set l \ \x. map_of l k = Some x" by (induct l) auto lemma map_of_filter_in: "map_of xs k = Some z \ P k z \ map_of (filter (case_prod P) xs) k = Some z" by (induct xs) auto lemma map_of_map: "map_of (map (\(k, v). (k, f v)) xs) = map_option f \ map_of xs" by (induct xs) (auto simp: fun_eq_iff) lemma dom_map_option: "dom (\k. map_option (f k) (m k)) = dom m" by (simp add: dom_def) lemma dom_map_option_comp [simp]: "dom (map_option g \ m) = dom m" using dom_map_option [of "\_. g" m] by (simp add: comp_def) subsection \\<^const>\map_option\ related\ lemma map_option_o_empty [simp]: "map_option f \ empty = empty" by (rule ext) simp lemma map_option_o_map_upd [simp]: "map_option f \ m(a\b) = (map_option f \ m)(a\f b)" by (rule ext) simp subsection \@{term [source] map_comp} related\ lemma map_comp_empty [simp]: "m \\<^sub>m empty = empty" "empty \\<^sub>m m = empty" by (auto simp: map_comp_def split: option.splits) lemma map_comp_simps [simp]: "m2 k = None \ (m1 \\<^sub>m m2) k = None" "m2 k = Some k' \ (m1 \\<^sub>m m2) k = m1 k'" by (auto simp: map_comp_def) lemma map_comp_Some_iff: "((m1 \\<^sub>m m2) k = Some v) = (\k'. m2 k = Some k' \ m1 k' = Some v)" by (auto simp: map_comp_def split: option.splits) lemma map_comp_None_iff: "((m1 \\<^sub>m m2) k = None) = (m2 k = None \ (\k'. m2 k = Some k' \ m1 k' = None)) " by (auto simp: map_comp_def split: option.splits) subsection \\++\\ lemma map_add_empty[simp]: "m ++ empty = m" by(simp add: map_add_def) lemma empty_map_add[simp]: "empty ++ m = m" by (rule ext) (simp add: map_add_def split: option.split) lemma map_add_assoc[simp]: "m1 ++ (m2 ++ m3) = (m1 ++ m2) ++ m3" by (rule ext) (simp add: map_add_def split: option.split) lemma map_add_Some_iff: "((m ++ n) k = Some x) = (n k = Some x \ n k = None \ m k = Some x)" by (simp add: map_add_def split: option.split) lemma map_add_SomeD [dest!]: "(m ++ n) k = Some x \ n k = Some x \ n k = None \ m k = Some x" by (rule map_add_Some_iff [THEN iffD1]) lemma map_add_find_right [simp]: "n k = Some xx \ (m ++ n) k = Some xx" by (subst map_add_Some_iff) fast lemma map_add_None [iff]: "((m ++ n) k = None) = (n k = None \ m k = None)" by (simp add: map_add_def split: option.split) lemma map_add_upd[simp]: "f ++ g(x\y) = (f ++ g)(x\y)" by (rule ext) (simp add: map_add_def) lemma map_add_upds[simp]: "m1 ++ (m2(xs[\]ys)) = (m1++m2)(xs[\]ys)" by (simp add: map_upds_def) lemma map_add_upd_left: "m\dom e2 \ e1(m \ u1) ++ e2 = (e1 ++ e2)(m \ u1)" by (rule ext) (auto simp: map_add_def dom_def split: option.split) lemma map_of_append[simp]: "map_of (xs @ ys) = map_of ys ++ map_of xs" unfolding map_add_def proof (induct xs) case (Cons a xs) then show ?case by (force split: option.split) qed auto lemma finite_range_map_of_map_add: "finite (range f) \ finite (range (f ++ map_of l))" proof (induct l) case (Cons a l) then show ?case by (metis finite_range_updI map_add_upd map_of.simps(2)) qed auto lemma inj_on_map_add_dom [iff]: "inj_on (m ++ m') (dom m') = inj_on m' (dom m')" by (fastforce simp: map_add_def dom_def inj_on_def split: option.splits) lemma map_upds_fold_map_upd: "m(ks[\]vs) = foldl (\m (k, v). m(k \ v)) m (zip ks vs)" unfolding map_upds_def proof (rule sym, rule zip_obtain_same_length) fix ks :: "'a list" and vs :: "'b list" assume "length ks = length vs" then show "foldl (\m (k, v). m(k\v)) m (zip ks vs) = m ++ map_of (rev (zip ks vs))" by(induct arbitrary: m rule: list_induct2) simp_all qed lemma map_add_map_of_foldr: "m ++ map_of ps = foldr (\(k, v) m. m(k \ v)) ps m" by (induct ps) (auto simp: fun_eq_iff map_add_def) subsection \@{term [source] restrict_map}\ lemma restrict_map_to_empty [simp]: "m|`{} = empty" by (simp add: restrict_map_def) lemma restrict_map_insert: "f |` (insert a A) = (f |` A)(a := f a)" by (auto simp: restrict_map_def) lemma restrict_map_empty [simp]: "empty|`D = empty" by (simp add: restrict_map_def) lemma restrict_in [simp]: "x \ A \ (m|`A) x = m x" by (simp add: restrict_map_def) lemma restrict_out [simp]: "x \ A \ (m|`A) x = None" by (simp add: restrict_map_def) lemma ran_restrictD: "y \ ran (m|`A) \ \x\A. m x = Some y" by (auto simp: restrict_map_def ran_def split: if_split_asm) lemma dom_restrict [simp]: "dom (m|`A) = dom m \ A" by (auto simp: restrict_map_def dom_def split: if_split_asm) lemma restrict_upd_same [simp]: "m(x\y)|`(-{x}) = m|`(-{x})" by (rule ext) (auto simp: restrict_map_def) lemma restrict_restrict [simp]: "m|`A|`B = m|`(A\B)" by (rule ext) (auto simp: restrict_map_def) lemma restrict_fun_upd [simp]: "m(x := y)|`D = (if x \ D then (m|`(D-{x}))(x := y) else m|`D)" by (simp add: restrict_map_def fun_eq_iff) lemma fun_upd_None_restrict [simp]: "(m|`D)(x := None) = (if x \ D then m|`(D - {x}) else m|`D)" by (simp add: restrict_map_def fun_eq_iff) lemma fun_upd_restrict: "(m|`D)(x := y) = (m|`(D-{x}))(x := y)" by (simp add: restrict_map_def fun_eq_iff) lemma fun_upd_restrict_conv [simp]: "x \ D \ (m|`D)(x := y) = (m|`(D-{x}))(x := y)" by (rule fun_upd_restrict) lemma map_of_map_restrict: "map_of (map (\k. (k, f k)) ks) = (Some \ f) |` set ks" by (induct ks) (simp_all add: fun_eq_iff restrict_map_insert) lemma restrict_complement_singleton_eq: "f |` (- {x}) = f(x := None)" by auto subsection \@{term [source] map_upds}\ lemma map_upds_Nil1 [simp]: "m([] [\] bs) = m" by (simp add: map_upds_def) lemma map_upds_Nil2 [simp]: "m(as [\] []) = m" by (simp add:map_upds_def) lemma map_upds_Cons [simp]: "m(a#as [\] b#bs) = (m(a\b))(as[\]bs)" by (simp add:map_upds_def) lemma map_upds_append1 [simp]: "size xs < size ys \ m(xs@[x] [\] ys) = m(xs [\] ys)(x \ ys!size xs)" proof (induct xs arbitrary: ys m) case Nil then show ?case by (auto simp: neq_Nil_conv) next case (Cons a xs) then show ?case by (cases ys) auto qed lemma map_upds_list_update2_drop [simp]: "size xs \ i \ m(xs[\]ys[i:=y]) = m(xs[\]ys)" proof (induct xs arbitrary: m ys i) case Nil then show ?case by auto next case (Cons a xs) then show ?case by (cases ys) (use Cons in \auto split: nat.split\) qed text \Something weirdly sensitive about this proof, which needs only four lines in apply style\ lemma map_upd_upds_conv_if: "(f(x\y))(xs [\] ys) = (if x \ set(take (length ys) xs) then f(xs [\] ys) else (f(xs [\] ys))(x\y))" proof (induct xs arbitrary: x y ys f) case (Cons a xs) show ?case proof (cases ys) case (Cons z zs) then show ?thesis using Cons.hyps apply (auto split: if_split simp: fun_upd_twist) using Cons.hyps apply fastforce+ done qed auto qed auto lemma map_upds_twist [simp]: "a \ set as \ m(a\b)(as[\]bs) = m(as[\]bs)(a\b)" using set_take_subset by (fastforce simp add: map_upd_upds_conv_if) lemma map_upds_apply_nontin [simp]: "x \ set xs \ (f(xs[\]ys)) x = f x" proof (induct xs arbitrary: ys) case (Cons a xs) then show ?case by (cases ys) (auto simp: map_upd_upds_conv_if) qed auto lemma fun_upds_append_drop [simp]: "size xs = size ys \ m(xs@zs[\]ys) = m(xs[\]ys)" proof (induct xs arbitrary: ys) case (Cons a xs) then show ?case by (cases ys) (auto simp: map_upd_upds_conv_if) qed auto lemma fun_upds_append2_drop [simp]: "size xs = size ys \ m(xs[\]ys@zs) = m(xs[\]ys)" proof (induct xs arbitrary: ys) case (Cons a xs) then show ?case by (cases ys) (auto simp: map_upd_upds_conv_if) qed auto lemma restrict_map_upds[simp]: "\ length xs = length ys; set xs \ D \ \ m(xs [\] ys)|`D = (m|`(D - set xs))(xs [\] ys)" proof (induct xs arbitrary: m ys) case (Cons a xs) then show ?case proof (cases ys) case (Cons z zs) with Cons.hyps Cons.prems show ?thesis apply (simp add: insert_absorb flip: Diff_insert) apply (auto simp add: map_upd_upds_conv_if) done qed auto qed auto subsection \@{term [source] dom}\ lemma dom_eq_empty_conv [simp]: "dom f = {} \ f = empty" by (auto simp: dom_def) lemma domI: "m a = Some b \ a \ dom m" by (simp add: dom_def) (* declare domI [intro]? *) lemma domD: "a \ dom m \ \b. m a = Some b" by (cases "m a") (auto simp add: dom_def) lemma domIff [iff, simp del, code_unfold]: "a \ dom m \ m a \ None" by (simp add: dom_def) lemma dom_empty [simp]: "dom empty = {}" by (simp add: dom_def) lemma dom_fun_upd [simp]: "dom(f(x := y)) = (if y = None then dom f - {x} else insert x (dom f))" by (auto simp: dom_def) lemma dom_if: "dom (\x. if P x then f x else g x) = dom f \ {x. P x} \ dom g \ {x. \ P x}" by (auto split: if_splits) lemma dom_map_of_conv_image_fst: "dom (map_of xys) = fst ` set xys" by (induct xys) (auto simp add: dom_if) lemma dom_map_of_zip [simp]: "length xs = length ys \ dom (map_of (zip xs ys)) = set xs" by (induct rule: list_induct2) (auto simp: dom_if) lemma finite_dom_map_of: "finite (dom (map_of l))" by (induct l) (auto simp: dom_def insert_Collect [symmetric]) lemma dom_map_upds [simp]: "dom(m(xs[\]ys)) = set(take (length ys) xs) \ dom m" proof (induct xs arbitrary: ys) case (Cons a xs) then show ?case by (cases ys) (auto simp: map_upd_upds_conv_if) qed auto lemma dom_map_add [simp]: "dom (m ++ n) = dom n \ dom m" by (auto simp: dom_def) lemma dom_override_on [simp]: "dom (override_on f g A) = (dom f - {a. a \ A - dom g}) \ {a. a \ A \ dom g}" by (auto simp: dom_def override_on_def) lemma map_add_comm: "dom m1 \ dom m2 = {} \ m1 ++ m2 = m2 ++ m1" by (rule ext) (force simp: map_add_def dom_def split: option.split) lemma map_add_dom_app_simps: "m \ dom l2 \ (l1 ++ l2) m = l2 m" "m \ dom l1 \ (l1 ++ l2) m = l2 m" "m \ dom l2 \ (l1 ++ l2) m = l1 m" by (auto simp add: map_add_def split: option.split_asm) lemma dom_const [simp]: "dom (\x. Some (f x)) = UNIV" by auto (* Due to John Matthews - could be rephrased with dom *) lemma finite_map_freshness: "finite (dom (f :: 'a \ 'b)) \ \ finite (UNIV :: 'a set) \ \x. f x = None" by (bestsimp dest: ex_new_if_finite) lemma dom_minus: "f x = None \ dom f - insert x A = dom f - A" unfolding dom_def by simp lemma insert_dom: "f x = Some y \ insert x (dom f) = dom f" unfolding dom_def by auto lemma map_of_map_keys: "set xs = dom m \ map_of (map (\k. (k, the (m k))) xs) = m" by (rule ext) (auto simp add: map_of_map_restrict restrict_map_def) lemma map_of_eqI: assumes set_eq: "set (map fst xs) = set (map fst ys)" assumes map_eq: "\k\set (map fst xs). map_of xs k = map_of ys k" shows "map_of xs = map_of ys" proof (rule ext) fix k show "map_of xs k = map_of ys k" proof (cases "map_of xs k") case None then have "k \ set (map fst xs)" by (simp add: map_of_eq_None_iff) with set_eq have "k \ set (map fst ys)" by simp then have "map_of ys k = None" by (simp add: map_of_eq_None_iff) with None show ?thesis by simp next case (Some v) then have "k \ set (map fst xs)" by (auto simp add: dom_map_of_conv_image_fst [symmetric]) with map_eq show ?thesis by auto qed qed lemma map_of_eq_dom: assumes "map_of xs = map_of ys" shows "fst ` set xs = fst ` set ys" proof - from assms have "dom (map_of xs) = dom (map_of ys)" by simp then show ?thesis by (simp add: dom_map_of_conv_image_fst) qed lemma finite_set_of_finite_maps: assumes "finite A" "finite B" shows "finite {m. dom m = A \ ran m \ B}" (is "finite ?S") proof - let ?S' = "{m. \x. (x \ A \ m x \ Some ` B) \ (x \ A \ m x = None)}" have "?S = ?S'" proof show "?S \ ?S'" by (auto simp: dom_def ran_def image_def) show "?S' \ ?S" proof fix m assume "m \ ?S'" hence 1: "dom m = A" by force hence 2: "ran m \ B" using \m \ ?S'\ by (auto simp: dom_def ran_def) from 1 2 show "m \ ?S" by blast qed qed with assms show ?thesis by(simp add: finite_set_of_finite_funs) qed subsection \@{term [source] ran}\ lemma ranI: "m a = Some b \ b \ ran m" by (auto simp: ran_def) (* declare ranI [intro]? *) lemma ran_empty [simp]: "ran empty = {}" by (auto simp: ran_def) lemma ran_map_upd [simp]: "m a = None \ ran(m(a\b)) = insert b (ran m)" unfolding ran_def by force +lemma fun_upd_None_if_notin_dom[simp]: "k \ dom m \ m(k := None) = m" + by auto + lemma ran_map_add: assumes "dom m1 \ dom m2 = {}" shows "ran (m1 ++ m2) = ran m1 \ ran m2" proof show "ran (m1 ++ m2) \ ran m1 \ ran m2" unfolding ran_def by auto next show "ran m1 \ ran m2 \ ran (m1 ++ m2)" proof - have "(m1 ++ m2) x = Some y" if "m1 x = Some y" for x y using assms map_add_comm that by fastforce moreover have "(m1 ++ m2) x = Some y" if "m2 x = Some y" for x y using assms that by auto ultimately show ?thesis unfolding ran_def by blast qed qed lemma finite_ran: assumes "finite (dom p)" shows "finite (ran p)" proof - have "ran p = (\x. the (p x)) ` dom p" unfolding ran_def by force from this \finite (dom p)\ show ?thesis by auto qed lemma ran_distinct: assumes dist: "distinct (map fst al)" shows "ran (map_of al) = snd ` set al" using assms proof (induct al) case Nil then show ?case by simp next case (Cons kv al) then have "ran (map_of al) = snd ` set al" by simp moreover from Cons.prems have "map_of al (fst kv) = None" by (simp add: map_of_eq_None_iff) ultimately show ?case by (simp only: map_of.simps ran_map_upd) simp qed lemma ran_map_of_zip: assumes "length xs = length ys" "distinct xs" shows "ran (map_of (zip xs ys)) = set ys" using assms by (simp add: ran_distinct set_map[symmetric]) lemma ran_map_option: "ran (\x. map_option f (m x)) = f ` ran m" by (auto simp add: ran_def) +subsection \@{term [source] graph}\ + +lemma graph_empty[simp]: "graph empty = {}" + unfolding graph_def by simp + +lemma in_graphI: "m k = Some v \ (k, v) \ graph m" + unfolding graph_def by blast + +lemma in_graphD: "(k, v) \ graph m \ m k = Some v" + unfolding graph_def by blast + +lemma graph_map_upd[simp]: "graph (m(k \ v)) = insert (k, v) (graph (m(k := None)))" + unfolding graph_def by (auto split: if_splits) + +lemma graph_fun_upd_None: "graph (m(k := None)) = {e \ graph m. fst e \ k}" + unfolding graph_def by (auto split: if_splits) + +lemma graph_restrictD: + assumes "(k, v) \ graph (m |` A)" + shows "k \ A" and "m k = Some v" + using assms unfolding graph_def + by (auto simp: restrict_map_def split: if_splits) + +lemma graph_map_comp[simp]: "graph (m1 \\<^sub>m m2) = graph m2 O graph m1" + unfolding graph_def by (auto simp: map_comp_Some_iff relcomp_unfold) + +lemma graph_map_add: "dom m1 \ dom m2 = {} \ graph (m1 ++ m2) = graph m1 \ graph m2" + unfolding graph_def using map_add_comm by force + +lemma graph_eq_to_snd_dom: "graph m = (\x. (x, the (m x))) ` dom m" + unfolding graph_def dom_def by force + +lemma fst_graph_eq_dom: "fst ` graph m = dom m" + unfolding graph_eq_to_snd_dom by force + +lemma graph_domD: "x \ graph m \ fst x \ dom m" + using fst_graph_eq_dom by (metis imageI) + +lemma snd_graph_ran: "snd ` graph m = ran m" + unfolding graph_def ran_def by force + +lemma graph_ranD: "x \ graph m \ snd x \ ran m" + using snd_graph_ran by (metis imageI) + +lemma finite_graph_map_of: "finite (graph (map_of al))" + unfolding graph_eq_to_snd_dom finite_dom_map_of + using finite_dom_map_of by blast + +lemma graph_map_of_if_distinct_ran: "distinct (map fst al) \ graph (map_of al) = set al" + unfolding graph_def by auto + +lemma finite_graph_iff_finite_dom[simp]: "finite (graph m) = finite (dom m)" + by (metis graph_eq_to_snd_dom finite_imageI fst_graph_eq_dom) + +lemma inj_on_fst_graph: "inj_on fst (graph m)" + unfolding graph_def inj_on_def by force subsection \\map_le\\ lemma map_le_empty [simp]: "empty \\<^sub>m g" by (simp add: map_le_def) lemma upd_None_map_le [simp]: "f(x := None) \\<^sub>m f" by (force simp add: map_le_def) lemma map_le_upd[simp]: "f \\<^sub>m g ==> f(a := b) \\<^sub>m g(a := b)" by (fastforce simp add: map_le_def) lemma map_le_imp_upd_le [simp]: "m1 \\<^sub>m m2 \ m1(x := None) \\<^sub>m m2(x \ y)" by (force simp add: map_le_def) lemma map_le_upds [simp]: "f \\<^sub>m g \ f(as [\] bs) \\<^sub>m g(as [\] bs)" proof (induct as arbitrary: f g bs) case (Cons a as) then show ?case by (cases bs) (use Cons in auto) qed auto lemma map_le_implies_dom_le: "(f \\<^sub>m g) \ (dom f \ dom g)" by (fastforce simp add: map_le_def dom_def) lemma map_le_refl [simp]: "f \\<^sub>m f" by (simp add: map_le_def) lemma map_le_trans[trans]: "\ m1 \\<^sub>m m2; m2 \\<^sub>m m3\ \ m1 \\<^sub>m m3" by (auto simp add: map_le_def dom_def) lemma map_le_antisym: "\ f \\<^sub>m g; g \\<^sub>m f \ \ f = g" unfolding map_le_def by (metis ext domIff) lemma map_le_map_add [simp]: "f \\<^sub>m g ++ f" by (fastforce simp: map_le_def) lemma map_le_iff_map_add_commute: "f \\<^sub>m f ++ g \ f ++ g = g ++ f" by (fastforce simp: map_add_def map_le_def fun_eq_iff split: option.splits) lemma map_add_le_mapE: "f ++ g \\<^sub>m h \ g \\<^sub>m h" by (fastforce simp: map_le_def map_add_def dom_def) lemma map_add_le_mapI: "\ f \\<^sub>m h; g \\<^sub>m h \ \ f ++ g \\<^sub>m h" by (auto simp: map_le_def map_add_def dom_def split: option.splits) lemma map_add_subsumed1: "f \\<^sub>m g \ f++g = g" by (simp add: map_add_le_mapI map_le_antisym) lemma map_add_subsumed2: "f \\<^sub>m g \ g++f = g" by (metis map_add_subsumed1 map_le_iff_map_add_commute) lemma dom_eq_singleton_conv: "dom f = {x} \ (\v. f = [x \ v])" (is "?lhs \ ?rhs") proof assume ?rhs then show ?lhs by (auto split: if_split_asm) next assume ?lhs then obtain v where v: "f x = Some v" by auto show ?rhs proof show "f = [x \ v]" proof (rule map_le_antisym) show "[x \ v] \\<^sub>m f" using v by (auto simp add: map_le_def) show "f \\<^sub>m [x \ v]" using \dom f = {x}\ \f x = Some v\ by (auto simp add: map_le_def) qed qed qed lemma map_add_eq_empty_iff[simp]: "(f++g = empty) \ f = empty \ g = empty" by (metis map_add_None) lemma empty_eq_map_add_iff[simp]: "(empty = f++g) \ f = empty \ g = empty" by(subst map_add_eq_empty_iff[symmetric])(rule eq_commute) subsection \Various\ lemma set_map_of_compr: assumes distinct: "distinct (map fst xs)" shows "set xs = {(k, v). map_of xs k = Some v}" using assms proof (induct xs) case Nil then show ?case by simp next case (Cons x xs) obtain k v where "x = (k, v)" by (cases x) blast with Cons.prems have "k \ dom (map_of xs)" by (simp add: dom_map_of_conv_image_fst) then have *: "insert (k, v) {(k, v). map_of xs k = Some v} = {(k', v'). (map_of xs(k \ v)) k' = Some v'}" by (auto split: if_splits) from Cons have "set xs = {(k, v). map_of xs k = Some v}" by simp with * \x = (k, v)\ show ?case by simp qed lemma eq_key_imp_eq_value: "v1 = v2" if "distinct (map fst xs)" "(k, v1) \ set xs" "(k, v2) \ set xs" proof - from that have "inj_on fst (set xs)" by (simp add: distinct_map) moreover have "fst (k, v1) = fst (k, v2)" by simp ultimately have "(k, v1) = (k, v2)" by (rule inj_onD) (fact that)+ then show ?thesis by simp qed lemma map_of_inject_set: assumes distinct: "distinct (map fst xs)" "distinct (map fst ys)" shows "map_of xs = map_of ys \ set xs = set ys" (is "?lhs \ ?rhs") proof assume ?lhs moreover from \distinct (map fst xs)\ have "set xs = {(k, v). map_of xs k = Some v}" by (rule set_map_of_compr) moreover from \distinct (map fst ys)\ have "set ys = {(k, v). map_of ys k = Some v}" by (rule set_map_of_compr) ultimately show ?rhs by simp next assume ?rhs show ?lhs proof fix k show "map_of xs k = map_of ys k" proof (cases "map_of xs k") case None with \?rhs\ have "map_of ys k = None" by (simp add: map_of_eq_None_iff) with None show ?thesis by simp next case (Some v) with distinct \?rhs\ have "map_of ys k = Some v" by simp with Some show ?thesis by simp qed qed qed -hide_const (open) Map.empty +lemma finite_Map_induct[consumes 1, case_names empty update]: + assumes "finite (dom m)" + assumes "P Map.empty" + assumes "\k v m. finite (dom m) \ k \ dom m \ P m \ P (m(k \ v))" + shows "P m" + using assms(1) +proof(induction "dom m" arbitrary: m rule: finite_induct) + case empty + then show ?case using assms(2) unfolding dom_def by simp +next + case (insert x F) + then have "finite (dom (m(x:=None)))" "x \ dom (m(x:=None))" "P (m(x:=None))" + by (metis Diff_insert_absorb dom_fun_upd)+ + with assms(3)[OF this] show ?case + by (metis fun_upd_triv fun_upd_upd option.exhaust) +qed + +hide_const (open) Map.empty Map.graph end diff --git a/src/HOL/Relation.thy b/src/HOL/Relation.thy --- a/src/HOL/Relation.thy +++ b/src/HOL/Relation.thy @@ -1,1250 +1,1253 @@ (* Title: HOL/Relation.thy Author: Lawrence C Paulson, Cambridge University Computer Laboratory Author: Stefan Berghofer, TU Muenchen *) section \Relations -- as sets of pairs, and binary predicates\ theory Relation imports Finite_Set begin text \A preliminary: classical rules for reasoning on predicates\ declare predicate1I [Pure.intro!, intro!] declare predicate1D [Pure.dest, dest] declare predicate2I [Pure.intro!, intro!] declare predicate2D [Pure.dest, dest] declare bot1E [elim!] declare bot2E [elim!] declare top1I [intro!] declare top2I [intro!] declare inf1I [intro!] declare inf2I [intro!] declare inf1E [elim!] declare inf2E [elim!] declare sup1I1 [intro?] declare sup2I1 [intro?] declare sup1I2 [intro?] declare sup2I2 [intro?] declare sup1E [elim!] declare sup2E [elim!] declare sup1CI [intro!] declare sup2CI [intro!] declare Inf1_I [intro!] declare INF1_I [intro!] declare Inf2_I [intro!] declare INF2_I [intro!] declare Inf1_D [elim] declare INF1_D [elim] declare Inf2_D [elim] declare INF2_D [elim] declare Inf1_E [elim] declare INF1_E [elim] declare Inf2_E [elim] declare INF2_E [elim] declare Sup1_I [intro] declare SUP1_I [intro] declare Sup2_I [intro] declare SUP2_I [intro] declare Sup1_E [elim!] declare SUP1_E [elim!] declare Sup2_E [elim!] declare SUP2_E [elim!] subsection \Fundamental\ subsubsection \Relations as sets of pairs\ type_synonym 'a rel = "('a \ 'a) set" lemma subrelI: "(\x y. (x, y) \ r \ (x, y) \ s) \ r \ s" \ \Version of @{thm [source] subsetI} for binary relations\ by auto lemma lfp_induct2: "(a, b) \ lfp f \ mono f \ (\a b. (a, b) \ f (lfp f \ {(x, y). P x y}) \ P a b) \ P a b" \ \Version of @{thm [source] lfp_induct} for binary relations\ using lfp_induct_set [of "(a, b)" f "case_prod P"] by auto subsubsection \Conversions between set and predicate relations\ lemma pred_equals_eq [pred_set_conv]: "(\x. x \ R) = (\x. x \ S) \ R = S" by (simp add: set_eq_iff fun_eq_iff) lemma pred_equals_eq2 [pred_set_conv]: "(\x y. (x, y) \ R) = (\x y. (x, y) \ S) \ R = S" by (simp add: set_eq_iff fun_eq_iff) lemma pred_subset_eq [pred_set_conv]: "(\x. x \ R) \ (\x. x \ S) \ R \ S" by (simp add: subset_iff le_fun_def) lemma pred_subset_eq2 [pred_set_conv]: "(\x y. (x, y) \ R) \ (\x y. (x, y) \ S) \ R \ S" by (simp add: subset_iff le_fun_def) lemma bot_empty_eq [pred_set_conv]: "\ = (\x. x \ {})" by (auto simp add: fun_eq_iff) lemma bot_empty_eq2 [pred_set_conv]: "\ = (\x y. (x, y) \ {})" by (auto simp add: fun_eq_iff) lemma top_empty_eq [pred_set_conv]: "\ = (\x. x \ UNIV)" by (auto simp add: fun_eq_iff) lemma top_empty_eq2 [pred_set_conv]: "\ = (\x y. (x, y) \ UNIV)" by (auto simp add: fun_eq_iff) lemma inf_Int_eq [pred_set_conv]: "(\x. x \ R) \ (\x. x \ S) = (\x. x \ R \ S)" by (simp add: inf_fun_def) lemma inf_Int_eq2 [pred_set_conv]: "(\x y. (x, y) \ R) \ (\x y. (x, y) \ S) = (\x y. (x, y) \ R \ S)" by (simp add: inf_fun_def) lemma sup_Un_eq [pred_set_conv]: "(\x. x \ R) \ (\x. x \ S) = (\x. x \ R \ S)" by (simp add: sup_fun_def) lemma sup_Un_eq2 [pred_set_conv]: "(\x y. (x, y) \ R) \ (\x y. (x, y) \ S) = (\x y. (x, y) \ R \ S)" by (simp add: sup_fun_def) lemma INF_INT_eq [pred_set_conv]: "(\i\S. (\x. x \ r i)) = (\x. x \ (\i\S. r i))" by (simp add: fun_eq_iff) lemma INF_INT_eq2 [pred_set_conv]: "(\i\S. (\x y. (x, y) \ r i)) = (\x y. (x, y) \ (\i\S. r i))" by (simp add: fun_eq_iff) lemma SUP_UN_eq [pred_set_conv]: "(\i\S. (\x. x \ r i)) = (\x. x \ (\i\S. r i))" by (simp add: fun_eq_iff) lemma SUP_UN_eq2 [pred_set_conv]: "(\i\S. (\x y. (x, y) \ r i)) = (\x y. (x, y) \ (\i\S. r i))" by (simp add: fun_eq_iff) lemma Inf_INT_eq [pred_set_conv]: "\S = (\x. x \ (\(Collect ` S)))" by (simp add: fun_eq_iff) lemma INF_Int_eq [pred_set_conv]: "(\i\S. (\x. x \ i)) = (\x. x \ \S)" by (simp add: fun_eq_iff) lemma Inf_INT_eq2 [pred_set_conv]: "\S = (\x y. (x, y) \ (\(Collect ` case_prod ` S)))" by (simp add: fun_eq_iff) lemma INF_Int_eq2 [pred_set_conv]: "(\i\S. (\x y. (x, y) \ i)) = (\x y. (x, y) \ \S)" by (simp add: fun_eq_iff) lemma Sup_SUP_eq [pred_set_conv]: "\S = (\x. x \ \(Collect ` S))" by (simp add: fun_eq_iff) lemma SUP_Sup_eq [pred_set_conv]: "(\i\S. (\x. x \ i)) = (\x. x \ \S)" by (simp add: fun_eq_iff) lemma Sup_SUP_eq2 [pred_set_conv]: "\S = (\x y. (x, y) \ (\(Collect ` case_prod ` S)))" by (simp add: fun_eq_iff) lemma SUP_Sup_eq2 [pred_set_conv]: "(\i\S. (\x y. (x, y) \ i)) = (\x y. (x, y) \ \S)" by (simp add: fun_eq_iff) subsection \Properties of relations\ subsubsection \Reflexivity\ definition refl_on :: "'a set \ 'a rel \ bool" where "refl_on A r \ r \ A \ A \ (\x\A. (x, x) \ r)" abbreviation refl :: "'a rel \ bool" \ \reflexivity over a type\ where "refl \ refl_on UNIV" definition reflp :: "('a \ 'a \ bool) \ bool" where "reflp r \ (\x. r x x)" lemma reflp_refl_eq [pred_set_conv]: "reflp (\x y. (x, y) \ r) \ refl r" by (simp add: refl_on_def reflp_def) lemma refl_onI [intro?]: "r \ A \ A \ (\x. x \ A \ (x, x) \ r) \ refl_on A r" unfolding refl_on_def by (iprover intro!: ballI) lemma refl_onD: "refl_on A r \ a \ A \ (a, a) \ r" unfolding refl_on_def by blast lemma refl_onD1: "refl_on A r \ (x, y) \ r \ x \ A" unfolding refl_on_def by blast lemma refl_onD2: "refl_on A r \ (x, y) \ r \ y \ A" unfolding refl_on_def by blast lemma reflpI [intro?]: "(\x. r x x) \ reflp r" by (auto intro: refl_onI simp add: reflp_def) lemma reflpE: assumes "reflp r" obtains "r x x" using assms by (auto dest: refl_onD simp add: reflp_def) lemma reflpD [dest?]: assumes "reflp r" shows "r x x" using assms by (auto elim: reflpE) lemma refl_on_Int: "refl_on A r \ refl_on B s \ refl_on (A \ B) (r \ s)" unfolding refl_on_def by blast lemma reflp_inf: "reflp r \ reflp s \ reflp (r \ s)" by (auto intro: reflpI elim: reflpE) lemma refl_on_Un: "refl_on A r \ refl_on B s \ refl_on (A \ B) (r \ s)" unfolding refl_on_def by blast lemma reflp_sup: "reflp r \ reflp s \ reflp (r \ s)" by (auto intro: reflpI elim: reflpE) lemma refl_on_INTER: "\x\S. refl_on (A x) (r x) \ refl_on (\(A ` S)) (\(r ` S))" unfolding refl_on_def by fast lemma refl_on_UNION: "\x\S. refl_on (A x) (r x) \ refl_on (\(A ` S)) (\(r ` S))" unfolding refl_on_def by blast lemma refl_on_empty [simp]: "refl_on {} {}" by (simp add: refl_on_def) lemma refl_on_singleton [simp]: "refl_on {x} {(x, x)}" by (blast intro: refl_onI) lemma refl_on_def' [nitpick_unfold, code]: "refl_on A r \ (\(x, y) \ r. x \ A \ y \ A) \ (\x \ A. (x, x) \ r)" by (auto intro: refl_onI dest: refl_onD refl_onD1 refl_onD2) lemma reflp_equality [simp]: "reflp (=)" by (simp add: reflp_def) lemma reflp_mono: "reflp R \ (\x y. R x y \ Q x y) \ reflp Q" by (auto intro: reflpI dest: reflpD) subsubsection \Irreflexivity\ definition irrefl :: "'a rel \ bool" where "irrefl r \ (\a. (a, a) \ r)" definition irreflp :: "('a \ 'a \ bool) \ bool" where "irreflp R \ (\a. \ R a a)" lemma irreflp_irrefl_eq [pred_set_conv]: "irreflp (\a b. (a, b) \ R) \ irrefl R" by (simp add: irrefl_def irreflp_def) lemma irreflI [intro?]: "(\a. (a, a) \ R) \ irrefl R" by (simp add: irrefl_def) lemma irreflpI [intro?]: "(\a. \ R a a) \ irreflp R" by (fact irreflI [to_pred]) lemma irrefl_distinct [code]: "irrefl r \ (\(a, b) \ r. a \ b)" by (auto simp add: irrefl_def) subsubsection \Asymmetry\ inductive asym :: "'a rel \ bool" where asymI: "(\a b. (a, b) \ R \ (b, a) \ R) \ asym R" inductive asymp :: "('a \ 'a \ bool) \ bool" where asympI: "(\a b. R a b \ \ R b a) \ asymp R" lemma asymp_asym_eq [pred_set_conv]: "asymp (\a b. (a, b) \ R) \ asym R" by (auto intro!: asymI asympI elim: asym.cases asymp.cases simp add: irreflp_irrefl_eq) lemma asymD: "\asym R; (x,y) \ R\ \ (y,x) \ R" by (simp add: asym.simps) lemma asym_iff: "asym R \ (\x y. (x,y) \ R \ (y,x) \ R)" by (blast intro: asymI dest: asymD) subsubsection \Symmetry\ definition sym :: "'a rel \ bool" where "sym r \ (\x y. (x, y) \ r \ (y, x) \ r)" definition symp :: "('a \ 'a \ bool) \ bool" where "symp r \ (\x y. r x y \ r y x)" lemma symp_sym_eq [pred_set_conv]: "symp (\x y. (x, y) \ r) \ sym r" by (simp add: sym_def symp_def) lemma symI [intro?]: "(\a b. (a, b) \ r \ (b, a) \ r) \ sym r" by (unfold sym_def) iprover lemma sympI [intro?]: "(\a b. r a b \ r b a) \ symp r" by (fact symI [to_pred]) lemma symE: assumes "sym r" and "(b, a) \ r" obtains "(a, b) \ r" using assms by (simp add: sym_def) lemma sympE: assumes "symp r" and "r b a" obtains "r a b" using assms by (rule symE [to_pred]) lemma symD [dest?]: assumes "sym r" and "(b, a) \ r" shows "(a, b) \ r" using assms by (rule symE) lemma sympD [dest?]: assumes "symp r" and "r b a" shows "r a b" using assms by (rule symD [to_pred]) lemma sym_Int: "sym r \ sym s \ sym (r \ s)" by (fast intro: symI elim: symE) lemma symp_inf: "symp r \ symp s \ symp (r \ s)" by (fact sym_Int [to_pred]) lemma sym_Un: "sym r \ sym s \ sym (r \ s)" by (fast intro: symI elim: symE) lemma symp_sup: "symp r \ symp s \ symp (r \ s)" by (fact sym_Un [to_pred]) lemma sym_INTER: "\x\S. sym (r x) \ sym (\(r ` S))" by (fast intro: symI elim: symE) lemma symp_INF: "\x\S. symp (r x) \ symp (\(r ` S))" by (fact sym_INTER [to_pred]) lemma sym_UNION: "\x\S. sym (r x) \ sym (\(r ` S))" by (fast intro: symI elim: symE) lemma symp_SUP: "\x\S. symp (r x) \ symp (\(r ` S))" by (fact sym_UNION [to_pred]) subsubsection \Antisymmetry\ definition antisym :: "'a rel \ bool" where "antisym r \ (\x y. (x, y) \ r \ (y, x) \ r \ x = y)" definition antisymp :: "('a \ 'a \ bool) \ bool" where "antisymp r \ (\x y. r x y \ r y x \ x = y)" lemma antisymp_antisym_eq [pred_set_conv]: "antisymp (\x y. (x, y) \ r) \ antisym r" by (simp add: antisym_def antisymp_def) lemma antisymI [intro?]: "(\x y. (x, y) \ r \ (y, x) \ r \ x = y) \ antisym r" unfolding antisym_def by iprover lemma antisympI [intro?]: "(\x y. r x y \ r y x \ x = y) \ antisymp r" by (fact antisymI [to_pred]) lemma antisymD [dest?]: "antisym r \ (a, b) \ r \ (b, a) \ r \ a = b" unfolding antisym_def by iprover lemma antisympD [dest?]: "antisymp r \ r a b \ r b a \ a = b" by (fact antisymD [to_pred]) lemma antisym_subset: "r \ s \ antisym s \ antisym r" unfolding antisym_def by blast lemma antisymp_less_eq: "r \ s \ antisymp s \ antisymp r" by (fact antisym_subset [to_pred]) lemma antisym_empty [simp]: "antisym {}" unfolding antisym_def by blast lemma antisym_bot [simp]: "antisymp \" by (fact antisym_empty [to_pred]) lemma antisymp_equality [simp]: "antisymp HOL.eq" by (auto intro: antisympI) lemma antisym_singleton [simp]: "antisym {x}" by (blast intro: antisymI) subsubsection \Transitivity\ definition trans :: "'a rel \ bool" where "trans r \ (\x y z. (x, y) \ r \ (y, z) \ r \ (x, z) \ r)" definition transp :: "('a \ 'a \ bool) \ bool" where "transp r \ (\x y z. r x y \ r y z \ r x z)" lemma transp_trans_eq [pred_set_conv]: "transp (\x y. (x, y) \ r) \ trans r" by (simp add: trans_def transp_def) lemma transI [intro?]: "(\x y z. (x, y) \ r \ (y, z) \ r \ (x, z) \ r) \ trans r" by (unfold trans_def) iprover lemma transpI [intro?]: "(\x y z. r x y \ r y z \ r x z) \ transp r" by (fact transI [to_pred]) lemma transE: assumes "trans r" and "(x, y) \ r" and "(y, z) \ r" obtains "(x, z) \ r" using assms by (unfold trans_def) iprover lemma transpE: assumes "transp r" and "r x y" and "r y z" obtains "r x z" using assms by (rule transE [to_pred]) lemma transD [dest?]: assumes "trans r" and "(x, y) \ r" and "(y, z) \ r" shows "(x, z) \ r" using assms by (rule transE) lemma transpD [dest?]: assumes "transp r" and "r x y" and "r y z" shows "r x z" using assms by (rule transD [to_pred]) lemma trans_Int: "trans r \ trans s \ trans (r \ s)" by (fast intro: transI elim: transE) lemma transp_inf: "transp r \ transp s \ transp (r \ s)" by (fact trans_Int [to_pred]) lemma trans_INTER: "\x\S. trans (r x) \ trans (\(r ` S))" by (fast intro: transI elim: transD) lemma transp_INF: "\x\S. transp (r x) \ transp (\(r ` S))" by (fact trans_INTER [to_pred]) lemma trans_join [code]: "trans r \ (\(x, y1) \ r. \(y2, z) \ r. y1 = y2 \ (x, z) \ r)" by (auto simp add: trans_def) lemma transp_trans: "transp r \ trans {(x, y). r x y}" by (simp add: trans_def transp_def) lemma transp_equality [simp]: "transp (=)" by (auto intro: transpI) lemma trans_empty [simp]: "trans {}" by (blast intro: transI) lemma transp_empty [simp]: "transp (\x y. False)" using trans_empty[to_pred] by (simp add: bot_fun_def) lemma trans_singleton [simp]: "trans {(a, a)}" by (blast intro: transI) lemma transp_singleton [simp]: "transp (\x y. x = a \ y = a)" by (simp add: transp_def) context preorder begin lemma transp_le[simp]: "transp (\)" by(auto simp add: transp_def intro: order_trans) lemma transp_less[simp]: "transp (<)" by(auto simp add: transp_def intro: less_trans) lemma transp_ge[simp]: "transp (\)" by(auto simp add: transp_def intro: order_trans) lemma transp_gr[simp]: "transp (>)" by(auto simp add: transp_def intro: less_trans) end subsubsection \Totality\ definition total_on :: "'a set \ 'a rel \ bool" where "total_on A r \ (\x\A. \y\A. x \ y \ (x, y) \ r \ (y, x) \ r)" lemma total_onI [intro?]: "(\x y. \x \ A; y \ A; x \ y\ \ (x, y) \ r \ (y, x) \ r) \ total_on A r" unfolding total_on_def by blast abbreviation "total \ total_on UNIV" lemma total_on_empty [simp]: "total_on {} r" by (simp add: total_on_def) lemma total_on_singleton [simp]: "total_on {x} {(x, x)}" unfolding total_on_def by blast subsubsection \Single valued relations\ definition single_valued :: "('a \ 'b) set \ bool" where "single_valued r \ (\x y. (x, y) \ r \ (\z. (x, z) \ r \ y = z))" definition single_valuedp :: "('a \ 'b \ bool) \ bool" where "single_valuedp r \ (\x y. r x y \ (\z. r x z \ y = z))" lemma single_valuedp_single_valued_eq [pred_set_conv]: "single_valuedp (\x y. (x, y) \ r) \ single_valued r" by (simp add: single_valued_def single_valuedp_def) lemma single_valuedp_iff_Uniq: "single_valuedp r \ (\x. \\<^sub>\\<^sub>1y. r x y)" unfolding Uniq_def single_valuedp_def by auto lemma single_valuedI: "(\x y. (x, y) \ r \ (\z. (x, z) \ r \ y = z)) \ single_valued r" unfolding single_valued_def by blast lemma single_valuedpI: "(\x y. r x y \ (\z. r x z \ y = z)) \ single_valuedp r" by (fact single_valuedI [to_pred]) lemma single_valuedD: "single_valued r \ (x, y) \ r \ (x, z) \ r \ y = z" by (simp add: single_valued_def) lemma single_valuedpD: "single_valuedp r \ r x y \ r x z \ y = z" by (fact single_valuedD [to_pred]) lemma single_valued_empty [simp]: "single_valued {}" by (simp add: single_valued_def) lemma single_valuedp_bot [simp]: "single_valuedp \" by (fact single_valued_empty [to_pred]) lemma single_valued_subset: "r \ s \ single_valued s \ single_valued r" unfolding single_valued_def by blast lemma single_valuedp_less_eq: "r \ s \ single_valuedp s \ single_valuedp r" by (fact single_valued_subset [to_pred]) subsection \Relation operations\ subsubsection \The identity relation\ definition Id :: "'a rel" where "Id = {p. \x. p = (x, x)}" lemma IdI [intro]: "(a, a) \ Id" by (simp add: Id_def) lemma IdE [elim!]: "p \ Id \ (\x. p = (x, x) \ P) \ P" unfolding Id_def by (iprover elim: CollectE) lemma pair_in_Id_conv [iff]: "(a, b) \ Id \ a = b" unfolding Id_def by blast lemma refl_Id: "refl Id" by (simp add: refl_on_def) lemma antisym_Id: "antisym Id" \ \A strange result, since \Id\ is also symmetric.\ by (simp add: antisym_def) lemma sym_Id: "sym Id" by (simp add: sym_def) lemma trans_Id: "trans Id" by (simp add: trans_def) lemma single_valued_Id [simp]: "single_valued Id" by (unfold single_valued_def) blast lemma irrefl_diff_Id [simp]: "irrefl (r - Id)" by (simp add: irrefl_def) lemma trans_diff_Id: "trans r \ antisym r \ trans (r - Id)" unfolding antisym_def trans_def by blast lemma total_on_diff_Id [simp]: "total_on A (r - Id) = total_on A r" by (simp add: total_on_def) lemma Id_fstsnd_eq: "Id = {x. fst x = snd x}" by force subsubsection \Diagonal: identity over a set\ definition Id_on :: "'a set \ 'a rel" where "Id_on A = (\x\A. {(x, x)})" lemma Id_on_empty [simp]: "Id_on {} = {}" by (simp add: Id_on_def) lemma Id_on_eqI: "a = b \ a \ A \ (a, b) \ Id_on A" by (simp add: Id_on_def) lemma Id_onI [intro!]: "a \ A \ (a, a) \ Id_on A" by (rule Id_on_eqI) (rule refl) lemma Id_onE [elim!]: "c \ Id_on A \ (\x. x \ A \ c = (x, x) \ P) \ P" \ \The general elimination rule.\ unfolding Id_on_def by (iprover elim!: UN_E singletonE) lemma Id_on_iff: "(x, y) \ Id_on A \ x = y \ x \ A" by blast lemma Id_on_def' [nitpick_unfold]: "Id_on {x. A x} = Collect (\(x, y). x = y \ A x)" by auto lemma Id_on_subset_Times: "Id_on A \ A \ A" by blast lemma refl_on_Id_on: "refl_on A (Id_on A)" by (rule refl_onI [OF Id_on_subset_Times Id_onI]) lemma antisym_Id_on [simp]: "antisym (Id_on A)" unfolding antisym_def by blast lemma sym_Id_on [simp]: "sym (Id_on A)" by (rule symI) clarify lemma trans_Id_on [simp]: "trans (Id_on A)" by (fast intro: transI elim: transD) lemma single_valued_Id_on [simp]: "single_valued (Id_on A)" unfolding single_valued_def by blast subsubsection \Composition\ inductive_set relcomp :: "('a \ 'b) set \ ('b \ 'c) set \ ('a \ 'c) set" (infixr "O" 75) for r :: "('a \ 'b) set" and s :: "('b \ 'c) set" where relcompI [intro]: "(a, b) \ r \ (b, c) \ s \ (a, c) \ r O s" notation relcompp (infixr "OO" 75) lemmas relcomppI = relcompp.intros text \ For historic reasons, the elimination rules are not wholly corresponding. Feel free to consolidate this. \ inductive_cases relcompEpair: "(a, c) \ r O s" inductive_cases relcomppE [elim!]: "(r OO s) a c" lemma relcompE [elim!]: "xz \ r O s \ (\x y z. xz = (x, z) \ (x, y) \ r \ (y, z) \ s \ P) \ P" apply (cases xz) apply simp apply (erule relcompEpair) apply iprover done lemma R_O_Id [simp]: "R O Id = R" by fast lemma Id_O_R [simp]: "Id O R = R" by fast lemma relcomp_empty1 [simp]: "{} O R = {}" by blast lemma relcompp_bot1 [simp]: "\ OO R = \" by (fact relcomp_empty1 [to_pred]) lemma relcomp_empty2 [simp]: "R O {} = {}" by blast lemma relcompp_bot2 [simp]: "R OO \ = \" by (fact relcomp_empty2 [to_pred]) lemma O_assoc: "(R O S) O T = R O (S O T)" by blast lemma relcompp_assoc: "(r OO s) OO t = r OO (s OO t)" by (fact O_assoc [to_pred]) lemma trans_O_subset: "trans r \ r O r \ r" by (unfold trans_def) blast lemma transp_relcompp_less_eq: "transp r \ r OO r \ r " by (fact trans_O_subset [to_pred]) lemma relcomp_mono: "r' \ r \ s' \ s \ r' O s' \ r O s" by blast lemma relcompp_mono: "r' \ r \ s' \ s \ r' OO s' \ r OO s " by (fact relcomp_mono [to_pred]) lemma relcomp_subset_Sigma: "r \ A \ B \ s \ B \ C \ r O s \ A \ C" by blast lemma relcomp_distrib [simp]: "R O (S \ T) = (R O S) \ (R O T)" by auto lemma relcompp_distrib [simp]: "R OO (S \ T) = R OO S \ R OO T" by (fact relcomp_distrib [to_pred]) lemma relcomp_distrib2 [simp]: "(S \ T) O R = (S O R) \ (T O R)" by auto lemma relcompp_distrib2 [simp]: "(S \ T) OO R = S OO R \ T OO R" by (fact relcomp_distrib2 [to_pred]) lemma relcomp_UNION_distrib: "s O \(r ` I) = (\i\I. s O r i) " by auto lemma relcompp_SUP_distrib: "s OO \(r ` I) = (\i\I. s OO r i)" by (fact relcomp_UNION_distrib [to_pred]) lemma relcomp_UNION_distrib2: "\(r ` I) O s = (\i\I. r i O s) " by auto lemma relcompp_SUP_distrib2: "\(r ` I) OO s = (\i\I. r i OO s)" by (fact relcomp_UNION_distrib2 [to_pred]) lemma single_valued_relcomp: "single_valued r \ single_valued s \ single_valued (r O s)" unfolding single_valued_def by blast lemma relcomp_unfold: "r O s = {(x, z). \y. (x, y) \ r \ (y, z) \ s}" by (auto simp add: set_eq_iff) lemma relcompp_apply: "(R OO S) a c \ (\b. R a b \ S b c)" unfolding relcomp_unfold [to_pred] .. lemma eq_OO: "(=) OO R = R" by blast lemma OO_eq: "R OO (=) = R" by blast subsubsection \Converse\ inductive_set converse :: "('a \ 'b) set \ ('b \ 'a) set" ("(_\)" [1000] 999) for r :: "('a \ 'b) set" where "(a, b) \ r \ (b, a) \ r\" notation conversep ("(_\\)" [1000] 1000) notation (ASCII) converse ("(_^-1)" [1000] 999) and conversep ("(_^--1)" [1000] 1000) lemma converseI [sym]: "(a, b) \ r \ (b, a) \ r\" by (fact converse.intros) lemma conversepI (* CANDIDATE [sym] *): "r a b \ r\\ b a" by (fact conversep.intros) lemma converseD [sym]: "(a, b) \ r\ \ (b, a) \ r" by (erule converse.cases) iprover lemma conversepD (* CANDIDATE [sym] *): "r\\ b a \ r a b" by (fact converseD [to_pred]) lemma converseE [elim!]: "yx \ r\ \ (\x y. yx = (y, x) \ (x, y) \ r \ P) \ P" \ \More general than \converseD\, as it ``splits'' the member of the relation.\ apply (cases yx) apply simp apply (erule converse.cases) apply iprover done lemmas conversepE [elim!] = conversep.cases lemma converse_iff [iff]: "(a, b) \ r\ \ (b, a) \ r" by (auto intro: converseI) lemma conversep_iff [iff]: "r\\ a b = r b a" by (fact converse_iff [to_pred]) lemma converse_converse [simp]: "(r\)\ = r" by (simp add: set_eq_iff) lemma conversep_conversep [simp]: "(r\\)\\ = r" by (fact converse_converse [to_pred]) lemma converse_empty[simp]: "{}\ = {}" by auto lemma converse_UNIV[simp]: "UNIV\ = UNIV" by auto lemma converse_relcomp: "(r O s)\ = s\ O r\" by blast lemma converse_relcompp: "(r OO s)\\ = s\\ OO r\\" by (iprover intro: order_antisym conversepI relcomppI elim: relcomppE dest: conversepD) lemma converse_Int: "(r \ s)\ = r\ \ s\" by blast lemma converse_meet: "(r \ s)\\ = r\\ \ s\\" by (simp add: inf_fun_def) (iprover intro: conversepI ext dest: conversepD) lemma converse_Un: "(r \ s)\ = r\ \ s\" by blast lemma converse_join: "(r \ s)\\ = r\\ \ s\\" by (simp add: sup_fun_def) (iprover intro: conversepI ext dest: conversepD) lemma converse_INTER: "(\(r ` S))\ = (\x\S. (r x)\)" by fast lemma converse_UNION: "(\(r ` S))\ = (\x\S. (r x)\)" by blast lemma converse_mono[simp]: "r\ \ s \ \ r \ s" by auto lemma conversep_mono[simp]: "r\\ \ s \\ \ r \ s" by (fact converse_mono[to_pred]) lemma converse_inject[simp]: "r\ = s \ \ r = s" by auto lemma conversep_inject[simp]: "r\\ = s \\ \ r = s" by (fact converse_inject[to_pred]) lemma converse_subset_swap: "r \ s \ \ r \ \ s" by auto lemma conversep_le_swap: "r \ s \\ \ r \\ \ s" by (fact converse_subset_swap[to_pred]) lemma converse_Id [simp]: "Id\ = Id" by blast lemma converse_Id_on [simp]: "(Id_on A)\ = Id_on A" by blast lemma refl_on_converse [simp]: "refl_on A (converse r) = refl_on A r" by (auto simp: refl_on_def) lemma sym_converse [simp]: "sym (converse r) = sym r" unfolding sym_def by blast lemma antisym_converse [simp]: "antisym (converse r) = antisym r" unfolding antisym_def by blast lemma trans_converse [simp]: "trans (converse r) = trans r" unfolding trans_def by blast lemma sym_conv_converse_eq: "sym r \ r\ = r" unfolding sym_def by fast lemma sym_Un_converse: "sym (r \ r\)" unfolding sym_def by blast lemma sym_Int_converse: "sym (r \ r\)" unfolding sym_def by blast lemma total_on_converse [simp]: "total_on A (r\) = total_on A r" by (auto simp: total_on_def) lemma finite_converse [iff]: "finite (r\) = finite r" unfolding converse_def conversep_iff using [[simproc add: finite_Collect]] by (auto elim: finite_imageD simp: inj_on_def) lemma card_inverse[simp]: "card (R\) = card R" proof - have *: "\R. prod.swap ` R = R\" by auto { assume "\finite R" hence ?thesis by auto } moreover { assume "finite R" with card_image_le[of R prod.swap] card_image_le[of "R\" prod.swap] have ?thesis by (auto simp: *) } ultimately show ?thesis by blast qed lemma conversep_noteq [simp]: "(\)\\ = (\)" by (auto simp add: fun_eq_iff) lemma conversep_eq [simp]: "(=)\\ = (=)" by (auto simp add: fun_eq_iff) lemma converse_unfold [code]: "r\ = {(y, x). (x, y) \ r}" by (simp add: set_eq_iff) subsubsection \Domain, range and field\ inductive_set Domain :: "('a \ 'b) set \ 'a set" for r :: "('a \ 'b) set" where DomainI [intro]: "(a, b) \ r \ a \ Domain r" lemmas DomainPI = Domainp.DomainI inductive_cases DomainE [elim!]: "a \ Domain r" inductive_cases DomainpE [elim!]: "Domainp r a" inductive_set Range :: "('a \ 'b) set \ 'b set" for r :: "('a \ 'b) set" where RangeI [intro]: "(a, b) \ r \ b \ Range r" lemmas RangePI = Rangep.RangeI inductive_cases RangeE [elim!]: "b \ Range r" inductive_cases RangepE [elim!]: "Rangep r b" definition Field :: "'a rel \ 'a set" where "Field r = Domain r \ Range r" lemma FieldI1: "(i, j) \ R \ i \ Field R" unfolding Field_def by blast lemma FieldI2: "(i, j) \ R \ j \ Field R" unfolding Field_def by auto lemma Domain_fst [code]: "Domain r = fst ` r" by force lemma Range_snd [code]: "Range r = snd ` r" by force lemma fst_eq_Domain: "fst ` R = Domain R" by force lemma snd_eq_Range: "snd ` R = Range R" by force lemma range_fst [simp]: "range fst = UNIV" by (auto simp: fst_eq_Domain) lemma range_snd [simp]: "range snd = UNIV" by (auto simp: snd_eq_Range) lemma Domain_empty [simp]: "Domain {} = {}" by auto lemma Range_empty [simp]: "Range {} = {}" by auto lemma Field_empty [simp]: "Field {} = {}" by (simp add: Field_def) lemma Domain_empty_iff: "Domain r = {} \ r = {}" by auto lemma Range_empty_iff: "Range r = {} \ r = {}" by auto lemma Domain_insert [simp]: "Domain (insert (a, b) r) = insert a (Domain r)" by blast lemma Range_insert [simp]: "Range (insert (a, b) r) = insert b (Range r)" by blast lemma Field_insert [simp]: "Field (insert (a, b) r) = {a, b} \ Field r" by (auto simp add: Field_def) lemma Domain_iff: "a \ Domain r \ (\y. (a, y) \ r)" by blast lemma Range_iff: "a \ Range r \ (\y. (y, a) \ r)" by blast lemma Domain_Id [simp]: "Domain Id = UNIV" by blast lemma Range_Id [simp]: "Range Id = UNIV" by blast lemma Domain_Id_on [simp]: "Domain (Id_on A) = A" by blast lemma Range_Id_on [simp]: "Range (Id_on A) = A" by blast lemma Domain_Un_eq: "Domain (A \ B) = Domain A \ Domain B" by blast lemma Range_Un_eq: "Range (A \ B) = Range A \ Range B" by blast lemma Field_Un [simp]: "Field (r \ s) = Field r \ Field s" by (auto simp: Field_def) lemma Domain_Int_subset: "Domain (A \ B) \ Domain A \ Domain B" by blast lemma Range_Int_subset: "Range (A \ B) \ Range A \ Range B" by blast lemma Domain_Diff_subset: "Domain A - Domain B \ Domain (A - B)" by blast lemma Range_Diff_subset: "Range A - Range B \ Range (A - B)" by blast lemma Domain_Union: "Domain (\S) = (\A\S. Domain A)" by blast lemma Range_Union: "Range (\S) = (\A\S. Range A)" by blast lemma Field_Union [simp]: "Field (\R) = \(Field ` R)" by (auto simp: Field_def) lemma Domain_converse [simp]: "Domain (r\) = Range r" by auto lemma Range_converse [simp]: "Range (r\) = Domain r" by blast lemma Field_converse [simp]: "Field (r\) = Field r" by (auto simp: Field_def) lemma Domain_Collect_case_prod [simp]: "Domain {(x, y). P x y} = {x. \y. P x y}" by auto lemma Range_Collect_case_prod [simp]: "Range {(x, y). P x y} = {y. \x. P x y}" by auto lemma finite_Domain: "finite r \ finite (Domain r)" by (induct set: finite) auto lemma finite_Range: "finite r \ finite (Range r)" by (induct set: finite) auto lemma finite_Field: "finite r \ finite (Field r)" by (simp add: Field_def finite_Domain finite_Range) lemma Domain_mono: "r \ s \ Domain r \ Domain s" by blast lemma Range_mono: "r \ s \ Range r \ Range s" by blast lemma mono_Field: "r \ s \ Field r \ Field s" by (auto simp: Field_def Domain_def Range_def) lemma Domain_unfold: "Domain r = {x. \y. (x, y) \ r}" by blast lemma Field_square [simp]: "Field (x \ x) = x" unfolding Field_def by blast subsubsection \Image of a set under a relation\ definition Image :: "('a \ 'b) set \ 'a set \ 'b set" (infixr "``" 90) where "r `` s = {y. \x\s. (x, y) \ r}" lemma Image_iff: "b \ r``A \ (\x\A. (x, b) \ r)" by (simp add: Image_def) lemma Image_singleton: "r``{a} = {b. (a, b) \ r}" by (simp add: Image_def) lemma Image_singleton_iff [iff]: "b \ r``{a} \ (a, b) \ r" by (rule Image_iff [THEN trans]) simp lemma ImageI [intro]: "(a, b) \ r \ a \ A \ b \ r``A" unfolding Image_def by blast lemma ImageE [elim!]: "b \ r `` A \ (\x. (x, b) \ r \ x \ A \ P) \ P" unfolding Image_def by (iprover elim!: CollectE bexE) lemma rev_ImageI: "a \ A \ (a, b) \ r \ b \ r `` A" \ \This version's more effective when we already have the required \a\\ by blast lemma Image_empty1 [simp]: "{} `` X = {}" by auto lemma Image_empty2 [simp]: "R``{} = {}" by blast lemma Image_Id [simp]: "Id `` A = A" by blast lemma Image_Id_on [simp]: "Id_on A `` B = A \ B" by blast lemma Image_Int_subset: "R `` (A \ B) \ R `` A \ R `` B" by blast lemma Image_Int_eq: "single_valued (converse R) \ R `` (A \ B) = R `` A \ R `` B" by (auto simp: single_valued_def) lemma Image_Un: "R `` (A \ B) = R `` A \ R `` B" by blast lemma Un_Image: "(R \ S) `` A = R `` A \ S `` A" by blast lemma Image_subset: "r \ A \ B \ r``C \ B" by (iprover intro!: subsetI elim!: ImageE dest!: subsetD SigmaD2) lemma Image_eq_UN: "r``B = (\y\ B. r``{y})" \ \NOT suitable for rewriting\ by blast lemma Image_mono: "r' \ r \ A' \ A \ (r' `` A') \ (r `` A)" by blast lemma Image_UN: "r `` (\(B ` A)) = (\x\A. r `` (B x))" by blast lemma UN_Image: "(\i\I. X i) `` S = (\i\I. X i `` S)" by auto lemma Image_INT_subset: "(r `` (\(B ` A))) \ (\x\A. r `` (B x))" by blast text \Converse inclusion requires some assumptions\ lemma Image_INT_eq: "single_valued (r\) \ A \ {} \ r `` (\(B ` A)) = (\x\A. r `` B x)" apply (rule equalityI) apply (rule Image_INT_subset) apply (auto simp add: single_valued_def) apply blast done lemma Image_subset_eq: "r``A \ B \ A \ - ((r\) `` (- B))" by blast lemma Image_Collect_case_prod [simp]: "{(x, y). P x y} `` A = {y. \x\A. P x y}" by auto lemma Sigma_Image: "(SIGMA x:A. B x) `` X = (\x\X \ A. B x)" by auto lemma relcomp_Image: "(X O Y) `` Z = Y `` (X `` Z)" by auto lemma finite_Image[simp]: assumes "finite R" shows "finite (R `` A)" by(rule finite_subset[OF _ finite_Range[OF assms]]) auto subsubsection \Inverse image\ definition inv_image :: "'b rel \ ('a \ 'b) \ 'a rel" where "inv_image r f = {(x, y). (f x, f y) \ r}" definition inv_imagep :: "('b \ 'b \ bool) \ ('a \ 'b) \ 'a \ 'a \ bool" where "inv_imagep r f = (\x y. r (f x) (f y))" lemma [pred_set_conv]: "inv_imagep (\x y. (x, y) \ r) f = (\x y. (x, y) \ inv_image r f)" by (simp add: inv_image_def inv_imagep_def) lemma sym_inv_image: "sym r \ sym (inv_image r f)" unfolding sym_def inv_image_def by blast lemma trans_inv_image: "trans r \ trans (inv_image r f)" unfolding trans_def inv_image_def by (simp (no_asm)) blast lemma total_inv_image: "\inj f; total r\ \ total (inv_image r f)" unfolding inv_image_def total_on_def by (auto simp: inj_eq) lemma asym_inv_image: "asym R \ asym (inv_image R f)" by (simp add: inv_image_def asym_iff) lemma in_inv_image[simp]: "(x, y) \ inv_image r f \ (f x, f y) \ r" by (auto simp: inv_image_def) lemma converse_inv_image[simp]: "(inv_image R f)\ = inv_image (R\) f" unfolding inv_image_def converse_unfold by auto lemma in_inv_imagep [simp]: "inv_imagep r f x y = r (f x) (f y)" by (simp add: inv_imagep_def) subsubsection \Powerset\ definition Powp :: "('a \ bool) \ 'a set \ bool" where "Powp A = (\B. \x \ B. A x)" lemma Powp_Pow_eq [pred_set_conv]: "Powp (\x. x \ A) = (\x. x \ Pow A)" by (auto simp add: Powp_def fun_eq_iff) lemmas Powp_mono [mono] = Pow_mono [to_pred] subsubsection \Expressing relation operations via \<^const>\Finite_Set.fold\\ lemma Id_on_fold: assumes "finite A" shows "Id_on A = Finite_Set.fold (\x. Set.insert (Pair x x)) {} A" proof - interpret comp_fun_commute "\x. Set.insert (Pair x x)" by standard auto from assms show ?thesis unfolding Id_on_def by (induct A) simp_all qed lemma comp_fun_commute_Image_fold: "comp_fun_commute (\(x,y) A. if x \ S then Set.insert y A else A)" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) show ?thesis by standard (auto simp: fun_eq_iff comp_fun_commute split: prod.split) qed lemma Image_fold: assumes "finite R" shows "R `` S = Finite_Set.fold (\(x,y) A. if x \ S then Set.insert y A else A) {} R" proof - interpret comp_fun_commute "(\(x,y) A. if x \ S then Set.insert y A else A)" by (rule comp_fun_commute_Image_fold) have *: "\x F. Set.insert x F `` S = (if fst x \ S then Set.insert (snd x) (F `` S) else (F `` S))" by (force intro: rev_ImageI) show ?thesis using assms by (induct R) (auto simp: *) qed lemma insert_relcomp_union_fold: assumes "finite S" shows "{x} O S \ X = Finite_Set.fold (\(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A') X S" proof - interpret comp_fun_commute "\(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A'" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) show "comp_fun_commute (\(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A')" by standard (auto simp add: fun_eq_iff split: prod.split) qed have *: "{x} O S = {(x', z). x' = fst x \ (snd x, z) \ S}" by (auto simp: relcomp_unfold intro!: exI) show ?thesis unfolding * using \finite S\ by (induct S) (auto split: prod.split) qed lemma insert_relcomp_fold: assumes "finite S" shows "Set.insert x R O S = Finite_Set.fold (\(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A') (R O S) S" proof - have "Set.insert x R O S = ({x} O S) \ (R O S)" by auto then show ?thesis by (auto simp: insert_relcomp_union_fold [OF assms]) qed lemma comp_fun_commute_relcomp_fold: assumes "finite S" shows "comp_fun_commute (\(x,y) A. Finite_Set.fold (\(w,z) A'. if y = w then Set.insert (x,z) A' else A') A S)" proof - have *: "\a b A. Finite_Set.fold (\(w, z) A'. if b = w then Set.insert (a, z) A' else A') A S = {(a,b)} O S \ A" by (auto simp: insert_relcomp_union_fold[OF assms] cong: if_cong) show ?thesis by standard (auto simp: *) qed lemma relcomp_fold: assumes "finite R" "finite S" shows "R O S = Finite_Set.fold (\(x,y) A. Finite_Set.fold (\(w,z) A'. if y = w then Set.insert (x,z) A' else A') A S) {} R" - using assms - by (induct R) - (auto simp: comp_fun_commute.fold_insert comp_fun_commute_relcomp_fold insert_relcomp_fold - cong: if_cong) +proof - + interpret commute_relcomp_fold: comp_fun_commute + "(\(x, y) A. Finite_Set.fold (\(w, z) A'. if y = w then insert (x, z) A' else A') A S)" + by (fact comp_fun_commute_relcomp_fold[OF \finite S\]) + from assms show ?thesis + by (induct R) (auto simp: comp_fun_commute_relcomp_fold insert_relcomp_fold cong: if_cong) +qed end diff --git a/src/HOL/Topological_Spaces.thy b/src/HOL/Topological_Spaces.thy --- a/src/HOL/Topological_Spaces.thy +++ b/src/HOL/Topological_Spaces.thy @@ -1,3836 +1,3836 @@ (* Title: HOL/Topological_Spaces.thy Author: Brian Huffman Author: Johannes Hölzl *) section \Topological Spaces\ theory Topological_Spaces imports Main begin named_theorems continuous_intros "structural introduction rules for continuity" subsection \Topological space\ class "open" = fixes "open" :: "'a set \ bool" class topological_space = "open" + assumes open_UNIV [simp, intro]: "open UNIV" assumes open_Int [intro]: "open S \ open T \ open (S \ T)" assumes open_Union [intro]: "\S\K. open S \ open (\K)" begin definition closed :: "'a set \ bool" where "closed S \ open (- S)" lemma open_empty [continuous_intros, intro, simp]: "open {}" using open_Union [of "{}"] by simp lemma open_Un [continuous_intros, intro]: "open S \ open T \ open (S \ T)" using open_Union [of "{S, T}"] by simp lemma open_UN [continuous_intros, intro]: "\x\A. open (B x) \ open (\x\A. B x)" using open_Union [of "B ` A"] by simp lemma open_Inter [continuous_intros, intro]: "finite S \ \T\S. open T \ open (\S)" - by (induct set: finite) auto + by (induction set: finite) auto lemma open_INT [continuous_intros, intro]: "finite A \ \x\A. open (B x) \ open (\x\A. B x)" using open_Inter [of "B ` A"] by simp lemma openI: assumes "\x. x \ S \ \T. open T \ x \ T \ T \ S" shows "open S" proof - have "open (\{T. open T \ T \ S})" by auto moreover have "\{T. open T \ T \ S} = S" by (auto dest!: assms) ultimately show "open S" by simp qed lemma open_subopen: "open S \ (\x\S. \T. open T \ x \ T \ T \ S)" by (auto intro: openI) lemma closed_empty [continuous_intros, intro, simp]: "closed {}" unfolding closed_def by simp lemma closed_Un [continuous_intros, intro]: "closed S \ closed T \ closed (S \ T)" unfolding closed_def by auto lemma closed_UNIV [continuous_intros, intro, simp]: "closed UNIV" unfolding closed_def by simp lemma closed_Int [continuous_intros, intro]: "closed S \ closed T \ closed (S \ T)" unfolding closed_def by auto lemma closed_INT [continuous_intros, intro]: "\x\A. closed (B x) \ closed (\x\A. B x)" unfolding closed_def by auto lemma closed_Inter [continuous_intros, intro]: "\S\K. closed S \ closed (\K)" unfolding closed_def uminus_Inf by auto lemma closed_Union [continuous_intros, intro]: "finite S \ \T\S. closed T \ closed (\S)" by (induct set: finite) auto lemma closed_UN [continuous_intros, intro]: "finite A \ \x\A. closed (B x) \ closed (\x\A. B x)" using closed_Union [of "B ` A"] by simp lemma open_closed: "open S \ closed (- S)" by (simp add: closed_def) lemma closed_open: "closed S \ open (- S)" by (rule closed_def) lemma open_Diff [continuous_intros, intro]: "open S \ closed T \ open (S - T)" by (simp add: closed_open Diff_eq open_Int) lemma closed_Diff [continuous_intros, intro]: "closed S \ open T \ closed (S - T)" by (simp add: open_closed Diff_eq closed_Int) lemma open_Compl [continuous_intros, intro]: "closed S \ open (- S)" by (simp add: closed_open) lemma closed_Compl [continuous_intros, intro]: "open S \ closed (- S)" by (simp add: open_closed) lemma open_Collect_neg: "closed {x. P x} \ open {x. \ P x}" unfolding Collect_neg_eq by (rule open_Compl) lemma open_Collect_conj: assumes "open {x. P x}" "open {x. Q x}" shows "open {x. P x \ Q x}" using open_Int[OF assms] by (simp add: Int_def) lemma open_Collect_disj: assumes "open {x. P x}" "open {x. Q x}" shows "open {x. P x \ Q x}" using open_Un[OF assms] by (simp add: Un_def) lemma open_Collect_ex: "(\i. open {x. P i x}) \ open {x. \i. P i x}" using open_UN[of UNIV "\i. {x. P i x}"] unfolding Collect_ex_eq by simp lemma open_Collect_imp: "closed {x. P x} \ open {x. Q x} \ open {x. P x \ Q x}" unfolding imp_conv_disj by (intro open_Collect_disj open_Collect_neg) lemma open_Collect_const: "open {x. P}" by (cases P) auto lemma closed_Collect_neg: "open {x. P x} \ closed {x. \ P x}" unfolding Collect_neg_eq by (rule closed_Compl) lemma closed_Collect_conj: assumes "closed {x. P x}" "closed {x. Q x}" shows "closed {x. P x \ Q x}" using closed_Int[OF assms] by (simp add: Int_def) lemma closed_Collect_disj: assumes "closed {x. P x}" "closed {x. Q x}" shows "closed {x. P x \ Q x}" using closed_Un[OF assms] by (simp add: Un_def) lemma closed_Collect_all: "(\i. closed {x. P i x}) \ closed {x. \i. P i x}" using closed_INT[of UNIV "\i. {x. P i x}"] by (simp add: Collect_all_eq) lemma closed_Collect_imp: "open {x. P x} \ closed {x. Q x} \ closed {x. P x \ Q x}" unfolding imp_conv_disj by (intro closed_Collect_disj closed_Collect_neg) lemma closed_Collect_const: "closed {x. P}" by (cases P) auto end subsection \Hausdorff and other separation properties\ class t0_space = topological_space + assumes t0_space: "x \ y \ \U. open U \ \ (x \ U \ y \ U)" class t1_space = topological_space + assumes t1_space: "x \ y \ \U. open U \ x \ U \ y \ U" instance t1_space \ t0_space by standard (fast dest: t1_space) context t1_space begin lemma separation_t1: "x \ y \ (\U. open U \ x \ U \ y \ U)" using t1_space[of x y] by blast lemma closed_singleton [iff]: "closed {a}" proof - let ?T = "\{S. open S \ a \ S}" have "open ?T" by (simp add: open_Union) also have "?T = - {a}" by (auto simp add: set_eq_iff separation_t1) finally show "closed {a}" by (simp only: closed_def) qed lemma closed_insert [continuous_intros, simp]: assumes "closed S" shows "closed (insert a S)" proof - from closed_singleton assms have "closed ({a} \ S)" by (rule closed_Un) then show "closed (insert a S)" by simp qed lemma finite_imp_closed: "finite S \ closed S" by (induct pred: finite) simp_all end text \T2 spaces are also known as Hausdorff spaces.\ class t2_space = topological_space + assumes hausdorff: "x \ y \ \U V. open U \ open V \ x \ U \ y \ V \ U \ V = {}" instance t2_space \ t1_space by standard (fast dest: hausdorff) lemma (in t2_space) separation_t2: "x \ y \ (\U V. open U \ open V \ x \ U \ y \ V \ U \ V = {})" using hausdorff [of x y] by blast lemma (in t0_space) separation_t0: "x \ y \ (\U. open U \ \ (x \ U \ y \ U))" using t0_space [of x y] by blast text \A classical separation axiom for topological space, the T3 axiom -- also called regularity: if a point is not in a closed set, then there are open sets separating them.\ class t3_space = t2_space + assumes t3_space: "closed S \ y \ S \ \U V. open U \ open V \ y \ U \ S \ V \ U \ V = {}" text \A classical separation axiom for topological space, the T4 axiom -- also called normality: if two closed sets are disjoint, then there are open sets separating them.\ class t4_space = t2_space + assumes t4_space: "closed S \ closed T \ S \ T = {} \ \U V. open U \ open V \ S \ U \ T \ V \ U \ V = {}" text \T4 is stronger than T3, and weaker than metric.\ instance t4_space \ t3_space proof fix S and y::'a assume "closed S" "y \ S" then show "\U V. open U \ open V \ y \ U \ S \ V \ U \ V = {}" using t4_space[of "{y}" S] by auto qed text \A perfect space is a topological space with no isolated points.\ class perfect_space = topological_space + assumes not_open_singleton: "\ open {x}" lemma (in perfect_space) UNIV_not_singleton: "UNIV \ {x}" for x::'a by (metis (no_types) open_UNIV not_open_singleton) subsection \Generators for toplogies\ inductive generate_topology :: "'a set set \ 'a set \ bool" for S :: "'a set set" where UNIV: "generate_topology S UNIV" | Int: "generate_topology S (a \ b)" if "generate_topology S a" and "generate_topology S b" | UN: "generate_topology S (\K)" if "(\k. k \ K \ generate_topology S k)" | Basis: "generate_topology S s" if "s \ S" hide_fact (open) UNIV Int UN Basis lemma generate_topology_Union: "(\k. k \ I \ generate_topology S (K k)) \ generate_topology S (\k\I. K k)" using generate_topology.UN [of "K ` I"] by auto lemma topological_space_generate_topology: "class.topological_space (generate_topology S)" by standard (auto intro: generate_topology.intros) subsection \Order topologies\ class order_topology = order + "open" + assumes open_generated_order: "open = generate_topology (range (\a. {..< a}) \ range (\a. {a <..}))" begin subclass topological_space unfolding open_generated_order by (rule topological_space_generate_topology) lemma open_greaterThan [continuous_intros, simp]: "open {a <..}" unfolding open_generated_order by (auto intro: generate_topology.Basis) lemma open_lessThan [continuous_intros, simp]: "open {..< a}" unfolding open_generated_order by (auto intro: generate_topology.Basis) lemma open_greaterThanLessThan [continuous_intros, simp]: "open {a <..< b}" unfolding greaterThanLessThan_eq by (simp add: open_Int) end class linorder_topology = linorder + order_topology lemma closed_atMost [continuous_intros, simp]: "closed {..a}" for a :: "'a::linorder_topology" by (simp add: closed_open) lemma closed_atLeast [continuous_intros, simp]: "closed {a..}" for a :: "'a::linorder_topology" by (simp add: closed_open) lemma closed_atLeastAtMost [continuous_intros, simp]: "closed {a..b}" for a b :: "'a::linorder_topology" proof - have "{a .. b} = {a ..} \ {.. b}" by auto then show ?thesis by (simp add: closed_Int) qed lemma (in order) less_separate: assumes "x < y" shows "\a b. x \ {..< a} \ y \ {b <..} \ {..< a} \ {b <..} = {}" proof (cases "\z. x < z \ z < y") case True then obtain z where "x < z \ z < y" .. then have "x \ {..< z} \ y \ {z <..} \ {z <..} \ {..< z} = {}" by auto then show ?thesis by blast next case False with \x < y\ have "x \ {..< y}" "y \ {x <..}" "{x <..} \ {..< y} = {}" by auto then show ?thesis by blast qed instance linorder_topology \ t2_space proof fix x y :: 'a show "x \ y \ \U V. open U \ open V \ x \ U \ y \ V \ U \ V = {}" using less_separate [of x y] less_separate [of y x] by (elim neqE; metis open_lessThan open_greaterThan Int_commute) qed lemma (in linorder_topology) open_right: assumes "open S" "x \ S" and gt_ex: "x < y" shows "\b>x. {x ..< b} \ S" using assms unfolding open_generated_order proof induct case UNIV then show ?case by blast next case (Int A B) then obtain a b where "a > x" "{x ..< a} \ A" "b > x" "{x ..< b} \ B" by auto then show ?case by (auto intro!: exI[of _ "min a b"]) next case UN then show ?case by blast next case Basis then show ?case by (fastforce intro: exI[of _ y] gt_ex) qed lemma (in linorder_topology) open_left: assumes "open S" "x \ S" and lt_ex: "y < x" shows "\b S" using assms unfolding open_generated_order proof induction case UNIV then show ?case by blast next case (Int A B) then obtain a b where "a < x" "{a <.. x} \ A" "b < x" "{b <.. x} \ B" by auto then show ?case by (auto intro!: exI[of _ "max a b"]) next case UN then show ?case by blast next case Basis then show ?case by (fastforce intro: exI[of _ y] lt_ex) qed subsection \Setup some topologies\ subsubsection \Boolean is an order topology\ class discrete_topology = topological_space + assumes open_discrete: "\A. open A" instance discrete_topology < t2_space proof fix x y :: 'a assume "x \ y" then show "\U V. open U \ open V \ x \ U \ y \ V \ U \ V = {}" by (intro exI[of _ "{_}"]) (auto intro!: open_discrete) qed instantiation bool :: linorder_topology begin definition open_bool :: "bool set \ bool" where "open_bool = generate_topology (range (\a. {..< a}) \ range (\a. {a <..}))" instance by standard (rule open_bool_def) end instance bool :: discrete_topology proof fix A :: "bool set" have *: "{False <..} = {True}" "{..< True} = {False}" by auto have "A = UNIV \ A = {} \ A = {False <..} \ A = {..< True}" using subset_UNIV[of A] unfolding UNIV_bool * by blast then show "open A" by auto qed instantiation nat :: linorder_topology begin definition open_nat :: "nat set \ bool" where "open_nat = generate_topology (range (\a. {..< a}) \ range (\a. {a <..}))" instance by standard (rule open_nat_def) end instance nat :: discrete_topology proof fix A :: "nat set" have "open {n}" for n :: nat proof (cases n) case 0 moreover have "{0} = {..<1::nat}" by auto ultimately show ?thesis by auto next case (Suc n') then have "{n} = {.. {n' <..}" by auto with Suc show ?thesis by (auto intro: open_lessThan open_greaterThan) qed then have "open (\a\A. {a})" by (intro open_UN) auto then show "open A" by simp qed instantiation int :: linorder_topology begin definition open_int :: "int set \ bool" where "open_int = generate_topology (range (\a. {..< a}) \ range (\a. {a <..}))" instance by standard (rule open_int_def) end instance int :: discrete_topology proof fix A :: "int set" have "{.. {i-1 <..} = {i}" for i :: int by auto then have "open {i}" for i :: int using open_Int[OF open_lessThan[of "i + 1"] open_greaterThan[of "i - 1"]] by auto then have "open (\a\A. {a})" by (intro open_UN) auto then show "open A" by simp qed subsubsection \Topological filters\ definition (in topological_space) nhds :: "'a \ 'a filter" where "nhds a = (INF S\{S. open S \ a \ S}. principal S)" definition (in topological_space) at_within :: "'a \ 'a set \ 'a filter" ("at (_)/ within (_)" [1000, 60] 60) where "at a within s = inf (nhds a) (principal (s - {a}))" abbreviation (in topological_space) at :: "'a \ 'a filter" ("at") where "at x \ at x within (CONST UNIV)" abbreviation (in order_topology) at_right :: "'a \ 'a filter" where "at_right x \ at x within {x <..}" abbreviation (in order_topology) at_left :: "'a \ 'a filter" where "at_left x \ at x within {..< x}" lemma (in topological_space) nhds_generated_topology: "open = generate_topology T \ nhds x = (INF S\{S\T. x \ S}. principal S)" unfolding nhds_def proof (safe intro!: antisym INF_greatest) fix S assume "generate_topology T S" "x \ S" then show "(INF S\{S \ T. x \ S}. principal S) \ principal S" by induct (auto intro: INF_lower order_trans simp: inf_principal[symmetric] simp del: inf_principal) qed (auto intro!: INF_lower intro: generate_topology.intros) lemma (in topological_space) eventually_nhds: "eventually P (nhds a) \ (\S. open S \ a \ S \ (\x\S. P x))" unfolding nhds_def by (subst eventually_INF_base) (auto simp: eventually_principal) lemma eventually_eventually: "eventually (\y. eventually P (nhds y)) (nhds x) = eventually P (nhds x)" by (auto simp: eventually_nhds) lemma (in topological_space) eventually_nhds_in_open: "open s \ x \ s \ eventually (\y. y \ s) (nhds x)" by (subst eventually_nhds) blast lemma (in topological_space) eventually_nhds_x_imp_x: "eventually P (nhds x) \ P x" by (subst (asm) eventually_nhds) blast lemma (in topological_space) nhds_neq_bot [simp]: "nhds a \ bot" by (simp add: trivial_limit_def eventually_nhds) lemma (in t1_space) t1_space_nhds: "x \ y \ (\\<^sub>F x in nhds x. x \ y)" by (drule t1_space) (auto simp: eventually_nhds) lemma (in topological_space) nhds_discrete_open: "open {x} \ nhds x = principal {x}" by (auto simp: nhds_def intro!: antisym INF_greatest INF_lower2[of "{x}"]) lemma (in discrete_topology) nhds_discrete: "nhds x = principal {x}" by (simp add: nhds_discrete_open open_discrete) lemma (in discrete_topology) at_discrete: "at x within S = bot" unfolding at_within_def nhds_discrete by simp lemma (in discrete_topology) tendsto_discrete: "filterlim (f :: 'b \ 'a) (nhds y) F \ eventually (\x. f x = y) F" by (auto simp: nhds_discrete filterlim_principal) lemma (in topological_space) at_within_eq: "at x within s = (INF S\{S. open S \ x \ S}. principal (S \ s - {x}))" unfolding nhds_def at_within_def by (subst INF_inf_const2[symmetric]) (auto simp: Diff_Int_distrib) lemma (in topological_space) eventually_at_filter: "eventually P (at a within s) \ eventually (\x. x \ a \ x \ s \ P x) (nhds a)" by (simp add: at_within_def eventually_inf_principal imp_conjL[symmetric] conj_commute) lemma (in topological_space) at_le: "s \ t \ at x within s \ at x within t" unfolding at_within_def by (intro inf_mono) auto lemma (in topological_space) eventually_at_topological: "eventually P (at a within s) \ (\S. open S \ a \ S \ (\x\S. x \ a \ x \ s \ P x))" by (simp add: eventually_nhds eventually_at_filter) lemma (in topological_space) at_within_open: "a \ S \ open S \ at a within S = at a" unfolding filter_eq_iff eventually_at_topological by (metis open_Int Int_iff UNIV_I) lemma (in topological_space) at_within_open_NO_MATCH: "a \ s \ open s \ NO_MATCH UNIV s \ at a within s = at a" by (simp only: at_within_open) lemma (in topological_space) at_within_open_subset: "a \ S \ open S \ S \ T \ at a within T = at a" by (metis at_le at_within_open dual_order.antisym subset_UNIV) lemma (in topological_space) at_within_nhd: assumes "x \ S" "open S" "T \ S - {x} = U \ S - {x}" shows "at x within T = at x within U" unfolding filter_eq_iff eventually_at_filter proof (intro allI eventually_subst) have "eventually (\x. x \ S) (nhds x)" using \x \ S\ \open S\ by (auto simp: eventually_nhds) then show "\\<^sub>F n in nhds x. (n \ x \ n \ T \ P n) = (n \ x \ n \ U \ P n)" for P by eventually_elim (insert \T \ S - {x} = U \ S - {x}\, blast) qed lemma (in topological_space) at_within_empty [simp]: "at a within {} = bot" unfolding at_within_def by simp lemma (in topological_space) at_within_union: "at x within (S \ T) = sup (at x within S) (at x within T)" unfolding filter_eq_iff eventually_sup eventually_at_filter by (auto elim!: eventually_rev_mp) lemma (in topological_space) at_eq_bot_iff: "at a = bot \ open {a}" unfolding trivial_limit_def eventually_at_topological apply safe apply (case_tac "S = {a}") apply simp apply fast apply fast done lemma (in perfect_space) at_neq_bot [simp]: "at a \ bot" by (simp add: at_eq_bot_iff not_open_singleton) lemma (in order_topology) nhds_order: "nhds x = inf (INF a\{x <..}. principal {..< a}) (INF a\{..< x}. principal {a <..})" proof - have 1: "{S \ range lessThan \ range greaterThan. x \ S} = (\a. {..< a}) ` {x <..} \ (\a. {a <..}) ` {..< x}" by auto show ?thesis by (simp only: nhds_generated_topology[OF open_generated_order] INF_union 1 INF_image comp_def) qed lemma (in topological_space) filterlim_at_within_If: assumes "filterlim f G (at x within (A \ {x. P x}))" and "filterlim g G (at x within (A \ {x. \P x}))" shows "filterlim (\x. if P x then f x else g x) G (at x within A)" proof (rule filterlim_If) note assms(1) also have "at x within (A \ {x. P x}) = inf (nhds x) (principal (A \ Collect P - {x}))" by (simp add: at_within_def) also have "A \ Collect P - {x} = (A - {x}) \ Collect P" by blast also have "inf (nhds x) (principal \) = inf (at x within A) (principal (Collect P))" by (simp add: at_within_def inf_assoc) finally show "filterlim f G (inf (at x within A) (principal (Collect P)))" . next note assms(2) also have "at x within (A \ {x. \ P x}) = inf (nhds x) (principal (A \ {x. \ P x} - {x}))" by (simp add: at_within_def) also have "A \ {x. \ P x} - {x} = (A - {x}) \ {x. \ P x}" by blast also have "inf (nhds x) (principal \) = inf (at x within A) (principal {x. \ P x})" by (simp add: at_within_def inf_assoc) finally show "filterlim g G (inf (at x within A) (principal {x. \ P x}))" . qed lemma (in topological_space) filterlim_at_If: assumes "filterlim f G (at x within {x. P x})" and "filterlim g G (at x within {x. \P x})" shows "filterlim (\x. if P x then f x else g x) G (at x)" using assms by (intro filterlim_at_within_If) simp_all lemma (in linorder_topology) at_within_order: assumes "UNIV \ {x}" shows "at x within s = inf (INF a\{x <..}. principal ({..< a} \ s - {x})) (INF a\{..< x}. principal ({a <..} \ s - {x}))" proof (cases "{x <..} = {}" "{..< x} = {}" rule: case_split [case_product case_split]) case True_True have "UNIV = {..< x} \ {x} \ {x <..}" by auto with assms True_True show ?thesis by auto qed (auto simp del: inf_principal simp: at_within_def nhds_order Int_Diff inf_principal[symmetric] INF_inf_const2 inf_sup_aci[where 'a="'a filter"]) lemma (in linorder_topology) at_left_eq: "y < x \ at_left x = (INF a\{..< x}. principal {a <..< x})" by (subst at_within_order) (auto simp: greaterThan_Int_greaterThan greaterThanLessThan_eq[symmetric] min.absorb2 INF_constant intro!: INF_lower2 inf_absorb2) lemma (in linorder_topology) eventually_at_left: "y < x \ eventually P (at_left x) \ (\by>b. y < x \ P y)" unfolding at_left_eq by (subst eventually_INF_base) (auto simp: eventually_principal Ball_def) lemma (in linorder_topology) at_right_eq: "x < y \ at_right x = (INF a\{x <..}. principal {x <..< a})" by (subst at_within_order) (auto simp: lessThan_Int_lessThan greaterThanLessThan_eq[symmetric] max.absorb2 INF_constant Int_commute intro!: INF_lower2 inf_absorb1) lemma (in linorder_topology) eventually_at_right: "x < y \ eventually P (at_right x) \ (\b>x. \y>x. y < b \ P y)" unfolding at_right_eq by (subst eventually_INF_base) (auto simp: eventually_principal Ball_def) lemma eventually_at_right_less: "\\<^sub>F y in at_right (x::'a::{linorder_topology, no_top}). x < y" using gt_ex[of x] eventually_at_right[of x] by auto lemma trivial_limit_at_right_top: "at_right (top::_::{order_top,linorder_topology}) = bot" by (auto simp: filter_eq_iff eventually_at_topological) lemma trivial_limit_at_left_bot: "at_left (bot::_::{order_bot,linorder_topology}) = bot" by (auto simp: filter_eq_iff eventually_at_topological) lemma trivial_limit_at_left_real [simp]: "\ trivial_limit (at_left x)" for x :: "'a::{no_bot,dense_order,linorder_topology}" using lt_ex [of x] by safe (auto simp add: trivial_limit_def eventually_at_left dest: dense) lemma trivial_limit_at_right_real [simp]: "\ trivial_limit (at_right x)" for x :: "'a::{no_top,dense_order,linorder_topology}" using gt_ex[of x] by safe (auto simp add: trivial_limit_def eventually_at_right dest: dense) lemma (in linorder_topology) at_eq_sup_left_right: "at x = sup (at_left x) (at_right x)" by (auto simp: eventually_at_filter filter_eq_iff eventually_sup elim: eventually_elim2 eventually_mono) lemma (in linorder_topology) eventually_at_split: "eventually P (at x) \ eventually P (at_left x) \ eventually P (at_right x)" by (subst at_eq_sup_left_right) (simp add: eventually_sup) lemma (in order_topology) eventually_at_leftI: assumes "\x. x \ {a<.. P x" "a < b" shows "eventually P (at_left b)" using assms unfolding eventually_at_topological by (intro exI[of _ "{a<..}"]) auto lemma (in order_topology) eventually_at_rightI: assumes "\x. x \ {a<.. P x" "a < b" shows "eventually P (at_right a)" using assms unfolding eventually_at_topological by (intro exI[of _ "{.. (\S. open S \ x \ S \ (\x. f x \ S \ P x))" unfolding eventually_filtercomap eventually_nhds by auto lemma eventually_filtercomap_at_topological: "eventually P (filtercomap f (at A within B)) \ (\S. open S \ A \ S \ (\x. f x \ S \ B - {A} \ P x))" (is "?lhs = ?rhs") unfolding at_within_def filtercomap_inf eventually_inf_principal filtercomap_principal eventually_filtercomap_nhds eventually_principal by blast lemma eventually_at_right_field: "eventually P (at_right x) \ (\b>x. \y>x. y < b \ P y)" for x :: "'a::{linordered_field, linorder_topology}" using linordered_field_no_ub[rule_format, of x] by (auto simp: eventually_at_right) lemma eventually_at_left_field: "eventually P (at_left x) \ (\by>b. y < x \ P y)" for x :: "'a::{linordered_field, linorder_topology}" using linordered_field_no_lb[rule_format, of x] by (auto simp: eventually_at_left) subsubsection \Tendsto\ abbreviation (in topological_space) tendsto :: "('b \ 'a) \ 'a \ 'b filter \ bool" (infixr "\" 55) where "(f \ l) F \ filterlim f (nhds l) F" definition (in t2_space) Lim :: "'f filter \ ('f \ 'a) \ 'a" where "Lim A f = (THE l. (f \ l) A)" lemma (in topological_space) tendsto_eq_rhs: "(f \ x) F \ x = y \ (f \ y) F" by simp named_theorems tendsto_intros "introduction rules for tendsto" setup \ Global_Theory.add_thms_dynamic (\<^binding>\tendsto_eq_intros\, fn context => Named_Theorems.get (Context.proof_of context) \<^named_theorems>\tendsto_intros\ |> map_filter (try (fn thm => @{thm tendsto_eq_rhs} OF [thm]))) \ context topological_space begin lemma tendsto_def: "(f \ l) F \ (\S. open S \ l \ S \ eventually (\x. f x \ S) F)" unfolding nhds_def filterlim_INF filterlim_principal by auto lemma tendsto_cong: "(f \ c) F \ (g \ c) F" if "eventually (\x. f x = g x) F" by (rule filterlim_cong [OF refl refl that]) lemma tendsto_mono: "F \ F' \ (f \ l) F' \ (f \ l) F" unfolding tendsto_def le_filter_def by fast lemma tendsto_ident_at [tendsto_intros, simp, intro]: "((\x. x) \ a) (at a within s)" by (auto simp: tendsto_def eventually_at_topological) lemma tendsto_const [tendsto_intros, simp, intro]: "((\x. k) \ k) F" by (simp add: tendsto_def) lemma filterlim_at: "(LIM x F. f x :> at b within s) \ eventually (\x. f x \ s \ f x \ b) F \ (f \ b) F" by (simp add: at_within_def filterlim_inf filterlim_principal conj_commute) lemma (in -) assumes "filterlim f (nhds L) F" shows tendsto_imp_filterlim_at_right: "eventually (\x. f x > L) F \ filterlim f (at_right L) F" and tendsto_imp_filterlim_at_left: "eventually (\x. f x < L) F \ filterlim f (at_left L) F" using assms by (auto simp: filterlim_at elim: eventually_mono) lemma filterlim_at_withinI: assumes "filterlim f (nhds c) F" assumes "eventually (\x. f x \ A - {c}) F" shows "filterlim f (at c within A) F" using assms by (simp add: filterlim_at) lemma filterlim_atI: assumes "filterlim f (nhds c) F" assumes "eventually (\x. f x \ c) F" shows "filterlim f (at c) F" using assms by (intro filterlim_at_withinI) simp_all lemma topological_tendstoI: "(\S. open S \ l \ S \ eventually (\x. f x \ S) F) \ (f \ l) F" by (auto simp: tendsto_def) lemma topological_tendstoD: "(f \ l) F \ open S \ l \ S \ eventually (\x. f x \ S) F" by (auto simp: tendsto_def) lemma tendsto_bot [simp]: "(f \ a) bot" by (simp add: tendsto_def) lemma tendsto_eventually: "eventually (\x. f x = l) net \ ((\x. f x) \ l) net" by (rule topological_tendstoI) (auto elim: eventually_mono) end lemma (in topological_space) filterlim_within_subset: "filterlim f l (at x within S) \ T \ S \ filterlim f l (at x within T)" by (blast intro: filterlim_mono at_le) lemmas tendsto_within_subset = filterlim_within_subset lemma (in order_topology) order_tendsto_iff: "(f \ x) F \ (\lx. l < f x) F) \ (\u>x. eventually (\x. f x < u) F)" by (auto simp: nhds_order filterlim_inf filterlim_INF filterlim_principal) lemma (in order_topology) order_tendstoI: "(\a. a < y \ eventually (\x. a < f x) F) \ (\a. y < a \ eventually (\x. f x < a) F) \ (f \ y) F" by (auto simp: order_tendsto_iff) lemma (in order_topology) order_tendstoD: assumes "(f \ y) F" shows "a < y \ eventually (\x. a < f x) F" and "y < a \ eventually (\x. f x < a) F" using assms by (auto simp: order_tendsto_iff) lemma (in linorder_topology) tendsto_max[tendsto_intros]: assumes X: "(X \ x) net" and Y: "(Y \ y) net" shows "((\x. max (X x) (Y x)) \ max x y) net" proof (rule order_tendstoI) fix a assume "a < max x y" then show "eventually (\x. a < max (X x) (Y x)) net" using order_tendstoD(1)[OF X, of a] order_tendstoD(1)[OF Y, of a] by (auto simp: less_max_iff_disj elim: eventually_mono) next fix a assume "max x y < a" then show "eventually (\x. max (X x) (Y x) < a) net" using order_tendstoD(2)[OF X, of a] order_tendstoD(2)[OF Y, of a] by (auto simp: eventually_conj_iff) qed lemma (in linorder_topology) tendsto_min[tendsto_intros]: assumes X: "(X \ x) net" and Y: "(Y \ y) net" shows "((\x. min (X x) (Y x)) \ min x y) net" proof (rule order_tendstoI) fix a assume "a < min x y" then show "eventually (\x. a < min (X x) (Y x)) net" using order_tendstoD(1)[OF X, of a] order_tendstoD(1)[OF Y, of a] by (auto simp: eventually_conj_iff) next fix a assume "min x y < a" then show "eventually (\x. min (X x) (Y x) < a) net" using order_tendstoD(2)[OF X, of a] order_tendstoD(2)[OF Y, of a] by (auto simp: min_less_iff_disj elim: eventually_mono) qed lemma (in order_topology) assumes "a < b" shows at_within_Icc_at_right: "at a within {a..b} = at_right a" and at_within_Icc_at_left: "at b within {a..b} = at_left b" using order_tendstoD(2)[OF tendsto_ident_at assms, of "{a<..}"] using order_tendstoD(1)[OF tendsto_ident_at assms, of "{.. x < b \ at x within {a..b} = at x" by (rule at_within_open_subset[where S="{a<.. bot" and "(f \ a) F" and "(f \ b) F" shows "a = b" proof (rule ccontr) assume "a \ b" obtain U V where "open U" "open V" "a \ U" "b \ V" "U \ V = {}" using hausdorff [OF \a \ b\] by fast have "eventually (\x. f x \ U) F" using \(f \ a) F\ \open U\ \a \ U\ by (rule topological_tendstoD) moreover have "eventually (\x. f x \ V) F" using \(f \ b) F\ \open V\ \b \ V\ by (rule topological_tendstoD) ultimately have "eventually (\x. False) F" proof eventually_elim case (elim x) then have "f x \ U \ V" by simp with \U \ V = {}\ show ?case by simp qed with \\ trivial_limit F\ show "False" by (simp add: trivial_limit_def) qed lemma (in t2_space) tendsto_const_iff: fixes a b :: 'a assumes "\ trivial_limit F" shows "((\x. a) \ b) F \ a = b" by (auto intro!: tendsto_unique [OF assms tendsto_const]) lemma (in t2_space) tendsto_unique': assumes "F \ bot" shows "\\<^sub>\\<^sub>1l. (f \ l) F" using Uniq_def assms local.tendsto_unique by fastforce lemma Lim_in_closed_set: assumes "closed S" "eventually (\x. f(x) \ S) F" "F \ bot" "(f \ l) F" shows "l \ S" proof (rule ccontr) assume "l \ S" with \closed S\ have "open (- S)" "l \ - S" by (simp_all add: open_Compl) with assms(4) have "eventually (\x. f x \ - S) F" by (rule topological_tendstoD) with assms(2) have "eventually (\x. False) F" by (rule eventually_elim2) simp with assms(3) show "False" by (simp add: eventually_False) qed lemma (in t3_space) nhds_closed: assumes "x \ A" and "open A" shows "\A'. x \ A' \ closed A' \ A' \ A \ eventually (\y. y \ A') (nhds x)" proof - from assms have "\U V. open U \ open V \ x \ U \ - A \ V \ U \ V = {}" by (intro t3_space) auto then obtain U V where UV: "open U" "open V" "x \ U" "-A \ V" "U \ V = {}" by auto have "eventually (\y. y \ U) (nhds x)" using \open U\ and \x \ U\ by (intro eventually_nhds_in_open) hence "eventually (\y. y \ -V) (nhds x)" by eventually_elim (use UV in auto) with UV show ?thesis by (intro exI[of _ "-V"]) auto qed lemma (in order_topology) increasing_tendsto: assumes bdd: "eventually (\n. f n \ l) F" and en: "\x. x < l \ eventually (\n. x < f n) F" shows "(f \ l) F" using assms by (intro order_tendstoI) (auto elim!: eventually_mono) lemma (in order_topology) decreasing_tendsto: assumes bdd: "eventually (\n. l \ f n) F" and en: "\x. l < x \ eventually (\n. f n < x) F" shows "(f \ l) F" using assms by (intro order_tendstoI) (auto elim!: eventually_mono) lemma (in order_topology) tendsto_sandwich: assumes ev: "eventually (\n. f n \ g n) net" "eventually (\n. g n \ h n) net" assumes lim: "(f \ c) net" "(h \ c) net" shows "(g \ c) net" proof (rule order_tendstoI) fix a show "a < c \ eventually (\x. a < g x) net" using order_tendstoD[OF lim(1), of a] ev by (auto elim: eventually_elim2) next fix a show "c < a \ eventually (\x. g x < a) net" using order_tendstoD[OF lim(2), of a] ev by (auto elim: eventually_elim2) qed lemma (in t1_space) limit_frequently_eq: assumes "F \ bot" and "frequently (\x. f x = c) F" and "(f \ d) F" shows "d = c" proof (rule ccontr) assume "d \ c" from t1_space[OF this] obtain U where "open U" "d \ U" "c \ U" by blast with assms have "eventually (\x. f x \ U) F" unfolding tendsto_def by blast then have "eventually (\x. f x \ c) F" by eventually_elim (insert \c \ U\, blast) with assms(2) show False unfolding frequently_def by contradiction qed lemma (in t1_space) tendsto_imp_eventually_ne: assumes "(f \ c) F" "c \ c'" shows "eventually (\z. f z \ c') F" proof (cases "F=bot") case True thus ?thesis by auto next case False show ?thesis proof (rule ccontr) assume "\ eventually (\z. f z \ c') F" then have "frequently (\z. f z = c') F" by (simp add: frequently_def) from limit_frequently_eq[OF False this \(f \ c) F\] and \c \ c'\ show False by contradiction qed qed lemma (in linorder_topology) tendsto_le: assumes F: "\ trivial_limit F" and x: "(f \ x) F" and y: "(g \ y) F" and ev: "eventually (\x. g x \ f x) F" shows "y \ x" proof (rule ccontr) assume "\ y \ x" with less_separate[of x y] obtain a b where xy: "x < a" "b < y" "{.. {b<..} = {}" by (auto simp: not_le) then have "eventually (\x. f x < a) F" "eventually (\x. b < g x) F" using x y by (auto intro: order_tendstoD) with ev have "eventually (\x. False) F" by eventually_elim (insert xy, fastforce) with F show False by (simp add: eventually_False) qed lemma (in linorder_topology) tendsto_lowerbound: assumes x: "(f \ x) F" and ev: "eventually (\i. a \ f i) F" and F: "\ trivial_limit F" shows "a \ x" using F x tendsto_const ev by (rule tendsto_le) lemma (in linorder_topology) tendsto_upperbound: assumes x: "(f \ x) F" and ev: "eventually (\i. a \ f i) F" and F: "\ trivial_limit F" shows "a \ x" by (rule tendsto_le [OF F tendsto_const x ev]) lemma filterlim_at_within_not_equal: fixes f::"'a \ 'b::t2_space" assumes "filterlim f (at a within s) F" shows "eventually (\w. f w\s \ f w \b) F" proof (cases "a=b") case True then show ?thesis using assms by (simp add: filterlim_at) next case False from hausdorff[OF this] obtain U V where UV:"open U" "open V" "a \ U" "b \ V" "U \ V = {}" by auto have "(f \ a) F" using assms filterlim_at by auto then have "\\<^sub>F x in F. f x \ U" using UV unfolding tendsto_def by auto moreover have "\\<^sub>F x in F. f x \ s \ f x\a" using assms filterlim_at by auto ultimately show ?thesis apply eventually_elim using UV by auto qed subsubsection \Rules about \<^const>\Lim\\ lemma tendsto_Lim: "\ trivial_limit net \ (f \ l) net \ Lim net f = l" unfolding Lim_def using tendsto_unique [of net f] by auto lemma Lim_ident_at: "\ trivial_limit (at x within s) \ Lim (at x within s) (\x. x) = x" by (rule tendsto_Lim[OF _ tendsto_ident_at]) auto lemma eventually_Lim_ident_at: "(\\<^sub>F y in at x within X. P (Lim (at x within X) (\x. x)) y) \ (\\<^sub>F y in at x within X. P x y)" for x::"'a::t2_space" by (cases "at x within X = bot") (auto simp: Lim_ident_at) lemma filterlim_at_bot_at_right: fixes f :: "'a::linorder_topology \ 'b::linorder" assumes mono: "\x y. Q x \ Q y \ x \ y \ f x \ f y" and bij: "\x. P x \ f (g x) = x" "\x. P x \ Q (g x)" and Q: "eventually Q (at_right a)" and bound: "\b. Q b \ a < b" and P: "eventually P at_bot" shows "filterlim f at_bot (at_right a)" proof - from P obtain x where x: "\y. y \ x \ P y" unfolding eventually_at_bot_linorder by auto show ?thesis proof (intro filterlim_at_bot_le[THEN iffD2] allI impI) fix z assume "z \ x" with x have "P z" by auto have "eventually (\x. x \ g z) (at_right a)" using bound[OF bij(2)[OF \P z\]] unfolding eventually_at_right[OF bound[OF bij(2)[OF \P z\]]] by (auto intro!: exI[of _ "g z"]) with Q show "eventually (\x. f x \ z) (at_right a)" by eventually_elim (metis bij \P z\ mono) qed qed lemma filterlim_at_top_at_left: fixes f :: "'a::linorder_topology \ 'b::linorder" assumes mono: "\x y. Q x \ Q y \ x \ y \ f x \ f y" and bij: "\x. P x \ f (g x) = x" "\x. P x \ Q (g x)" and Q: "eventually Q (at_left a)" and bound: "\b. Q b \ b < a" and P: "eventually P at_top" shows "filterlim f at_top (at_left a)" proof - from P obtain x where x: "\y. x \ y \ P y" unfolding eventually_at_top_linorder by auto show ?thesis proof (intro filterlim_at_top_ge[THEN iffD2] allI impI) fix z assume "x \ z" with x have "P z" by auto have "eventually (\x. g z \ x) (at_left a)" using bound[OF bij(2)[OF \P z\]] unfolding eventually_at_left[OF bound[OF bij(2)[OF \P z\]]] by (auto intro!: exI[of _ "g z"]) with Q show "eventually (\x. z \ f x) (at_left a)" by eventually_elim (metis bij \P z\ mono) qed qed lemma filterlim_split_at: "filterlim f F (at_left x) \ filterlim f F (at_right x) \ filterlim f F (at x)" for x :: "'a::linorder_topology" by (subst at_eq_sup_left_right) (rule filterlim_sup) lemma filterlim_at_split: "filterlim f F (at x) \ filterlim f F (at_left x) \ filterlim f F (at_right x)" for x :: "'a::linorder_topology" by (subst at_eq_sup_left_right) (simp add: filterlim_def filtermap_sup) lemma eventually_nhds_top: fixes P :: "'a :: {order_top,linorder_topology} \ bool" and b :: 'a assumes "b < top" shows "eventually P (nhds top) \ (\bz. b < z \ P z))" unfolding eventually_nhds proof safe fix S :: "'a set" assume "open S" "top \ S" note open_left[OF this \b < top\] moreover assume "\s\S. P s" ultimately show "\bz>b. P z" by (auto simp: subset_eq Ball_def) next fix b assume "b < top" "\z>b. P z" then show "\S. open S \ top \ S \ (\xa\S. P xa)" by (intro exI[of _ "{b <..}"]) auto qed lemma tendsto_at_within_iff_tendsto_nhds: "(g \ g l) (at l within S) \ (g \ g l) (inf (nhds l) (principal S))" unfolding tendsto_def eventually_at_filter eventually_inf_principal by (intro ext all_cong imp_cong) (auto elim!: eventually_mono) subsection \Limits on sequences\ abbreviation (in topological_space) LIMSEQ :: "[nat \ 'a, 'a] \ bool" ("((_)/ \ (_))" [60, 60] 60) where "X \ L \ (X \ L) sequentially" abbreviation (in t2_space) lim :: "(nat \ 'a) \ 'a" where "lim X \ Lim sequentially X" definition (in topological_space) convergent :: "(nat \ 'a) \ bool" where "convergent X = (\L. X \ L)" lemma lim_def: "lim X = (THE L. X \ L)" unfolding Lim_def .. lemma lim_explicit: "f \ f0 \ (\S. open S \ f0 \ S \ (\N. \n\N. f n \ S))" unfolding tendsto_def eventually_sequentially by auto subsection \Monotone sequences and subsequences\ text \ Definition of monotonicity. The use of disjunction here complicates proofs considerably. One alternative is to add a Boolean argument to indicate the direction. Another is to develop the notions of increasing and decreasing first. \ definition monoseq :: "(nat \ 'a::order) \ bool" where "monoseq X \ (\m. \n\m. X m \ X n) \ (\m. \n\m. X n \ X m)" abbreviation incseq :: "(nat \ 'a::order) \ bool" where "incseq X \ mono X" lemma incseq_def: "incseq X \ (\m. \n\m. X n \ X m)" unfolding mono_def .. abbreviation decseq :: "(nat \ 'a::order) \ bool" where "decseq X \ antimono X" lemma decseq_def: "decseq X \ (\m. \n\m. X n \ X m)" unfolding antimono_def .. subsubsection \Definition of subsequence.\ (* For compatibility with the old "subseq" *) lemma strict_mono_leD: "strict_mono r \ m \ n \ r m \ r n" by (erule (1) monoD [OF strict_mono_mono]) lemma strict_mono_id: "strict_mono id" by (simp add: strict_mono_def) lemma incseq_SucI: "(\n. X n \ X (Suc n)) \ incseq X" using lift_Suc_mono_le[of X] by (auto simp: incseq_def) lemma incseqD: "incseq f \ i \ j \ f i \ f j" by (auto simp: incseq_def) lemma incseq_SucD: "incseq A \ A i \ A (Suc i)" using incseqD[of A i "Suc i"] by auto lemma incseq_Suc_iff: "incseq f \ (\n. f n \ f (Suc n))" by (auto intro: incseq_SucI dest: incseq_SucD) lemma incseq_const[simp, intro]: "incseq (\x. k)" unfolding incseq_def by auto lemma decseq_SucI: "(\n. X (Suc n) \ X n) \ decseq X" using order.lift_Suc_mono_le[OF dual_order, of X] by (auto simp: decseq_def) lemma decseqD: "decseq f \ i \ j \ f j \ f i" by (auto simp: decseq_def) lemma decseq_SucD: "decseq A \ A (Suc i) \ A i" using decseqD[of A i "Suc i"] by auto lemma decseq_Suc_iff: "decseq f \ (\n. f (Suc n) \ f n)" by (auto intro: decseq_SucI dest: decseq_SucD) lemma decseq_const[simp, intro]: "decseq (\x. k)" unfolding decseq_def by auto lemma monoseq_iff: "monoseq X \ incseq X \ decseq X" unfolding monoseq_def incseq_def decseq_def .. lemma monoseq_Suc: "monoseq X \ (\n. X n \ X (Suc n)) \ (\n. X (Suc n) \ X n)" unfolding monoseq_iff incseq_Suc_iff decseq_Suc_iff .. lemma monoI1: "\m. \n \ m. X m \ X n \ monoseq X" by (simp add: monoseq_def) lemma monoI2: "\m. \n \ m. X n \ X m \ monoseq X" by (simp add: monoseq_def) lemma mono_SucI1: "\n. X n \ X (Suc n) \ monoseq X" by (simp add: monoseq_Suc) lemma mono_SucI2: "\n. X (Suc n) \ X n \ monoseq X" by (simp add: monoseq_Suc) lemma monoseq_minus: fixes a :: "nat \ 'a::ordered_ab_group_add" assumes "monoseq a" shows "monoseq (\ n. - a n)" proof (cases "\m. \n \ m. a m \ a n") case True then have "\m. \n \ m. - a n \ - a m" by auto then show ?thesis by (rule monoI2) next case False then have "\m. \n \ m. - a m \ - a n" using \monoseq a\[unfolded monoseq_def] by auto then show ?thesis by (rule monoI1) qed subsubsection \Subsequence (alternative definition, (e.g. Hoskins)\ lemma strict_mono_Suc_iff: "strict_mono f \ (\n. f n < f (Suc n))" proof (intro iffI strict_monoI) assume *: "\n. f n < f (Suc n)" fix m n :: nat assume "m < n" thus "f m < f n" by (induction rule: less_Suc_induct) (use * in auto) qed (auto simp: strict_mono_def) lemma strict_mono_add: "strict_mono (\n::'a::linordered_semidom. n + k)" by (auto simp: strict_mono_def) text \For any sequence, there is a monotonic subsequence.\ lemma seq_monosub: fixes s :: "nat \ 'a::linorder" shows "\f. strict_mono f \ monoseq (\n. (s (f n)))" proof (cases "\n. \p>n. \m\p. s m \ s p") case True then have "\f. \n. (\m\f n. s m \ s (f n)) \ f n < f (Suc n)" by (intro dependent_nat_choice) (auto simp: conj_commute) then obtain f :: "nat \ nat" where f: "strict_mono f" and mono: "\n m. f n \ m \ s m \ s (f n)" by (auto simp: strict_mono_Suc_iff) then have "incseq f" unfolding strict_mono_Suc_iff incseq_Suc_iff by (auto intro: less_imp_le) then have "monoseq (\n. s (f n))" by (auto simp add: incseq_def intro!: mono monoI2) with f show ?thesis by auto next case False then obtain N where N: "p > N \ \m>p. s p < s m" for p by (force simp: not_le le_less) have "\f. \n. N < f n \ f n < f (Suc n) \ s (f n) \ s (f (Suc n))" proof (intro dependent_nat_choice) fix x assume "N < x" with N[of x] show "\y>N. x < y \ s x \ s y" by (auto intro: less_trans) qed auto then show ?thesis by (auto simp: monoseq_iff incseq_Suc_iff strict_mono_Suc_iff) qed lemma seq_suble: assumes sf: "strict_mono (f :: nat \ nat)" shows "n \ f n" proof (induct n) case 0 show ?case by simp next case (Suc n) with sf [unfolded strict_mono_Suc_iff, rule_format, of n] have "n < f (Suc n)" by arith then show ?case by arith qed lemma eventually_subseq: "strict_mono r \ eventually P sequentially \ eventually (\n. P (r n)) sequentially" unfolding eventually_sequentially by (metis seq_suble le_trans) lemma not_eventually_sequentiallyD: assumes "\ eventually P sequentially" shows "\r::nat\nat. strict_mono r \ (\n. \ P (r n))" proof - from assms have "\n. \m\n. \ P m" unfolding eventually_sequentially by (simp add: not_less) then obtain r where "\n. r n \ n" "\n. \ P (r n)" by (auto simp: choice_iff) then show ?thesis by (auto intro!: exI[of _ "\n. r (((Suc \ r) ^^ Suc n) 0)"] simp: less_eq_Suc_le strict_mono_Suc_iff) qed lemma sequentially_offset: assumes "eventually (\i. P i) sequentially" shows "eventually (\i. P (i + k)) sequentially" using assms by (rule eventually_sequentially_seg [THEN iffD2]) lemma seq_offset_neg: "(f \ l) sequentially \ ((\i. f(i - k)) \ l) sequentially" apply (erule filterlim_compose) apply (simp add: filterlim_def le_sequentially eventually_filtermap eventually_sequentially, arith) done lemma filterlim_subseq: "strict_mono f \ filterlim f sequentially sequentially" unfolding filterlim_iff by (metis eventually_subseq) lemma strict_mono_o: "strict_mono r \ strict_mono s \ strict_mono (r \ s)" unfolding strict_mono_def by simp lemma strict_mono_compose: "strict_mono r \ strict_mono s \ strict_mono (\x. r (s x))" using strict_mono_o[of r s] by (simp add: o_def) lemma incseq_imp_monoseq: "incseq X \ monoseq X" by (simp add: incseq_def monoseq_def) lemma decseq_imp_monoseq: "decseq X \ monoseq X" by (simp add: decseq_def monoseq_def) lemma decseq_eq_incseq: "decseq X = incseq (\n. - X n)" for X :: "nat \ 'a::ordered_ab_group_add" by (simp add: decseq_def incseq_def) lemma INT_decseq_offset: assumes "decseq F" shows "(\i. F i) = (\i\{n..}. F i)" proof safe fix x i assume x: "x \ (\i\{n..}. F i)" show "x \ F i" proof cases from x have "x \ F n" by auto also assume "i \ n" with \decseq F\ have "F n \ F i" unfolding decseq_def by simp finally show ?thesis . qed (insert x, simp) qed auto lemma LIMSEQ_const_iff: "(\n. k) \ l \ k = l" for k l :: "'a::t2_space" using trivial_limit_sequentially by (rule tendsto_const_iff) lemma LIMSEQ_SUP: "incseq X \ X \ (SUP i. X i :: 'a::{complete_linorder,linorder_topology})" by (intro increasing_tendsto) (auto simp: SUP_upper less_SUP_iff incseq_def eventually_sequentially intro: less_le_trans) lemma LIMSEQ_INF: "decseq X \ X \ (INF i. X i :: 'a::{complete_linorder,linorder_topology})" by (intro decreasing_tendsto) (auto simp: INF_lower INF_less_iff decseq_def eventually_sequentially intro: le_less_trans) lemma LIMSEQ_ignore_initial_segment: "f \ a \ (\n. f (n + k)) \ a" unfolding tendsto_def by (subst eventually_sequentially_seg[where k=k]) lemma LIMSEQ_offset: "(\n. f (n + k)) \ a \ f \ a" unfolding tendsto_def by (subst (asm) eventually_sequentially_seg[where k=k]) lemma LIMSEQ_Suc: "f \ l \ (\n. f (Suc n)) \ l" by (drule LIMSEQ_ignore_initial_segment [where k="Suc 0"]) simp lemma LIMSEQ_imp_Suc: "(\n. f (Suc n)) \ l \ f \ l" by (rule LIMSEQ_offset [where k="Suc 0"]) simp lemma LIMSEQ_lessThan_iff_atMost: shows "(\n. f {.. x \ (\n. f {..n}) \ x" apply (subst filterlim_sequentially_Suc [symmetric]) apply (simp only: lessThan_Suc_atMost) done lemma (in t2_space) LIMSEQ_Uniq: "\\<^sub>\\<^sub>1l. X \ l" by (simp add: tendsto_unique') lemma (in t2_space) LIMSEQ_unique: "X \ a \ X \ b \ a = b" using trivial_limit_sequentially by (rule tendsto_unique) lemma LIMSEQ_le_const: "X \ x \ \N. \n\N. a \ X n \ a \ x" for a x :: "'a::linorder_topology" by (simp add: eventually_at_top_linorder tendsto_lowerbound) lemma LIMSEQ_le: "X \ x \ Y \ y \ \N. \n\N. X n \ Y n \ x \ y" for x y :: "'a::linorder_topology" using tendsto_le[of sequentially Y y X x] by (simp add: eventually_sequentially) lemma LIMSEQ_le_const2: "X \ x \ \N. \n\N. X n \ a \ x \ a" for a x :: "'a::linorder_topology" by (rule LIMSEQ_le[of X x "\n. a"]) auto lemma Lim_bounded: "f \ l \ \n\M. f n \ C \ l \ C" for l :: "'a::linorder_topology" by (intro LIMSEQ_le_const2) auto lemma Lim_bounded2: fixes f :: "nat \ 'a::linorder_topology" assumes lim:"f \ l" and ge: "\n\N. f n \ C" shows "l \ C" using ge by (intro tendsto_le[OF trivial_limit_sequentially lim tendsto_const]) (auto simp: eventually_sequentially) lemma lim_mono: fixes X Y :: "nat \ 'a::linorder_topology" assumes "\n. N \ n \ X n \ Y n" and "X \ x" and "Y \ y" shows "x \ y" using assms(1) by (intro LIMSEQ_le[OF assms(2,3)]) auto lemma Sup_lim: fixes a :: "'a::{complete_linorder,linorder_topology}" assumes "\n. b n \ s" and "b \ a" shows "a \ Sup s" by (metis Lim_bounded assms complete_lattice_class.Sup_upper) lemma Inf_lim: fixes a :: "'a::{complete_linorder,linorder_topology}" assumes "\n. b n \ s" and "b \ a" shows "Inf s \ a" by (metis Lim_bounded2 assms complete_lattice_class.Inf_lower) lemma SUP_Lim: fixes X :: "nat \ 'a::{complete_linorder,linorder_topology}" assumes inc: "incseq X" and l: "X \ l" shows "(SUP n. X n) = l" using LIMSEQ_SUP[OF inc] tendsto_unique[OF trivial_limit_sequentially l] by simp lemma INF_Lim: fixes X :: "nat \ 'a::{complete_linorder,linorder_topology}" assumes dec: "decseq X" and l: "X \ l" shows "(INF n. X n) = l" using LIMSEQ_INF[OF dec] tendsto_unique[OF trivial_limit_sequentially l] by simp lemma convergentD: "convergent X \ \L. X \ L" by (simp add: convergent_def) lemma convergentI: "X \ L \ convergent X" by (auto simp add: convergent_def) lemma convergent_LIMSEQ_iff: "convergent X \ X \ lim X" by (auto intro: theI LIMSEQ_unique simp add: convergent_def lim_def) lemma convergent_const: "convergent (\n. c)" by (rule convergentI) (rule tendsto_const) lemma monoseq_le: "monoseq a \ a \ x \ (\n. a n \ x) \ (\m. \n\m. a m \ a n) \ (\n. x \ a n) \ (\m. \n\m. a n \ a m)" for x :: "'a::linorder_topology" by (metis LIMSEQ_le_const LIMSEQ_le_const2 decseq_def incseq_def monoseq_iff) lemma LIMSEQ_subseq_LIMSEQ: "X \ L \ strict_mono f \ (X \ f) \ L" unfolding comp_def by (rule filterlim_compose [of X, OF _ filterlim_subseq]) lemma convergent_subseq_convergent: "convergent X \ strict_mono f \ convergent (X \ f)" by (auto simp: convergent_def intro: LIMSEQ_subseq_LIMSEQ) lemma limI: "X \ L \ lim X = L" by (rule tendsto_Lim) (rule trivial_limit_sequentially) lemma lim_le: "convergent f \ (\n. f n \ x) \ lim f \ x" for x :: "'a::linorder_topology" using LIMSEQ_le_const2[of f "lim f" x] by (simp add: convergent_LIMSEQ_iff) lemma lim_const [simp]: "lim (\m. a) = a" by (simp add: limI) subsubsection \Increasing and Decreasing Series\ lemma incseq_le: "incseq X \ X \ L \ X n \ L" for L :: "'a::linorder_topology" by (metis incseq_def LIMSEQ_le_const) lemma decseq_ge: "decseq X \ X \ L \ L \ X n" for L :: "'a::linorder_topology" by (metis decseq_def LIMSEQ_le_const2) subsection \First countable topologies\ class first_countable_topology = topological_space + assumes first_countable_basis: "\A::nat \ 'a set. (\i. x \ A i \ open (A i)) \ (\S. open S \ x \ S \ (\i. A i \ S))" lemma (in first_countable_topology) countable_basis_at_decseq: obtains A :: "nat \ 'a set" where "\i. open (A i)" "\i. x \ (A i)" "\S. open S \ x \ S \ eventually (\i. A i \ S) sequentially" proof atomize_elim from first_countable_basis[of x] obtain A :: "nat \ 'a set" where nhds: "\i. open (A i)" "\i. x \ A i" and incl: "\S. open S \ x \ S \ \i. A i \ S" by auto define F where "F n = (\i\n. A i)" for n show "\A. (\i. open (A i)) \ (\i. x \ A i) \ (\S. open S \ x \ S \ eventually (\i. A i \ S) sequentially)" proof (safe intro!: exI[of _ F]) fix i show "open (F i)" using nhds(1) by (auto simp: F_def) show "x \ F i" using nhds(2) by (auto simp: F_def) next fix S assume "open S" "x \ S" from incl[OF this] obtain i where "F i \ S" unfolding F_def by auto moreover have "\j. i \ j \ F j \ F i" by (simp add: Inf_superset_mono F_def image_mono) ultimately show "eventually (\i. F i \ S) sequentially" by (auto simp: eventually_sequentially) qed qed lemma (in first_countable_topology) nhds_countable: obtains X :: "nat \ 'a set" where "decseq X" "\n. open (X n)" "\n. x \ X n" "nhds x = (INF n. principal (X n))" proof - from first_countable_basis obtain A :: "nat \ 'a set" where *: "\n. x \ A n" "\n. open (A n)" "\S. open S \ x \ S \ \i. A i \ S" by metis show thesis proof show "decseq (\n. \i\n. A i)" by (simp add: antimono_iff_le_Suc atMost_Suc) show "x \ (\i\n. A i)" "\n. open (\i\n. A i)" for n using * by auto show "nhds x = (INF n. principal (\i\n. A i))" using * unfolding nhds_def apply - apply (rule INF_eq) apply simp_all apply fastforce apply (intro exI [of _ "\i\n. A i" for n] conjI open_INT) apply auto done qed qed lemma (in first_countable_topology) countable_basis: obtains A :: "nat \ 'a set" where "\i. open (A i)" "\i. x \ A i" "\F. (\n. F n \ A n) \ F \ x" proof atomize_elim obtain A :: "nat \ 'a set" where *: "\i. open (A i)" "\i. x \ A i" "\S. open S \ x \ S \ eventually (\i. A i \ S) sequentially" by (rule countable_basis_at_decseq) blast have "eventually (\n. F n \ S) sequentially" if "\n. F n \ A n" "open S" "x \ S" for F S using *(3)[of S] that by (auto elim: eventually_mono simp: subset_eq) with * show "\A. (\i. open (A i)) \ (\i. x \ A i) \ (\F. (\n. F n \ A n) \ F \ x)" by (intro exI[of _ A]) (auto simp: tendsto_def) qed lemma (in first_countable_topology) sequentially_imp_eventually_nhds_within: assumes "\f. (\n. f n \ s) \ f \ a \ eventually (\n. P (f n)) sequentially" shows "eventually P (inf (nhds a) (principal s))" proof (rule ccontr) obtain A :: "nat \ 'a set" where *: "\i. open (A i)" "\i. a \ A i" "\F. \n. F n \ A n \ F \ a" by (rule countable_basis) blast assume "\ ?thesis" with * have "\F. \n. F n \ s \ F n \ A n \ \ P (F n)" unfolding eventually_inf_principal eventually_nhds by (intro choice) fastforce then obtain F where F: "\n. F n \ s" and "\n. F n \ A n" and F': "\n. \ P (F n)" by blast with * have "F \ a" by auto then have "eventually (\n. P (F n)) sequentially" using assms F by simp then show False by (simp add: F') qed lemma (in first_countable_topology) eventually_nhds_within_iff_sequentially: "eventually P (inf (nhds a) (principal s)) \ (\f. (\n. f n \ s) \ f \ a \ eventually (\n. P (f n)) sequentially)" proof (safe intro!: sequentially_imp_eventually_nhds_within) assume "eventually P (inf (nhds a) (principal s))" then obtain S where "open S" "a \ S" "\x\S. x \ s \ P x" by (auto simp: eventually_inf_principal eventually_nhds) moreover fix f assume "\n. f n \ s" "f \ a" ultimately show "eventually (\n. P (f n)) sequentially" by (auto dest!: topological_tendstoD elim: eventually_mono) qed lemma (in first_countable_topology) eventually_nhds_iff_sequentially: "eventually P (nhds a) \ (\f. f \ a \ eventually (\n. P (f n)) sequentially)" using eventually_nhds_within_iff_sequentially[of P a UNIV] by simp (*Thanks to Sébastien Gouëzel*) lemma Inf_as_limit: fixes A::"'a::{linorder_topology, first_countable_topology, complete_linorder} set" assumes "A \ {}" shows "\u. (\n. u n \ A) \ u \ Inf A" proof (cases "Inf A \ A") case True show ?thesis by (rule exI[of _ "\n. Inf A"], auto simp add: True) next case False obtain y where "y \ A" using assms by auto then have "Inf A < y" using False Inf_lower less_le by auto obtain F :: "nat \ 'a set" where F: "\i. open (F i)" "\i. Inf A \ F i" "\u. (\n. u n \ F n) \ u \ Inf A" by (metis first_countable_topology_class.countable_basis) define u where "u = (\n. SOME z. z \ F n \ z \ A)" have "\z. z \ U \ z \ A" if "Inf A \ U" "open U" for U proof - obtain b where "b > Inf A" "{Inf A .. U" using open_right[OF \open U\ \Inf A \ U\ \Inf A < y\] by auto obtain z where "z < b" "z \ A" using \Inf A < b\ Inf_less_iff by auto then have "z \ {Inf A ..z \ A\ \{Inf A .. U\ by auto qed then have *: "u n \ F n \ u n \ A" for n using \Inf A \ F n\ \open (F n)\ unfolding u_def by (metis (no_types, lifting) someI_ex) then have "u \ Inf A" using F(3) by simp then show ?thesis using * by auto qed lemma tendsto_at_iff_sequentially: "(f \ a) (at x within s) \ (\X. (\i. X i \ s - {x}) \ X \ x \ ((f \ X) \ a))" for f :: "'a::first_countable_topology \ _" unfolding filterlim_def[of _ "nhds a"] le_filter_def eventually_filtermap at_within_def eventually_nhds_within_iff_sequentially comp_def by metis lemma approx_from_above_dense_linorder: fixes x::"'a::{dense_linorder, linorder_topology, first_countable_topology}" assumes "x < y" shows "\u. (\n. u n > x) \ (u \ x)" proof - obtain A :: "nat \ 'a set" where A: "\i. open (A i)" "\i. x \ A i" "\F. (\n. F n \ A n) \ F \ x" by (metis first_countable_topology_class.countable_basis) define u where "u = (\n. SOME z. z \ A n \ z > x)" have "\z. z \ U \ x < z" if "x \ U" "open U" for U using open_right[OF \open U\ \x \ U\ \x < y\] by (meson atLeastLessThan_iff dense less_imp_le subset_eq) then have *: "u n \ A n \ x < u n" for n using \x \ A n\ \open (A n)\ unfolding u_def by (metis (no_types, lifting) someI_ex) then have "u \ x" using A(3) by simp then show ?thesis using * by auto qed lemma approx_from_below_dense_linorder: fixes x::"'a::{dense_linorder, linorder_topology, first_countable_topology}" assumes "x > y" shows "\u. (\n. u n < x) \ (u \ x)" proof - obtain A :: "nat \ 'a set" where A: "\i. open (A i)" "\i. x \ A i" "\F. (\n. F n \ A n) \ F \ x" by (metis first_countable_topology_class.countable_basis) define u where "u = (\n. SOME z. z \ A n \ z < x)" have "\z. z \ U \ z < x" if "x \ U" "open U" for U using open_left[OF \open U\ \x \ U\ \x > y\] by (meson dense greaterThanAtMost_iff less_imp_le subset_eq) then have *: "u n \ A n \ u n < x" for n using \x \ A n\ \open (A n)\ unfolding u_def by (metis (no_types, lifting) someI_ex) then have "u \ x" using A(3) by simp then show ?thesis using * by auto qed subsection \Function limit at a point\ abbreviation LIM :: "('a::topological_space \ 'b::topological_space) \ 'a \ 'b \ bool" ("((_)/ \(_)/\ (_))" [60, 0, 60] 60) where "f \a\ L \ (f \ L) (at a)" lemma tendsto_within_open: "a \ S \ open S \ (f \ l) (at a within S) \ (f \a\ l)" by (simp add: tendsto_def at_within_open[where S = S]) lemma tendsto_within_open_NO_MATCH: "a \ S \ NO_MATCH UNIV S \ open S \ (f \ l)(at a within S) \ (f \ l)(at a)" for f :: "'a::topological_space \ 'b::topological_space" using tendsto_within_open by blast lemma LIM_const_not_eq[tendsto_intros]: "k \ L \ \ (\x. k) \a\ L" for a :: "'a::perfect_space" and k L :: "'b::t2_space" by (simp add: tendsto_const_iff) lemmas LIM_not_zero = LIM_const_not_eq [where L = 0] lemma LIM_const_eq: "(\x. k) \a\ L \ k = L" for a :: "'a::perfect_space" and k L :: "'b::t2_space" by (simp add: tendsto_const_iff) lemma LIM_unique: "f \a\ L \ f \a\ M \ L = M" for a :: "'a::perfect_space" and L M :: "'b::t2_space" using at_neq_bot by (rule tendsto_unique) lemma LIM_Uniq: "\\<^sub>\\<^sub>1L::'b::t2_space. f \a\ L" for a :: "'a::perfect_space" by (auto simp add: Uniq_def LIM_unique) text \Limits are equal for functions equal except at limit point.\ lemma LIM_equal: "\x. x \ a \ f x = g x \ (f \a\ l) \ (g \a\ l)" by (simp add: tendsto_def eventually_at_topological) lemma LIM_cong: "a = b \ (\x. x \ b \ f x = g x) \ l = m \ (f \a\ l) \ (g \b\ m)" by (simp add: LIM_equal) lemma tendsto_cong_limit: "(f \ l) F \ k = l \ (f \ k) F" by simp lemma tendsto_at_iff_tendsto_nhds: "g \l\ g l \ (g \ g l) (nhds l)" unfolding tendsto_def eventually_at_filter by (intro ext all_cong imp_cong) (auto elim!: eventually_mono) lemma tendsto_compose: "g \l\ g l \ (f \ l) F \ ((\x. g (f x)) \ g l) F" unfolding tendsto_at_iff_tendsto_nhds by (rule filterlim_compose[of g]) lemma tendsto_compose_eventually: "g \l\ m \ (f \ l) F \ eventually (\x. f x \ l) F \ ((\x. g (f x)) \ m) F" by (rule filterlim_compose[of g _ "at l"]) (auto simp add: filterlim_at) lemma LIM_compose_eventually: assumes "f \a\ b" and "g \b\ c" and "eventually (\x. f x \ b) (at a)" shows "(\x. g (f x)) \a\ c" using assms(2,1,3) by (rule tendsto_compose_eventually) lemma tendsto_compose_filtermap: "((g \ f) \ T) F \ (g \ T) (filtermap f F)" by (simp add: filterlim_def filtermap_filtermap comp_def) lemma tendsto_compose_at: assumes f: "(f \ y) F" and g: "(g \ z) (at y)" and fg: "eventually (\w. f w = y \ g y = z) F" shows "((g \ f) \ z) F" proof - have "(\\<^sub>F a in F. f a \ y) \ g y = z" using fg by force moreover have "(g \ z) (filtermap f F) \ \ (\\<^sub>F a in F. f a \ y)" by (metis (no_types) filterlim_atI filterlim_def tendsto_mono f g) ultimately show ?thesis by (metis (no_types) f filterlim_compose filterlim_filtermap g tendsto_at_iff_tendsto_nhds tendsto_compose_filtermap) qed subsubsection \Relation of \LIM\ and \LIMSEQ\\ lemma (in first_countable_topology) sequentially_imp_eventually_within: "(\f. (\n. f n \ s \ f n \ a) \ f \ a \ eventually (\n. P (f n)) sequentially) \ eventually P (at a within s)" unfolding at_within_def by (intro sequentially_imp_eventually_nhds_within) auto lemma (in first_countable_topology) sequentially_imp_eventually_at: "(\f. (\n. f n \ a) \ f \ a \ eventually (\n. P (f n)) sequentially) \ eventually P (at a)" using sequentially_imp_eventually_within [where s=UNIV] by simp lemma LIMSEQ_SEQ_conv1: fixes f :: "'a::topological_space \ 'b::topological_space" assumes f: "f \a\ l" shows "\S. (\n. S n \ a) \ S \ a \ (\n. f (S n)) \ l" using tendsto_compose_eventually [OF f, where F=sequentially] by simp lemma LIMSEQ_SEQ_conv2: fixes f :: "'a::first_countable_topology \ 'b::topological_space" assumes "\S. (\n. S n \ a) \ S \ a \ (\n. f (S n)) \ l" shows "f \a\ l" using assms unfolding tendsto_def [where l=l] by (simp add: sequentially_imp_eventually_at) lemma LIMSEQ_SEQ_conv: "(\S. (\n. S n \ a) \ S \ a \ (\n. X (S n)) \ L) \ X \a\ L" for a :: "'a::first_countable_topology" and L :: "'b::topological_space" using LIMSEQ_SEQ_conv2 LIMSEQ_SEQ_conv1 .. lemma sequentially_imp_eventually_at_left: fixes a :: "'a::{linorder_topology,first_countable_topology}" assumes b[simp]: "b < a" and *: "\f. (\n. b < f n) \ (\n. f n < a) \ incseq f \ f \ a \ eventually (\n. P (f n)) sequentially" shows "eventually P (at_left a)" proof (safe intro!: sequentially_imp_eventually_within) fix X assume X: "\n. X n \ {..< a} \ X n \ a" "X \ a" show "eventually (\n. P (X n)) sequentially" proof (rule ccontr) assume neg: "\ ?thesis" have "\s. \n. (\ P (X (s n)) \ b < X (s n)) \ (X (s n) \ X (s (Suc n)) \ Suc (s n) \ s (Suc n))" (is "\s. ?P s") proof (rule dependent_nat_choice) have "\ eventually (\n. b < X n \ P (X n)) sequentially" by (intro not_eventually_impI neg order_tendstoD(1) [OF X(2) b]) then show "\x. \ P (X x) \ b < X x" by (auto dest!: not_eventuallyD) next fix x n have "\ eventually (\n. Suc x \ n \ b < X n \ X x < X n \ P (X n)) sequentially" using X by (intro not_eventually_impI order_tendstoD(1)[OF X(2)] eventually_ge_at_top neg) auto then show "\n. (\ P (X n) \ b < X n) \ (X x \ X n \ Suc x \ n)" by (auto dest!: not_eventuallyD) qed then obtain s where "?P s" .. with X have "b < X (s n)" and "X (s n) < a" and "incseq (\n. X (s n))" and "(\n. X (s n)) \ a" and "\ P (X (s n))" for n by (auto simp: strict_mono_Suc_iff Suc_le_eq incseq_Suc_iff intro!: LIMSEQ_subseq_LIMSEQ[OF \X \ a\, unfolded comp_def]) from *[OF this(1,2,3,4)] this(5) show False by auto qed qed lemma tendsto_at_left_sequentially: fixes a b :: "'b::{linorder_topology,first_countable_topology}" assumes "b < a" assumes *: "\S. (\n. S n < a) \ (\n. b < S n) \ incseq S \ S \ a \ (\n. X (S n)) \ L" shows "(X \ L) (at_left a)" using assms by (simp add: tendsto_def [where l=L] sequentially_imp_eventually_at_left) lemma sequentially_imp_eventually_at_right: fixes a b :: "'a::{linorder_topology,first_countable_topology}" assumes b[simp]: "a < b" assumes *: "\f. (\n. a < f n) \ (\n. f n < b) \ decseq f \ f \ a \ eventually (\n. P (f n)) sequentially" shows "eventually P (at_right a)" proof (safe intro!: sequentially_imp_eventually_within) fix X assume X: "\n. X n \ {a <..} \ X n \ a" "X \ a" show "eventually (\n. P (X n)) sequentially" proof (rule ccontr) assume neg: "\ ?thesis" have "\s. \n. (\ P (X (s n)) \ X (s n) < b) \ (X (s (Suc n)) \ X (s n) \ Suc (s n) \ s (Suc n))" (is "\s. ?P s") proof (rule dependent_nat_choice) have "\ eventually (\n. X n < b \ P (X n)) sequentially" by (intro not_eventually_impI neg order_tendstoD(2) [OF X(2) b]) then show "\x. \ P (X x) \ X x < b" by (auto dest!: not_eventuallyD) next fix x n have "\ eventually (\n. Suc x \ n \ X n < b \ X n < X x \ P (X n)) sequentially" using X by (intro not_eventually_impI order_tendstoD(2)[OF X(2)] eventually_ge_at_top neg) auto then show "\n. (\ P (X n) \ X n < b) \ (X n \ X x \ Suc x \ n)" by (auto dest!: not_eventuallyD) qed then obtain s where "?P s" .. with X have "a < X (s n)" and "X (s n) < b" and "decseq (\n. X (s n))" and "(\n. X (s n)) \ a" and "\ P (X (s n))" for n by (auto simp: strict_mono_Suc_iff Suc_le_eq decseq_Suc_iff intro!: LIMSEQ_subseq_LIMSEQ[OF \X \ a\, unfolded comp_def]) from *[OF this(1,2,3,4)] this(5) show False by auto qed qed lemma tendsto_at_right_sequentially: fixes a :: "_ :: {linorder_topology, first_countable_topology}" assumes "a < b" and *: "\S. (\n. a < S n) \ (\n. S n < b) \ decseq S \ S \ a \ (\n. X (S n)) \ L" shows "(X \ L) (at_right a)" using assms by (simp add: tendsto_def [where l=L] sequentially_imp_eventually_at_right) subsection \Continuity\ subsubsection \Continuity on a set\ definition continuous_on :: "'a set \ ('a::topological_space \ 'b::topological_space) \ bool" where "continuous_on s f \ (\x\s. (f \ f x) (at x within s))" lemma continuous_on_cong [cong]: "s = t \ (\x. x \ t \ f x = g x) \ continuous_on s f \ continuous_on t g" unfolding continuous_on_def by (intro ball_cong filterlim_cong) (auto simp: eventually_at_filter) lemma continuous_on_cong_simp: "s = t \ (\x. x \ t =simp=> f x = g x) \ continuous_on s f \ continuous_on t g" unfolding simp_implies_def by (rule continuous_on_cong) lemma continuous_on_topological: "continuous_on s f \ (\x\s. \B. open B \ f x \ B \ (\A. open A \ x \ A \ (\y\s. y \ A \ f y \ B)))" unfolding continuous_on_def tendsto_def eventually_at_topological by metis lemma continuous_on_open_invariant: "continuous_on s f \ (\B. open B \ (\A. open A \ A \ s = f -` B \ s))" proof safe fix B :: "'b set" assume "continuous_on s f" "open B" then have "\x\f -` B \ s. (\A. open A \ x \ A \ s \ A \ f -` B)" by (auto simp: continuous_on_topological subset_eq Ball_def imp_conjL) then obtain A where "\x\f -` B \ s. open (A x) \ x \ A x \ s \ A x \ f -` B" unfolding bchoice_iff .. then show "\A. open A \ A \ s = f -` B \ s" by (intro exI[of _ "\x\f -` B \ s. A x"]) auto next assume B: "\B. open B \ (\A. open A \ A \ s = f -` B \ s)" show "continuous_on s f" unfolding continuous_on_topological proof safe fix x B assume "x \ s" "open B" "f x \ B" with B obtain A where A: "open A" "A \ s = f -` B \ s" by auto with \x \ s\ \f x \ B\ show "\A. open A \ x \ A \ (\y\s. y \ A \ f y \ B)" by (intro exI[of _ A]) auto qed qed lemma continuous_on_open_vimage: "open s \ continuous_on s f \ (\B. open B \ open (f -` B \ s))" unfolding continuous_on_open_invariant by (metis open_Int Int_absorb Int_commute[of s] Int_assoc[of _ _ s]) corollary continuous_imp_open_vimage: assumes "continuous_on s f" "open s" "open B" "f -` B \ s" shows "open (f -` B)" by (metis assms continuous_on_open_vimage le_iff_inf) corollary open_vimage[continuous_intros]: assumes "open s" and "continuous_on UNIV f" shows "open (f -` s)" using assms by (simp add: continuous_on_open_vimage [OF open_UNIV]) lemma continuous_on_closed_invariant: "continuous_on s f \ (\B. closed B \ (\A. closed A \ A \ s = f -` B \ s))" proof - have *: "(\A. P A \ Q (- A)) \ (\A. P A) \ (\A. Q A)" for P Q :: "'b set \ bool" by (metis double_compl) show ?thesis unfolding continuous_on_open_invariant by (intro *) (auto simp: open_closed[symmetric]) qed lemma continuous_on_closed_vimage: "closed s \ continuous_on s f \ (\B. closed B \ closed (f -` B \ s))" unfolding continuous_on_closed_invariant by (metis closed_Int Int_absorb Int_commute[of s] Int_assoc[of _ _ s]) corollary closed_vimage_Int[continuous_intros]: assumes "closed s" and "continuous_on t f" and t: "closed t" shows "closed (f -` s \ t)" using assms by (simp add: continuous_on_closed_vimage [OF t]) corollary closed_vimage[continuous_intros]: assumes "closed s" and "continuous_on UNIV f" shows "closed (f -` s)" using closed_vimage_Int [OF assms] by simp lemma continuous_on_empty [simp]: "continuous_on {} f" by (simp add: continuous_on_def) lemma continuous_on_sing [simp]: "continuous_on {x} f" by (simp add: continuous_on_def at_within_def) lemma continuous_on_open_Union: "(\s. s \ S \ open s) \ (\s. s \ S \ continuous_on s f) \ continuous_on (\S) f" unfolding continuous_on_def by safe (metis open_Union at_within_open UnionI) lemma continuous_on_open_UN: "(\s. s \ S \ open (A s)) \ (\s. s \ S \ continuous_on (A s) f) \ continuous_on (\s\S. A s) f" by (rule continuous_on_open_Union) auto lemma continuous_on_open_Un: "open s \ open t \ continuous_on s f \ continuous_on t f \ continuous_on (s \ t) f" using continuous_on_open_Union [of "{s,t}"] by auto lemma continuous_on_closed_Un: "closed s \ closed t \ continuous_on s f \ continuous_on t f \ continuous_on (s \ t) f" by (auto simp add: continuous_on_closed_vimage closed_Un Int_Un_distrib) lemma continuous_on_closed_Union: assumes "finite I" "\i. i \ I \ closed (U i)" "\i. i \ I \ continuous_on (U i) f" shows "continuous_on (\ i \ I. U i) f" using assms by (induction I) (auto intro!: continuous_on_closed_Un) lemma continuous_on_If: assumes closed: "closed s" "closed t" and cont: "continuous_on s f" "continuous_on t g" and P: "\x. x \ s \ \ P x \ f x = g x" "\x. x \ t \ P x \ f x = g x" shows "continuous_on (s \ t) (\x. if P x then f x else g x)" (is "continuous_on _ ?h") proof- from P have "\x\s. f x = ?h x" "\x\t. g x = ?h x" by auto with cont have "continuous_on s ?h" "continuous_on t ?h" by simp_all with closed show ?thesis by (rule continuous_on_closed_Un) qed lemma continuous_on_cases: "closed s \ closed t \ continuous_on s f \ continuous_on t g \ \x. (x\s \ \ P x) \ (x \ t \ P x) \ f x = g x \ continuous_on (s \ t) (\x. if P x then f x else g x)" by (rule continuous_on_If) auto lemma continuous_on_id[continuous_intros,simp]: "continuous_on s (\x. x)" unfolding continuous_on_def by fast lemma continuous_on_id'[continuous_intros,simp]: "continuous_on s id" unfolding continuous_on_def id_def by fast lemma continuous_on_const[continuous_intros,simp]: "continuous_on s (\x. c)" unfolding continuous_on_def by auto lemma continuous_on_subset: "continuous_on s f \ t \ s \ continuous_on t f" unfolding continuous_on_def by (metis subset_eq tendsto_within_subset) lemma continuous_on_compose[continuous_intros]: "continuous_on s f \ continuous_on (f ` s) g \ continuous_on s (g \ f)" unfolding continuous_on_topological by simp metis lemma continuous_on_compose2: "continuous_on t g \ continuous_on s f \ f ` s \ t \ continuous_on s (\x. g (f x))" using continuous_on_compose[of s f g] continuous_on_subset by (force simp add: comp_def) lemma continuous_on_generate_topology: assumes *: "open = generate_topology X" and **: "\B. B \ X \ \C. open C \ C \ A = f -` B \ A" shows "continuous_on A f" unfolding continuous_on_open_invariant proof safe fix B :: "'a set" assume "open B" then show "\C. open C \ C \ A = f -` B \ A" unfolding * proof induct case (UN K) then obtain C where "\k. k \ K \ open (C k)" "\k. k \ K \ C k \ A = f -` k \ A" by metis then show ?case by (intro exI[of _ "\k\K. C k"]) blast qed (auto intro: **) qed lemma continuous_onI_mono: fixes f :: "'a::linorder_topology \ 'b::{dense_order,linorder_topology}" assumes "open (f`A)" and mono: "\x y. x \ A \ y \ A \ x \ y \ f x \ f y" shows "continuous_on A f" proof (rule continuous_on_generate_topology[OF open_generated_order], safe) have monoD: "\x y. x \ A \ y \ A \ f x < f y \ x < y" by (auto simp: not_le[symmetric] mono) have "\x. x \ A \ f x < b \ a < x" if a: "a \ A" and fa: "f a < b" for a b proof - obtain y where "f a < y" "{f a ..< y} \ f`A" using open_right[OF \open (f`A)\, of "f a" b] a fa by auto obtain z where z: "f a < z" "z < min b y" using dense[of "f a" "min b y"] \f a < y\ \f a < b\ by auto then obtain c where "z = f c" "c \ A" using \{f a ..< y} \ f`A\[THEN subsetD, of z] by (auto simp: less_imp_le) with a z show ?thesis by (auto intro!: exI[of _ c] simp: monoD) qed then show "\C. open C \ C \ A = f -` {.. A" for b by (intro exI[of _ "(\x\{x\A. f x < b}. {..< x})"]) (auto intro: le_less_trans[OF mono] less_imp_le) have "\x. x \ A \ b < f x \ x < a" if a: "a \ A" and fa: "b < f a" for a b proof - note a fa moreover obtain y where "y < f a" "{y <.. f a} \ f`A" using open_left[OF \open (f`A)\, of "f a" b] a fa by auto then obtain z where z: "max b y < z" "z < f a" using dense[of "max b y" "f a"] \y < f a\ \b < f a\ by auto then obtain c where "z = f c" "c \ A" using \{y <.. f a} \ f`A\[THEN subsetD, of z] by (auto simp: less_imp_le) with a z show ?thesis by (auto intro!: exI[of _ c] simp: monoD) qed then show "\C. open C \ C \ A = f -` {b <..} \ A" for b by (intro exI[of _ "(\x\{x\A. b < f x}. {x <..})"]) (auto intro: less_le_trans[OF _ mono] less_imp_le) qed lemma continuous_on_IccI: "\(f \ f a) (at_right a); (f \ f b) (at_left b); (\x. a < x \ x < b \ f \x\ f x); a < b\ \ continuous_on {a .. b} f" for a::"'a::linorder_topology" using at_within_open[of _ "{a<.. f a) (at_right a)" and continuous_on_Icc_at_leftD: "(f \ f b) (at_left b)" using assms by (auto simp: at_within_Icc_at_right at_within_Icc_at_left continuous_on_def dest: bspec[where x=a] bspec[where x=b]) lemma continuous_on_discrete [simp]: "continuous_on A (f :: 'a :: discrete_topology \ _)" by (auto simp: continuous_on_def at_discrete) subsubsection \Continuity at a point\ definition continuous :: "'a::t2_space filter \ ('a \ 'b::topological_space) \ bool" where "continuous F f \ (f \ f (Lim F (\x. x))) F" lemma continuous_bot[continuous_intros, simp]: "continuous bot f" unfolding continuous_def by auto lemma continuous_trivial_limit: "trivial_limit net \ continuous net f" by simp lemma continuous_within: "continuous (at x within s) f \ (f \ f x) (at x within s)" by (cases "trivial_limit (at x within s)") (auto simp add: Lim_ident_at continuous_def) lemma continuous_within_topological: "continuous (at x within s) f \ (\B. open B \ f x \ B \ (\A. open A \ x \ A \ (\y\s. y \ A \ f y \ B)))" unfolding continuous_within tendsto_def eventually_at_topological by metis lemma continuous_within_compose[continuous_intros]: "continuous (at x within s) f \ continuous (at (f x) within f ` s) g \ continuous (at x within s) (g \ f)" by (simp add: continuous_within_topological) metis lemma continuous_within_compose2: "continuous (at x within s) f \ continuous (at (f x) within f ` s) g \ continuous (at x within s) (\x. g (f x))" using continuous_within_compose[of x s f g] by (simp add: comp_def) lemma continuous_at: "continuous (at x) f \ f \x\ f x" using continuous_within[of x UNIV f] by simp lemma continuous_ident[continuous_intros, simp]: "continuous (at x within S) (\x. x)" unfolding continuous_within by (rule tendsto_ident_at) lemma continuous_id[continuous_intros, simp]: "continuous (at x within S) id" by (simp add: id_def) lemma continuous_const[continuous_intros, simp]: "continuous F (\x. c)" unfolding continuous_def by (rule tendsto_const) lemma continuous_on_eq_continuous_within: "continuous_on s f \ (\x\s. continuous (at x within s) f)" unfolding continuous_on_def continuous_within .. lemma continuous_discrete [simp]: "continuous (at x within A) (f :: 'a :: discrete_topology \ _)" by (auto simp: continuous_def at_discrete) abbreviation isCont :: "('a::t2_space \ 'b::topological_space) \ 'a \ bool" where "isCont f a \ continuous (at a) f" lemma isCont_def: "isCont f a \ f \a\ f a" by (rule continuous_at) lemma isContD: "isCont f x \ f \x\ f x" by (simp add: isCont_def) lemma isCont_cong: assumes "eventually (\x. f x = g x) (nhds x)" shows "isCont f x \ isCont g x" proof - from assms have [simp]: "f x = g x" by (rule eventually_nhds_x_imp_x) from assms have "eventually (\x. f x = g x) (at x)" by (auto simp: eventually_at_filter elim!: eventually_mono) with assms have "isCont f x \ isCont g x" unfolding isCont_def by (intro filterlim_cong) (auto elim!: eventually_mono) with assms show ?thesis by simp qed lemma continuous_at_imp_continuous_at_within: "isCont f x \ continuous (at x within s) f" by (auto intro: tendsto_mono at_le simp: continuous_at continuous_within) lemma continuous_on_eq_continuous_at: "open s \ continuous_on s f \ (\x\s. isCont f x)" by (simp add: continuous_on_def continuous_at at_within_open[of _ s]) lemma continuous_within_open: "a \ A \ open A \ continuous (at a within A) f \ isCont f a" by (simp add: at_within_open_NO_MATCH) lemma continuous_at_imp_continuous_on: "\x\s. isCont f x \ continuous_on s f" by (auto intro: continuous_at_imp_continuous_at_within simp: continuous_on_eq_continuous_within) lemma isCont_o2: "isCont f a \ isCont g (f a) \ isCont (\x. g (f x)) a" unfolding isCont_def by (rule tendsto_compose) lemma continuous_at_compose[continuous_intros]: "isCont f a \ isCont g (f a) \ isCont (g \ f) a" unfolding o_def by (rule isCont_o2) lemma isCont_tendsto_compose: "isCont g l \ (f \ l) F \ ((\x. g (f x)) \ g l) F" unfolding isCont_def by (rule tendsto_compose) lemma continuous_on_tendsto_compose: assumes f_cont: "continuous_on s f" and g: "(g \ l) F" and l: "l \ s" and ev: "\\<^sub>Fx in F. g x \ s" shows "((\x. f (g x)) \ f l) F" proof - from f_cont l have f: "(f \ f l) (at l within s)" by (simp add: continuous_on_def) have i: "((\x. if g x = l then f l else f (g x)) \ f l) F" by (rule filterlim_If) (auto intro!: filterlim_compose[OF f] eventually_conj tendsto_mono[OF _ g] simp: filterlim_at eventually_inf_principal eventually_mono[OF ev]) show ?thesis by (rule filterlim_cong[THEN iffD1[OF _ i]]) auto qed lemma continuous_within_compose3: "isCont g (f x) \ continuous (at x within s) f \ continuous (at x within s) (\x. g (f x))" using continuous_at_imp_continuous_at_within continuous_within_compose2 by blast lemma filtermap_nhds_open_map: assumes cont: "isCont f a" and open_map: "\S. open S \ open (f`S)" shows "filtermap f (nhds a) = nhds (f a)" unfolding filter_eq_iff proof safe fix P assume "eventually P (filtermap f (nhds a))" then obtain S where "open S" "a \ S" "\x\S. P (f x)" by (auto simp: eventually_filtermap eventually_nhds) then show "eventually P (nhds (f a))" unfolding eventually_nhds by (intro exI[of _ "f`S"]) (auto intro!: open_map) qed (metis filterlim_iff tendsto_at_iff_tendsto_nhds isCont_def eventually_filtermap cont) lemma continuous_at_split: "continuous (at x) f \ continuous (at_left x) f \ continuous (at_right x) f" for x :: "'a::linorder_topology" by (simp add: continuous_within filterlim_at_split) lemma continuous_on_max [continuous_intros]: fixes f g :: "'a::topological_space \ 'b::linorder_topology" shows "continuous_on A f \ continuous_on A g \ continuous_on A (\x. max (f x) (g x))" by (auto simp: continuous_on_def intro!: tendsto_max) lemma continuous_on_min [continuous_intros]: fixes f g :: "'a::topological_space \ 'b::linorder_topology" shows "continuous_on A f \ continuous_on A g \ continuous_on A (\x. min (f x) (g x))" by (auto simp: continuous_on_def intro!: tendsto_min) lemma continuous_max [continuous_intros]: fixes f :: "'a::t2_space \ 'b::linorder_topology" shows "\continuous F f; continuous F g\ \ continuous F (\x. (max (f x) (g x)))" by (simp add: tendsto_max continuous_def) lemma continuous_min [continuous_intros]: fixes f :: "'a::t2_space \ 'b::linorder_topology" shows "\continuous F f; continuous F g\ \ continuous F (\x. (min (f x) (g x)))" by (simp add: tendsto_min continuous_def) text \ The following open/closed Collect lemmas are ported from Sébastien Gouëzel's \Ergodic_Theory\. \ lemma open_Collect_neq: fixes f g :: "'a::topological_space \ 'b::t2_space" assumes f: "continuous_on UNIV f" and g: "continuous_on UNIV g" shows "open {x. f x \ g x}" proof (rule openI) fix t assume "t \ {x. f x \ g x}" then obtain U V where *: "open U" "open V" "f t \ U" "g t \ V" "U \ V = {}" by (auto simp add: separation_t2) with open_vimage[OF \open U\ f] open_vimage[OF \open V\ g] show "\T. open T \ t \ T \ T \ {x. f x \ g x}" by (intro exI[of _ "f -` U \ g -` V"]) auto qed lemma closed_Collect_eq: fixes f g :: "'a::topological_space \ 'b::t2_space" assumes f: "continuous_on UNIV f" and g: "continuous_on UNIV g" shows "closed {x. f x = g x}" using open_Collect_neq[OF f g] by (simp add: closed_def Collect_neg_eq) lemma open_Collect_less: fixes f g :: "'a::topological_space \ 'b::linorder_topology" assumes f: "continuous_on UNIV f" and g: "continuous_on UNIV g" shows "open {x. f x < g x}" proof (rule openI) fix t assume t: "t \ {x. f x < g x}" show "\T. open T \ t \ T \ T \ {x. f x < g x}" proof (cases "\z. f t < z \ z < g t") case True then obtain z where "f t < z \ z < g t" by blast then show ?thesis using open_vimage[OF _ f, of "{..< z}"] open_vimage[OF _ g, of "{z <..}"] by (intro exI[of _ "f -` {.. g -` {z<..}"]) auto next case False then have *: "{g t ..} = {f t <..}" "{..< g t} = {.. f t}" using t by (auto intro: leI) show ?thesis using open_vimage[OF _ f, of "{..< g t}"] open_vimage[OF _ g, of "{f t <..}"] t apply (intro exI[of _ "f -` {..< g t} \ g -` {f t<..}"]) apply (simp add: open_Int) apply (auto simp add: *) done qed qed lemma closed_Collect_le: fixes f g :: "'a :: topological_space \ 'b::linorder_topology" assumes f: "continuous_on UNIV f" and g: "continuous_on UNIV g" shows "closed {x. f x \ g x}" using open_Collect_less [OF g f] by (simp add: closed_def Collect_neg_eq[symmetric] not_le) subsubsection \Open-cover compactness\ context topological_space begin definition compact :: "'a set \ bool" where compact_eq_Heine_Borel: (* This name is used for backwards compatibility *) "compact S \ (\C. (\c\C. open c) \ S \ \C \ (\D\C. finite D \ S \ \D))" lemma compactI: assumes "\C. \t\C. open t \ s \ \C \ \C'. C' \ C \ finite C' \ s \ \C'" shows "compact s" unfolding compact_eq_Heine_Borel using assms by metis lemma compact_empty[simp]: "compact {}" by (auto intro!: compactI) lemma compactE: (*related to COMPACT_IMP_HEINE_BOREL in HOL Light*) assumes "compact S" "S \ \\" "\B. B \ \ \ open B" obtains \' where "\' \ \" "finite \'" "S \ \\'" by (meson assms compact_eq_Heine_Borel) lemma compactE_image: assumes "compact S" and opn: "\T. T \ C \ open (f T)" and S: "S \ (\c\C. f c)" obtains C' where "C' \ C" and "finite C'" and "S \ (\c\C'. f c)" apply (rule compactE[OF \compact S\ S]) using opn apply force by (metis finite_subset_image) lemma compact_Int_closed [intro]: assumes "compact S" and "closed T" shows "compact (S \ T)" proof (rule compactI) fix C assume C: "\c\C. open c" assume cover: "S \ T \ \C" from C \closed T\ have "\c\C \ {- T}. open c" by auto moreover from cover have "S \ \(C \ {- T})" by auto ultimately have "\D\C \ {- T}. finite D \ S \ \D" using \compact S\ unfolding compact_eq_Heine_Borel by auto then obtain D where "D \ C \ {- T} \ finite D \ S \ \D" .. then show "\D\C. finite D \ S \ T \ \D" by (intro exI[of _ "D - {-T}"]) auto qed lemma compact_diff: "\compact S; open T\ \ compact(S - T)" by (simp add: Diff_eq compact_Int_closed open_closed) lemma inj_setminus: "inj_on uminus (A::'a set set)" by (auto simp: inj_on_def) subsection \Finite intersection property\ lemma compact_fip: "compact U \ (\A. (\a\A. closed a) \ (\B \ A. finite B \ U \ \B \ {}) \ U \ \A \ {})" (is "_ \ ?R") proof (safe intro!: compact_eq_Heine_Borel[THEN iffD2]) fix A assume "compact U" assume A: "\a\A. closed a" "U \ \A = {}" assume fin: "\B \ A. finite B \ U \ \B \ {}" from A have "(\a\uminus`A. open a) \ U \ \(uminus`A)" by auto with \compact U\ obtain B where "B \ A" "finite (uminus`B)" "U \ \(uminus`B)" unfolding compact_eq_Heine_Borel by (metis subset_image_iff) with fin[THEN spec, of B] show False by (auto dest: finite_imageD intro: inj_setminus) next fix A assume ?R assume "\a\A. open a" "U \ \A" then have "U \ \(uminus`A) = {}" "\a\uminus`A. closed a" by auto with \?R\ obtain B where "B \ A" "finite (uminus`B)" "U \ \(uminus`B) = {}" by (metis subset_image_iff) then show "\T\A. finite T \ U \ \T" by (auto intro!: exI[of _ B] inj_setminus dest: finite_imageD) qed lemma compact_imp_fip: assumes "compact S" and "\T. T \ F \ closed T" and "\F'. finite F' \ F' \ F \ S \ (\F') \ {}" shows "S \ (\F) \ {}" using assms unfolding compact_fip by auto lemma compact_imp_fip_image: assumes "compact s" and P: "\i. i \ I \ closed (f i)" and Q: "\I'. finite I' \ I' \ I \ (s \ (\i\I'. f i) \ {})" shows "s \ (\i\I. f i) \ {}" proof - note \compact s\ moreover from P have "\i \ f ` I. closed i" by blast moreover have "\A. finite A \ A \ f ` I \ (s \ (\A) \ {})" apply rule apply rule apply (erule conjE) proof - fix A :: "'a set set" assume "finite A" and "A \ f ` I" then obtain B where "B \ I" and "finite B" and "A = f ` B" using finite_subset_image [of A f I] by blast with Q [of B] show "s \ \A \ {}" by simp qed ultimately have "s \ (\(f ` I)) \ {}" by (metis compact_imp_fip) then show ?thesis by simp qed end lemma (in t2_space) compact_imp_closed: assumes "compact s" shows "closed s" unfolding closed_def proof (rule openI) fix y assume "y \ - s" let ?C = "\x\s. {u. open u \ x \ u \ eventually (\y. y \ u) (nhds y)}" have "s \ \?C" proof fix x assume "x \ s" with \y \ - s\ have "x \ y" by clarsimp then have "\u v. open u \ open v \ x \ u \ y \ v \ u \ v = {}" by (rule hausdorff) with \x \ s\ show "x \ \?C" unfolding eventually_nhds by auto qed then obtain D where "D \ ?C" and "finite D" and "s \ \D" by (rule compactE [OF \compact s\]) auto from \D \ ?C\ have "\x\D. eventually (\y. y \ x) (nhds y)" by auto with \finite D\ have "eventually (\y. y \ \D) (nhds y)" by (simp add: eventually_ball_finite) with \s \ \D\ have "eventually (\y. y \ s) (nhds y)" by (auto elim!: eventually_mono) then show "\t. open t \ y \ t \ t \ - s" by (simp add: eventually_nhds subset_eq) qed lemma compact_continuous_image: assumes f: "continuous_on s f" and s: "compact s" shows "compact (f ` s)" proof (rule compactI) fix C assume "\c\C. open c" and cover: "f`s \ \C" with f have "\c\C. \A. open A \ A \ s = f -` c \ s" unfolding continuous_on_open_invariant by blast then obtain A where A: "\c\C. open (A c) \ A c \ s = f -` c \ s" unfolding bchoice_iff .. with cover have "\c. c \ C \ open (A c)" "s \ (\c\C. A c)" by (fastforce simp add: subset_eq set_eq_iff)+ from compactE_image[OF s this] obtain D where "D \ C" "finite D" "s \ (\c\D. A c)" . with A show "\D \ C. finite D \ f`s \ \D" by (intro exI[of _ D]) (fastforce simp add: subset_eq set_eq_iff)+ qed lemma continuous_on_inv: fixes f :: "'a::topological_space \ 'b::t2_space" assumes "continuous_on s f" and "compact s" and "\x\s. g (f x) = x" shows "continuous_on (f ` s) g" unfolding continuous_on_topological proof (clarsimp simp add: assms(3)) fix x :: 'a and B :: "'a set" assume "x \ s" and "open B" and "x \ B" have 1: "\x\s. f x \ f ` (s - B) \ x \ s - B" using assms(3) by (auto, metis) have "continuous_on (s - B) f" using \continuous_on s f\ Diff_subset by (rule continuous_on_subset) moreover have "compact (s - B)" using \open B\ and \compact s\ unfolding Diff_eq by (intro compact_Int_closed closed_Compl) ultimately have "compact (f ` (s - B))" by (rule compact_continuous_image) then have "closed (f ` (s - B))" by (rule compact_imp_closed) then have "open (- f ` (s - B))" by (rule open_Compl) moreover have "f x \ - f ` (s - B)" using \x \ s\ and \x \ B\ by (simp add: 1) moreover have "\y\s. f y \ - f ` (s - B) \ y \ B" by (simp add: 1) ultimately show "\A. open A \ f x \ A \ (\y\s. f y \ A \ y \ B)" by fast qed lemma continuous_on_inv_into: fixes f :: "'a::topological_space \ 'b::t2_space" assumes s: "continuous_on s f" "compact s" and f: "inj_on f s" shows "continuous_on (f ` s) (the_inv_into s f)" by (rule continuous_on_inv[OF s]) (auto simp: the_inv_into_f_f[OF f]) lemma (in linorder_topology) compact_attains_sup: assumes "compact S" "S \ {}" shows "\s\S. \t\S. t \ s" proof (rule classical) assume "\ (\s\S. \t\S. t \ s)" then obtain t where t: "\s\S. t s \ S" and "\s\S. s < t s" by (metis not_le) then have "\s. s\S \ open {..< t s}" "S \ (\s\S. {..< t s})" by auto with \compact S\ obtain C where "C \ S" "finite C" and C: "S \ (\s\C. {..< t s})" by (metis compactE_image) with \S \ {}\ have Max: "Max (t`C) \ t`C" and "\s\t`C. s \ Max (t`C)" by (auto intro!: Max_in) with C have "S \ {..< Max (t`C)}" by (auto intro: less_le_trans simp: subset_eq) with t Max \C \ S\ show ?thesis by fastforce qed lemma (in linorder_topology) compact_attains_inf: assumes "compact S" "S \ {}" shows "\s\S. \t\S. s \ t" proof (rule classical) assume "\ (\s\S. \t\S. s \ t)" then obtain t where t: "\s\S. t s \ S" and "\s\S. t s < s" by (metis not_le) then have "\s. s\S \ open {t s <..}" "S \ (\s\S. {t s <..})" by auto with \compact S\ obtain C where "C \ S" "finite C" and C: "S \ (\s\C. {t s <..})" by (metis compactE_image) with \S \ {}\ have Min: "Min (t`C) \ t`C" and "\s\t`C. Min (t`C) \ s" by (auto intro!: Min_in) with C have "S \ {Min (t`C) <..}" by (auto intro: le_less_trans simp: subset_eq) with t Min \C \ S\ show ?thesis by fastforce qed lemma continuous_attains_sup: fixes f :: "'a::topological_space \ 'b::linorder_topology" shows "compact s \ s \ {} \ continuous_on s f \ (\x\s. \y\s. f y \ f x)" using compact_attains_sup[of "f ` s"] compact_continuous_image[of s f] by auto lemma continuous_attains_inf: fixes f :: "'a::topological_space \ 'b::linorder_topology" shows "compact s \ s \ {} \ continuous_on s f \ (\x\s. \y\s. f x \ f y)" using compact_attains_inf[of "f ` s"] compact_continuous_image[of s f] by auto subsection \Connectedness\ context topological_space begin definition "connected S \ \ (\A B. open A \ open B \ S \ A \ B \ A \ B \ S = {} \ A \ S \ {} \ B \ S \ {})" lemma connectedI: "(\A B. open A \ open B \ A \ U \ {} \ B \ U \ {} \ A \ B \ U = {} \ U \ A \ B \ False) \ connected U" by (auto simp: connected_def) lemma connected_empty [simp]: "connected {}" by (auto intro!: connectedI) lemma connected_sing [simp]: "connected {x}" by (auto intro!: connectedI) lemma connectedD: "connected A \ open U \ open V \ U \ V \ A = {} \ A \ U \ V \ U \ A = {} \ V \ A = {}" by (auto simp: connected_def) end lemma connected_closed: "connected s \ \ (\A B. closed A \ closed B \ s \ A \ B \ A \ B \ s = {} \ A \ s \ {} \ B \ s \ {})" apply (simp add: connected_def del: ex_simps, safe) apply (drule_tac x="-A" in spec) apply (drule_tac x="-B" in spec) apply (fastforce simp add: closed_def [symmetric]) apply (drule_tac x="-A" in spec) apply (drule_tac x="-B" in spec) apply (fastforce simp add: open_closed [symmetric]) done lemma connected_closedD: "\connected s; A \ B \ s = {}; s \ A \ B; closed A; closed B\ \ A \ s = {} \ B \ s = {}" by (simp add: connected_closed) lemma connected_Union: assumes cs: "\s. s \ S \ connected s" and ne: "\S \ {}" shows "connected(\S)" proof (rule connectedI) fix A B assume A: "open A" and B: "open B" and Alap: "A \ \S \ {}" and Blap: "B \ \S \ {}" and disj: "A \ B \ \S = {}" and cover: "\S \ A \ B" have disjs:"\s. s \ S \ A \ B \ s = {}" using disj by auto obtain sa where sa: "sa \ S" "A \ sa \ {}" using Alap by auto obtain sb where sb: "sb \ S" "B \ sb \ {}" using Blap by auto obtain x where x: "\s. s \ S \ x \ s" using ne by auto then have "x \ \S" using \sa \ S\ by blast then have "x \ A \ x \ B" using cover by auto then show False using cs [unfolded connected_def] by (metis A B IntI Sup_upper sa sb disjs x cover empty_iff subset_trans) qed lemma connected_Un: "connected s \ connected t \ s \ t \ {} \ connected (s \ t)" using connected_Union [of "{s,t}"] by auto lemma connected_diff_open_from_closed: assumes st: "s \ t" and tu: "t \ u" and s: "open s" and t: "closed t" and u: "connected u" and ts: "connected (t - s)" shows "connected(u - s)" proof (rule connectedI) fix A B assume AB: "open A" "open B" "A \ (u - s) \ {}" "B \ (u - s) \ {}" and disj: "A \ B \ (u - s) = {}" and cover: "u - s \ A \ B" then consider "A \ (t - s) = {}" | "B \ (t - s) = {}" using st ts tu connectedD [of "t-s" "A" "B"] by auto then show False proof cases case 1 then have "(A - t) \ (B \ s) \ u = {}" using disj st by auto moreover have "u \ (A - t) \ (B \ s)" using 1 cover by auto ultimately show False using connectedD [of u "A - t" "B \ s"] AB s t 1 u by auto next case 2 then have "(A \ s) \ (B - t) \ u = {}" using disj st by auto moreover have "u \ (A \ s) \ (B - t)" using 2 cover by auto ultimately show False using connectedD [of u "A \ s" "B - t"] AB s t 2 u by auto qed qed lemma connected_iff_const: fixes S :: "'a::topological_space set" shows "connected S \ (\P::'a \ bool. continuous_on S P \ (\c. \s\S. P s = c))" proof safe fix P :: "'a \ bool" assume "connected S" "continuous_on S P" then have "\b. \A. open A \ A \ S = P -` {b} \ S" unfolding continuous_on_open_invariant by (simp add: open_discrete) from this[of True] this[of False] obtain t f where "open t" "open f" and *: "f \ S = P -` {False} \ S" "t \ S = P -` {True} \ S" by meson then have "t \ S = {} \ f \ S = {}" by (intro connectedD[OF \connected S\]) auto then show "\c. \s\S. P s = c" proof (rule disjE) assume "t \ S = {}" then show ?thesis unfolding * by (intro exI[of _ False]) auto next assume "f \ S = {}" then show ?thesis unfolding * by (intro exI[of _ True]) auto qed next assume P: "\P::'a \ bool. continuous_on S P \ (\c. \s\S. P s = c)" show "connected S" proof (rule connectedI) fix A B assume *: "open A" "open B" "A \ S \ {}" "B \ S \ {}" "A \ B \ S = {}" "S \ A \ B" have "continuous_on S (\x. x \ A)" unfolding continuous_on_open_invariant proof safe fix C :: "bool set" have "C = UNIV \ C = {True} \ C = {False} \ C = {}" using subset_UNIV[of C] unfolding UNIV_bool by auto with * show "\T. open T \ T \ S = (\x. x \ A) -` C \ S" by (intro exI[of _ "(if True \ C then A else {}) \ (if False \ C then B else {})"]) auto qed from P[rule_format, OF this] obtain c where "\s. s \ S \ (s \ A) = c" by blast with * show False by (cases c) auto qed qed lemma connectedD_const: "connected S \ continuous_on S P \ \c. \s\S. P s = c" for P :: "'a::topological_space \ bool" by (auto simp: connected_iff_const) lemma connectedI_const: "(\P::'a::topological_space \ bool. continuous_on S P \ \c. \s\S. P s = c) \ connected S" by (auto simp: connected_iff_const) lemma connected_local_const: assumes "connected A" "a \ A" "b \ A" and *: "\a\A. eventually (\b. f a = f b) (at a within A)" shows "f a = f b" proof - obtain S where S: "\a. a \ A \ a \ S a" "\a. a \ A \ open (S a)" "\a x. a \ A \ x \ S a \ x \ A \ f a = f x" using * unfolding eventually_at_topological by metis let ?P = "\b\{b\A. f a = f b}. S b" and ?N = "\b\{b\A. f a \ f b}. S b" have "?P \ A = {} \ ?N \ A = {}" using \connected A\ S \a\A\ by (intro connectedD) (auto, metis) then show "f a = f b" proof assume "?N \ A = {}" then have "\x\A. f a = f x" using S(1) by auto with \b\A\ show ?thesis by auto next assume "?P \ A = {}" then show ?thesis using \a \ A\ S(1)[of a] by auto qed qed lemma (in linorder_topology) connectedD_interval: assumes "connected U" and xy: "x \ U" "y \ U" and "x \ z" "z \ y" shows "z \ U" proof - have eq: "{.. {z<..} = - {z}" by auto have "\ connected U" if "z \ U" "x < z" "z < y" using xy that apply (simp only: connected_def simp_thms) apply (rule_tac exI[of _ "{..< z}"]) apply (rule_tac exI[of _ "{z <..}"]) apply (auto simp add: eq) done with assms show "z \ U" by (metis less_le) qed lemma (in linorder_topology) not_in_connected_cases: assumes conn: "connected S" assumes nbdd: "x \ S" assumes ne: "S \ {}" obtains "bdd_above S" "\y. y \ S \ x \ y" | "bdd_below S" "\y. y \ S \ x \ y" proof - obtain s where "s \ S" using ne by blast { assume "s \ x" have "False" if "x \ y" "y \ S" for y using connectedD_interval[OF conn \s \ S\ \y \ S\ \s \ x\ \x \ y\] \x \ S\ by simp then have wit: "y \ S \ x \ y" for y using le_cases by blast then have "bdd_above S" by (rule local.bdd_aboveI) note this wit } moreover { assume "x \ s" have "False" if "x \ y" "y \ S" for y using connectedD_interval[OF conn \y \ S\ \s \ S\ \x \ y\ \s \ x\ ] \x \ S\ by simp then have wit: "y \ S \ x \ y" for y using le_cases by blast then have "bdd_below S" by (rule bdd_belowI) note this wit } ultimately show ?thesis by (meson le_cases that) qed lemma connected_continuous_image: assumes *: "continuous_on s f" and "connected s" shows "connected (f ` s)" proof (rule connectedI_const) fix P :: "'b \ bool" assume "continuous_on (f ` s) P" then have "continuous_on s (P \ f)" by (rule continuous_on_compose[OF *]) from connectedD_const[OF \connected s\ this] show "\c. \s\f ` s. P s = c" by auto qed section \Linear Continuum Topologies\ class linear_continuum_topology = linorder_topology + linear_continuum begin lemma Inf_notin_open: assumes A: "open A" and bnd: "\a\A. x < a" shows "Inf A \ A" proof assume "Inf A \ A" then obtain b where "b < Inf A" "{b <.. Inf A} \ A" using open_left[of A "Inf A" x] assms by auto with dense[of b "Inf A"] obtain c where "c < Inf A" "c \ A" by (auto simp: subset_eq) then show False using cInf_lower[OF \c \ A\] bnd by (metis not_le less_imp_le bdd_belowI) qed lemma Sup_notin_open: assumes A: "open A" and bnd: "\a\A. a < x" shows "Sup A \ A" proof assume "Sup A \ A" with assms obtain b where "Sup A < b" "{Sup A ..< b} \ A" using open_right[of A "Sup A" x] by auto with dense[of "Sup A" b] obtain c where "Sup A < c" "c \ A" by (auto simp: subset_eq) then show False using cSup_upper[OF \c \ A\] bnd by (metis less_imp_le not_le bdd_aboveI) qed end instance linear_continuum_topology \ perfect_space proof fix x :: 'a obtain y where "x < y \ y < x" using ex_gt_or_lt [of x] .. with Inf_notin_open[of "{x}" y] Sup_notin_open[of "{x}" y] show "\ open {x}" by auto qed lemma connectedI_interval: fixes U :: "'a :: linear_continuum_topology set" assumes *: "\x y z. x \ U \ y \ U \ x \ z \ z \ y \ z \ U" shows "connected U" proof (rule connectedI) { fix A B assume "open A" "open B" "A \ B \ U = {}" "U \ A \ B" fix x y assume "x < y" "x \ A" "y \ B" "x \ U" "y \ U" let ?z = "Inf (B \ {x <..})" have "x \ ?z" "?z \ y" using \y \ B\ \x < y\ by (auto intro: cInf_lower cInf_greatest) with \x \ U\ \y \ U\ have "?z \ U" by (rule *) moreover have "?z \ B \ {x <..}" using \open B\ by (intro Inf_notin_open) auto ultimately have "?z \ A" using \x \ ?z\ \A \ B \ U = {}\ \x \ A\ \U \ A \ B\ by auto have "\b\B. b \ A \ b \ U" if "?z < y" proof - obtain a where "?z < a" "{?z ..< a} \ A" using open_right[OF \open A\ \?z \ A\ \?z < y\] by auto moreover obtain b where "b \ B" "x < b" "b < min a y" using cInf_less_iff[of "B \ {x <..}" "min a y"] \?z < a\ \?z < y\ \x < y\ \y \ B\ by auto moreover have "?z \ b" using \b \ B\ \x < b\ by (intro cInf_lower) auto moreover have "b \ U" using \x \ ?z\ \?z \ b\ \b < min a y\ by (intro *[OF \x \ U\ \y \ U\]) (auto simp: less_imp_le) ultimately show ?thesis by (intro bexI[of _ b]) auto qed then have False using \?z \ y\ \?z \ A\ \y \ B\ \y \ U\ \A \ B \ U = {}\ unfolding le_less by blast } note not_disjoint = this fix A B assume AB: "open A" "open B" "U \ A \ B" "A \ B \ U = {}" moreover assume "A \ U \ {}" then obtain x where x: "x \ U" "x \ A" by auto moreover assume "B \ U \ {}" then obtain y where y: "y \ U" "y \ B" by auto moreover note not_disjoint[of B A y x] not_disjoint[of A B x y] ultimately show False by (cases x y rule: linorder_cases) auto qed lemma connected_iff_interval: "connected U \ (\x\U. \y\U. \z. x \ z \ z \ y \ z \ U)" for U :: "'a::linear_continuum_topology set" by (auto intro: connectedI_interval dest: connectedD_interval) lemma connected_UNIV[simp]: "connected (UNIV::'a::linear_continuum_topology set)" by (simp add: connected_iff_interval) lemma connected_Ioi[simp]: "connected {a<..}" for a :: "'a::linear_continuum_topology" by (auto simp: connected_iff_interval) lemma connected_Ici[simp]: "connected {a..}" for a :: "'a::linear_continuum_topology" by (auto simp: connected_iff_interval) lemma connected_Iio[simp]: "connected {.. A" "b \ A" shows "{a <..< b} \ A" using connectedD_interval[OF assms] by (simp add: subset_eq Ball_def less_imp_le) lemma connected_contains_Icc: fixes A :: "'a::linorder_topology set" assumes "connected A" "a \ A" "b \ A" shows "{a..b} \ A" proof fix x assume "x \ {a..b}" then have "x = a \ x = b \ x \ {a<.. A" using assms connected_contains_Ioo[of A a b] by auto qed subsection \Intermediate Value Theorem\ lemma IVT': fixes f :: "'a::linear_continuum_topology \ 'b::linorder_topology" assumes y: "f a \ y" "y \ f b" "a \ b" and *: "continuous_on {a .. b} f" shows "\x. a \ x \ x \ b \ f x = y" proof - have "connected {a..b}" unfolding connected_iff_interval by auto from connected_continuous_image[OF * this, THEN connectedD_interval, of "f a" "f b" y] y show ?thesis by (auto simp add: atLeastAtMost_def atLeast_def atMost_def) qed lemma IVT2': fixes f :: "'a :: linear_continuum_topology \ 'b :: linorder_topology" assumes y: "f b \ y" "y \ f a" "a \ b" and *: "continuous_on {a .. b} f" shows "\x. a \ x \ x \ b \ f x = y" proof - have "connected {a..b}" unfolding connected_iff_interval by auto from connected_continuous_image[OF * this, THEN connectedD_interval, of "f b" "f a" y] y show ?thesis by (auto simp add: atLeastAtMost_def atLeast_def atMost_def) qed lemma IVT: fixes f :: "'a::linear_continuum_topology \ 'b::linorder_topology" shows "f a \ y \ y \ f b \ a \ b \ (\x. a \ x \ x \ b \ isCont f x) \ \x. a \ x \ x \ b \ f x = y" by (rule IVT') (auto intro: continuous_at_imp_continuous_on) lemma IVT2: fixes f :: "'a::linear_continuum_topology \ 'b::linorder_topology" shows "f b \ y \ y \ f a \ a \ b \ (\x. a \ x \ x \ b \ isCont f x) \ \x. a \ x \ x \ b \ f x = y" by (rule IVT2') (auto intro: continuous_at_imp_continuous_on) lemma continuous_inj_imp_mono: fixes f :: "'a::linear_continuum_topology \ 'b::linorder_topology" assumes x: "a < x" "x < b" and cont: "continuous_on {a..b} f" and inj: "inj_on f {a..b}" shows "(f a < f x \ f x < f b) \ (f b < f x \ f x < f a)" proof - note I = inj_on_eq_iff[OF inj] { assume "f x < f a" "f x < f b" then obtain s t where "x \ s" "s \ b" "a \ t" "t \ x" "f s = f t" "f x < f s" using IVT'[of f x "min (f a) (f b)" b] IVT2'[of f x "min (f a) (f b)" a] x by (auto simp: continuous_on_subset[OF cont] less_imp_le) with x I have False by auto } moreover { assume "f a < f x" "f b < f x" then obtain s t where "x \ s" "s \ b" "a \ t" "t \ x" "f s = f t" "f s < f x" using IVT'[of f a "max (f a) (f b)" x] IVT2'[of f b "max (f a) (f b)" x] x by (auto simp: continuous_on_subset[OF cont] less_imp_le) with x I have False by auto } ultimately show ?thesis using I[of a x] I[of x b] x less_trans[OF x] by (auto simp add: le_less less_imp_neq neq_iff) qed lemma continuous_at_Sup_mono: fixes f :: "'a::{linorder_topology,conditionally_complete_linorder} \ 'b::{linorder_topology,conditionally_complete_linorder}" assumes "mono f" and cont: "continuous (at_left (Sup S)) f" and S: "S \ {}" "bdd_above S" shows "f (Sup S) = (SUP s\S. f s)" proof (rule antisym) have f: "(f \ f (Sup S)) (at_left (Sup S))" using cont unfolding continuous_within . show "f (Sup S) \ (SUP s\S. f s)" proof cases assume "Sup S \ S" then show ?thesis by (rule cSUP_upper) (auto intro: bdd_above_image_mono S \mono f\) next assume "Sup S \ S" from \S \ {}\ obtain s where "s \ S" by auto with \Sup S \ S\ S have "s < Sup S" unfolding less_le by (blast intro: cSup_upper) show ?thesis proof (rule ccontr) assume "\ ?thesis" with order_tendstoD(1)[OF f, of "SUP s\S. f s"] obtain b where "b < Sup S" and *: "\y. b < y \ y < Sup S \ (SUP s\S. f s) < f y" by (auto simp: not_le eventually_at_left[OF \s < Sup S\]) with \S \ {}\ obtain c where "c \ S" "b < c" using less_cSupD[of S b] by auto with \Sup S \ S\ S have "c < Sup S" unfolding less_le by (blast intro: cSup_upper) from *[OF \b < c\ \c < Sup S\] cSUP_upper[OF \c \ S\ bdd_above_image_mono[of f]] show False by (auto simp: assms) qed qed qed (intro cSUP_least \mono f\[THEN monoD] cSup_upper S) lemma continuous_at_Sup_antimono: fixes f :: "'a::{linorder_topology,conditionally_complete_linorder} \ 'b::{linorder_topology,conditionally_complete_linorder}" assumes "antimono f" and cont: "continuous (at_left (Sup S)) f" and S: "S \ {}" "bdd_above S" shows "f (Sup S) = (INF s\S. f s)" proof (rule antisym) have f: "(f \ f (Sup S)) (at_left (Sup S))" using cont unfolding continuous_within . show "(INF s\S. f s) \ f (Sup S)" proof cases assume "Sup S \ S" then show ?thesis by (intro cINF_lower) (auto intro: bdd_below_image_antimono S \antimono f\) next assume "Sup S \ S" from \S \ {}\ obtain s where "s \ S" by auto with \Sup S \ S\ S have "s < Sup S" unfolding less_le by (blast intro: cSup_upper) show ?thesis proof (rule ccontr) assume "\ ?thesis" with order_tendstoD(2)[OF f, of "INF s\S. f s"] obtain b where "b < Sup S" and *: "\y. b < y \ y < Sup S \ f y < (INF s\S. f s)" by (auto simp: not_le eventually_at_left[OF \s < Sup S\]) with \S \ {}\ obtain c where "c \ S" "b < c" using less_cSupD[of S b] by auto with \Sup S \ S\ S have "c < Sup S" unfolding less_le by (blast intro: cSup_upper) from *[OF \b < c\ \c < Sup S\] cINF_lower[OF bdd_below_image_antimono, of f S c] \c \ S\ show False by (auto simp: assms) qed qed qed (intro cINF_greatest \antimono f\[THEN antimonoD] cSup_upper S) lemma continuous_at_Inf_mono: fixes f :: "'a::{linorder_topology,conditionally_complete_linorder} \ 'b::{linorder_topology,conditionally_complete_linorder}" assumes "mono f" and cont: "continuous (at_right (Inf S)) f" and S: "S \ {}" "bdd_below S" shows "f (Inf S) = (INF s\S. f s)" proof (rule antisym) have f: "(f \ f (Inf S)) (at_right (Inf S))" using cont unfolding continuous_within . show "(INF s\S. f s) \ f (Inf S)" proof cases assume "Inf S \ S" then show ?thesis by (rule cINF_lower[rotated]) (auto intro: bdd_below_image_mono S \mono f\) next assume "Inf S \ S" from \S \ {}\ obtain s where "s \ S" by auto with \Inf S \ S\ S have "Inf S < s" unfolding less_le by (blast intro: cInf_lower) show ?thesis proof (rule ccontr) assume "\ ?thesis" with order_tendstoD(2)[OF f, of "INF s\S. f s"] obtain b where "Inf S < b" and *: "\y. Inf S < y \ y < b \ f y < (INF s\S. f s)" by (auto simp: not_le eventually_at_right[OF \Inf S < s\]) with \S \ {}\ obtain c where "c \ S" "c < b" using cInf_lessD[of S b] by auto with \Inf S \ S\ S have "Inf S < c" unfolding less_le by (blast intro: cInf_lower) from *[OF \Inf S < c\ \c < b\] cINF_lower[OF bdd_below_image_mono[of f] \c \ S\] show False by (auto simp: assms) qed qed qed (intro cINF_greatest \mono f\[THEN monoD] cInf_lower \bdd_below S\ \S \ {}\) lemma continuous_at_Inf_antimono: fixes f :: "'a::{linorder_topology,conditionally_complete_linorder} \ 'b::{linorder_topology,conditionally_complete_linorder}" assumes "antimono f" and cont: "continuous (at_right (Inf S)) f" and S: "S \ {}" "bdd_below S" shows "f (Inf S) = (SUP s\S. f s)" proof (rule antisym) have f: "(f \ f (Inf S)) (at_right (Inf S))" using cont unfolding continuous_within . show "f (Inf S) \ (SUP s\S. f s)" proof cases assume "Inf S \ S" then show ?thesis by (rule cSUP_upper) (auto intro: bdd_above_image_antimono S \antimono f\) next assume "Inf S \ S" from \S \ {}\ obtain s where "s \ S" by auto with \Inf S \ S\ S have "Inf S < s" unfolding less_le by (blast intro: cInf_lower) show ?thesis proof (rule ccontr) assume "\ ?thesis" with order_tendstoD(1)[OF f, of "SUP s\S. f s"] obtain b where "Inf S < b" and *: "\y. Inf S < y \ y < b \ (SUP s\S. f s) < f y" by (auto simp: not_le eventually_at_right[OF \Inf S < s\]) with \S \ {}\ obtain c where "c \ S" "c < b" using cInf_lessD[of S b] by auto with \Inf S \ S\ S have "Inf S < c" unfolding less_le by (blast intro: cInf_lower) from *[OF \Inf S < c\ \c < b\] cSUP_upper[OF \c \ S\ bdd_above_image_antimono[of f]] show False by (auto simp: assms) qed qed qed (intro cSUP_least \antimono f\[THEN antimonoD] cInf_lower S) subsection \Uniform spaces\ class uniformity = fixes uniformity :: "('a \ 'a) filter" begin abbreviation uniformity_on :: "'a set \ ('a \ 'a) filter" where "uniformity_on s \ inf uniformity (principal (s\s))" end lemma uniformity_Abort: "uniformity = Filter.abstract_filter (\u. Code.abort (STR ''uniformity is not executable'') (\u. uniformity))" by simp class open_uniformity = "open" + uniformity + assumes open_uniformity: "\U. open U \ (\x\U. eventually (\(x', y). x' = x \ y \ U) uniformity)" begin subclass topological_space by standard (force elim: eventually_mono eventually_elim2 simp: split_beta' open_uniformity)+ end class uniform_space = open_uniformity + assumes uniformity_refl: "eventually E uniformity \ E (x, x)" and uniformity_sym: "eventually E uniformity \ eventually (\(x, y). E (y, x)) uniformity" and uniformity_trans: "eventually E uniformity \ \D. eventually D uniformity \ (\x y z. D (x, y) \ D (y, z) \ E (x, z))" begin lemma uniformity_bot: "uniformity \ bot" using uniformity_refl by auto lemma uniformity_trans': "eventually E uniformity \ eventually (\((x, y), (y', z)). y = y' \ E (x, z)) (uniformity \\<^sub>F uniformity)" by (drule uniformity_trans) (auto simp add: eventually_prod_same) lemma uniformity_transE: assumes "eventually E uniformity" obtains D where "eventually D uniformity" "\x y z. D (x, y) \ D (y, z) \ E (x, z)" using uniformity_trans [OF assms] by auto lemma eventually_nhds_uniformity: "eventually P (nhds x) \ eventually (\(x', y). x' = x \ P y) uniformity" (is "_ \ ?N P x") unfolding eventually_nhds proof safe assume *: "?N P x" have "?N (?N P) x" if "?N P x" for x proof - from that obtain D where ev: "eventually D uniformity" and D: "D (a, b) \ D (b, c) \ case (a, c) of (x', y) \ x' = x \ P y" for a b c by (rule uniformity_transE) simp from ev show ?thesis by eventually_elim (insert ev D, force elim: eventually_mono split: prod.split) qed then have "open {x. ?N P x}" by (simp add: open_uniformity) then show "\S. open S \ x \ S \ (\x\S. P x)" by (intro exI[of _ "{x. ?N P x}"]) (auto dest: uniformity_refl simp: *) qed (force simp add: open_uniformity elim: eventually_mono) subsubsection \Totally bounded sets\ definition totally_bounded :: "'a set \ bool" where "totally_bounded S \ (\E. eventually E uniformity \ (\X. finite X \ (\s\S. \x\X. E (x, s))))" lemma totally_bounded_empty[iff]: "totally_bounded {}" by (auto simp add: totally_bounded_def) lemma totally_bounded_subset: "totally_bounded S \ T \ S \ totally_bounded T" by (fastforce simp add: totally_bounded_def) lemma totally_bounded_Union[intro]: assumes M: "finite M" "\S. S \ M \ totally_bounded S" shows "totally_bounded (\M)" unfolding totally_bounded_def proof safe fix E assume "eventually E uniformity" with M obtain X where "\S\M. finite (X S) \ (\s\S. \x\X S. E (x, s))" by (metis totally_bounded_def) with \finite M\ show "\X. finite X \ (\s\\M. \x\X. E (x, s))" by (intro exI[of _ "\S\M. X S"]) force qed subsubsection \Cauchy filter\ definition cauchy_filter :: "'a filter \ bool" where "cauchy_filter F \ F \\<^sub>F F \ uniformity" definition Cauchy :: "(nat \ 'a) \ bool" where Cauchy_uniform: "Cauchy X = cauchy_filter (filtermap X sequentially)" lemma Cauchy_uniform_iff: "Cauchy X \ (\P. eventually P uniformity \ (\N. \n\N. \m\N. P (X n, X m)))" unfolding Cauchy_uniform cauchy_filter_def le_filter_def eventually_prod_same eventually_filtermap eventually_sequentially proof safe let ?U = "\P. eventually P uniformity" { fix P assume "?U P" "\P. ?U P \ (\Q. (\N. \n\N. Q (X n)) \ (\x y. Q x \ Q y \ P (x, y)))" then obtain Q N where "\n. n \ N \ Q (X n)" "\x y. Q x \ Q y \ P (x, y)" by metis then show "\N. \n\N. \m\N. P (X n, X m)" by blast next fix P assume "?U P" and P: "\P. ?U P \ (\N. \n\N. \m\N. P (X n, X m))" then obtain Q where "?U Q" and Q: "\x y z. Q (x, y) \ Q (y, z) \ P (x, z)" by (auto elim: uniformity_transE) then have "?U (\x. Q x \ (\(x, y). Q (y, x)) x)" unfolding eventually_conj_iff by (simp add: uniformity_sym) from P[rule_format, OF this] obtain N where N: "\n m. n \ N \ m \ N \ Q (X n, X m) \ Q (X m, X n)" by auto show "\Q. (\N. \n\N. Q (X n)) \ (\x y. Q x \ Q y \ P (x, y))" proof (safe intro!: exI[of _ "\x. \n\N. Q (x, X n) \ Q (X n, x)"] exI[of _ N] N) fix x y assume "\n\N. Q (x, X n) \ Q (X n, x)" "\n\N. Q (y, X n) \ Q (X n, y)" then have "Q (x, X N)" "Q (X N, y)" by auto then show "P (x, y)" by (rule Q) qed } qed lemma nhds_imp_cauchy_filter: assumes *: "F \ nhds x" shows "cauchy_filter F" proof - have "F \\<^sub>F F \ nhds x \\<^sub>F nhds x" by (intro prod_filter_mono *) also have "\ \ uniformity" unfolding le_filter_def eventually_nhds_uniformity eventually_prod_same proof safe fix P assume "eventually P uniformity" then obtain Ql where ev: "eventually Ql uniformity" and "Ql (x, y) \ Ql (y, z) \ P (x, z)" for x y z by (rule uniformity_transE) simp with ev[THEN uniformity_sym] show "\Q. eventually (\(x', y). x' = x \ Q y) uniformity \ (\x y. Q x \ Q y \ P (x, y))" by (rule_tac exI[of _ "\y. Ql (y, x) \ Ql (x, y)"]) (fastforce elim: eventually_elim2) qed finally show ?thesis by (simp add: cauchy_filter_def) qed lemma LIMSEQ_imp_Cauchy: "X \ x \ Cauchy X" unfolding Cauchy_uniform filterlim_def by (intro nhds_imp_cauchy_filter) lemma Cauchy_subseq_Cauchy: assumes "Cauchy X" "strict_mono f" shows "Cauchy (X \ f)" unfolding Cauchy_uniform comp_def filtermap_filtermap[symmetric] cauchy_filter_def by (rule order_trans[OF _ \Cauchy X\[unfolded Cauchy_uniform cauchy_filter_def]]) (intro prod_filter_mono filtermap_mono filterlim_subseq[OF \strict_mono f\, unfolded filterlim_def]) lemma convergent_Cauchy: "convergent X \ Cauchy X" unfolding convergent_def by (erule exE, erule LIMSEQ_imp_Cauchy) definition complete :: "'a set \ bool" where complete_uniform: "complete S \ (\F \ principal S. F \ bot \ cauchy_filter F \ (\x\S. F \ nhds x))" end subsubsection \Uniformly continuous functions\ definition uniformly_continuous_on :: "'a set \ ('a::uniform_space \ 'b::uniform_space) \ bool" where uniformly_continuous_on_uniformity: "uniformly_continuous_on s f \ (LIM (x, y) (uniformity_on s). (f x, f y) :> uniformity)" lemma uniformly_continuous_onD: "uniformly_continuous_on s f \ eventually E uniformity \ eventually (\(x, y). x \ s \ y \ s \ E (f x, f y)) uniformity" by (simp add: uniformly_continuous_on_uniformity filterlim_iff eventually_inf_principal split_beta' mem_Times_iff imp_conjL) lemma uniformly_continuous_on_const[continuous_intros]: "uniformly_continuous_on s (\x. c)" by (auto simp: uniformly_continuous_on_uniformity filterlim_iff uniformity_refl) lemma uniformly_continuous_on_id[continuous_intros]: "uniformly_continuous_on s (\x. x)" by (auto simp: uniformly_continuous_on_uniformity filterlim_def) lemma uniformly_continuous_on_compose[continuous_intros]: "uniformly_continuous_on s g \ uniformly_continuous_on (g`s) f \ uniformly_continuous_on s (\x. f (g x))" using filterlim_compose[of "\(x, y). (f x, f y)" uniformity "uniformity_on (g`s)" "\(x, y). (g x, g y)" "uniformity_on s"] by (simp add: split_beta' uniformly_continuous_on_uniformity filterlim_inf filterlim_principal eventually_inf_principal mem_Times_iff) lemma uniformly_continuous_imp_continuous: assumes f: "uniformly_continuous_on s f" shows "continuous_on s f" by (auto simp: filterlim_iff eventually_at_filter eventually_nhds_uniformity continuous_on_def elim: eventually_mono dest!: uniformly_continuous_onD[OF f]) section \Product Topology\ subsection \Product is a topological space\ instantiation prod :: (topological_space, topological_space) topological_space begin definition open_prod_def[code del]: "open (S :: ('a \ 'b) set) \ (\x\S. \A B. open A \ open B \ x \ A \ B \ A \ B \ S)" lemma open_prod_elim: assumes "open S" and "x \ S" obtains A B where "open A" and "open B" and "x \ A \ B" and "A \ B \ S" using assms unfolding open_prod_def by fast lemma open_prod_intro: assumes "\x. x \ S \ \A B. open A \ open B \ x \ A \ B \ A \ B \ S" shows "open S" using assms unfolding open_prod_def by fast instance proof show "open (UNIV :: ('a \ 'b) set)" unfolding open_prod_def by auto next fix S T :: "('a \ 'b) set" assume "open S" "open T" show "open (S \ T)" proof (rule open_prod_intro) fix x assume x: "x \ S \ T" from x have "x \ S" by simp obtain Sa Sb where A: "open Sa" "open Sb" "x \ Sa \ Sb" "Sa \ Sb \ S" using \open S\ and \x \ S\ by (rule open_prod_elim) from x have "x \ T" by simp obtain Ta Tb where B: "open Ta" "open Tb" "x \ Ta \ Tb" "Ta \ Tb \ T" using \open T\ and \x \ T\ by (rule open_prod_elim) let ?A = "Sa \ Ta" and ?B = "Sb \ Tb" have "open ?A \ open ?B \ x \ ?A \ ?B \ ?A \ ?B \ S \ T" using A B by (auto simp add: open_Int) then show "\A B. open A \ open B \ x \ A \ B \ A \ B \ S \ T" by fast qed next fix K :: "('a \ 'b) set set" assume "\S\K. open S" then show "open (\K)" unfolding open_prod_def by fast qed end declare [[code abort: "open :: ('a::topological_space \ 'b::topological_space) set \ bool"]] lemma open_Times: "open S \ open T \ open (S \ T)" unfolding open_prod_def by auto lemma fst_vimage_eq_Times: "fst -` S = S \ UNIV" by auto lemma snd_vimage_eq_Times: "snd -` S = UNIV \ S" by auto lemma open_vimage_fst: "open S \ open (fst -` S)" by (simp add: fst_vimage_eq_Times open_Times) lemma open_vimage_snd: "open S \ open (snd -` S)" by (simp add: snd_vimage_eq_Times open_Times) lemma closed_vimage_fst: "closed S \ closed (fst -` S)" unfolding closed_open vimage_Compl [symmetric] by (rule open_vimage_fst) lemma closed_vimage_snd: "closed S \ closed (snd -` S)" unfolding closed_open vimage_Compl [symmetric] by (rule open_vimage_snd) lemma closed_Times: "closed S \ closed T \ closed (S \ T)" proof - have "S \ T = (fst -` S) \ (snd -` T)" by auto then show "closed S \ closed T \ closed (S \ T)" by (simp add: closed_vimage_fst closed_vimage_snd closed_Int) qed lemma subset_fst_imageI: "A \ B \ S \ y \ B \ A \ fst ` S" unfolding image_def subset_eq by force lemma subset_snd_imageI: "A \ B \ S \ x \ A \ B \ snd ` S" unfolding image_def subset_eq by force lemma open_image_fst: assumes "open S" shows "open (fst ` S)" proof (rule openI) fix x assume "x \ fst ` S" then obtain y where "(x, y) \ S" by auto then obtain A B where "open A" "open B" "x \ A" "y \ B" "A \ B \ S" using \open S\ unfolding open_prod_def by auto from \A \ B \ S\ \y \ B\ have "A \ fst ` S" by (rule subset_fst_imageI) with \open A\ \x \ A\ have "open A \ x \ A \ A \ fst ` S" by simp then show "\T. open T \ x \ T \ T \ fst ` S" .. qed lemma open_image_snd: assumes "open S" shows "open (snd ` S)" proof (rule openI) fix y assume "y \ snd ` S" then obtain x where "(x, y) \ S" by auto then obtain A B where "open A" "open B" "x \ A" "y \ B" "A \ B \ S" using \open S\ unfolding open_prod_def by auto from \A \ B \ S\ \x \ A\ have "B \ snd ` S" by (rule subset_snd_imageI) with \open B\ \y \ B\ have "open B \ y \ B \ B \ snd ` S" by simp then show "\T. open T \ y \ T \ T \ snd ` S" .. qed lemma nhds_prod: "nhds (a, b) = nhds a \\<^sub>F nhds b" unfolding nhds_def proof (subst prod_filter_INF, auto intro!: antisym INF_greatest simp: principal_prod_principal) fix S T assume "open S" "a \ S" "open T" "b \ T" then show "(INF x \ {S. open S \ (a, b) \ S}. principal x) \ principal (S \ T)" by (intro INF_lower) (auto intro!: open_Times) next fix S' assume "open S'" "(a, b) \ S'" then obtain S T where "open S" "a \ S" "open T" "b \ T" "S \ T \ S'" by (auto elim: open_prod_elim) then show "(INF x \ {S. open S \ a \ S}. INF y \ {S. open S \ b \ S}. principal (x \ y)) \ principal S'" by (auto intro!: INF_lower2) qed subsubsection \Continuity of operations\ lemma tendsto_fst [tendsto_intros]: assumes "(f \ a) F" shows "((\x. fst (f x)) \ fst a) F" proof (rule topological_tendstoI) fix S assume "open S" and "fst a \ S" then have "open (fst -` S)" and "a \ fst -` S" by (simp_all add: open_vimage_fst) with assms have "eventually (\x. f x \ fst -` S) F" by (rule topological_tendstoD) then show "eventually (\x. fst (f x) \ S) F" by simp qed lemma tendsto_snd [tendsto_intros]: assumes "(f \ a) F" shows "((\x. snd (f x)) \ snd a) F" proof (rule topological_tendstoI) fix S assume "open S" and "snd a \ S" then have "open (snd -` S)" and "a \ snd -` S" by (simp_all add: open_vimage_snd) with assms have "eventually (\x. f x \ snd -` S) F" by (rule topological_tendstoD) then show "eventually (\x. snd (f x) \ S) F" by simp qed lemma tendsto_Pair [tendsto_intros]: assumes "(f \ a) F" and "(g \ b) F" shows "((\x. (f x, g x)) \ (a, b)) F" unfolding nhds_prod using assms by (rule filterlim_Pair) lemma continuous_fst[continuous_intros]: "continuous F f \ continuous F (\x. fst (f x))" unfolding continuous_def by (rule tendsto_fst) lemma continuous_snd[continuous_intros]: "continuous F f \ continuous F (\x. snd (f x))" unfolding continuous_def by (rule tendsto_snd) lemma continuous_Pair[continuous_intros]: "continuous F f \ continuous F g \ continuous F (\x. (f x, g x))" unfolding continuous_def by (rule tendsto_Pair) lemma continuous_on_fst[continuous_intros]: "continuous_on s f \ continuous_on s (\x. fst (f x))" unfolding continuous_on_def by (auto intro: tendsto_fst) lemma continuous_on_snd[continuous_intros]: "continuous_on s f \ continuous_on s (\x. snd (f x))" unfolding continuous_on_def by (auto intro: tendsto_snd) lemma continuous_on_Pair[continuous_intros]: "continuous_on s f \ continuous_on s g \ continuous_on s (\x. (f x, g x))" unfolding continuous_on_def by (auto intro: tendsto_Pair) lemma continuous_on_swap[continuous_intros]: "continuous_on A prod.swap" by (simp add: prod.swap_def continuous_on_fst continuous_on_snd continuous_on_Pair continuous_on_id) lemma continuous_on_swap_args: assumes "continuous_on (A\B) (\(x,y). d x y)" shows "continuous_on (B\A) (\(x,y). d y x)" proof - have "(\(x,y). d y x) = (\(x,y). d x y) \ prod.swap" by force then show ?thesis by (metis assms continuous_on_compose continuous_on_swap product_swap) qed lemma isCont_fst [simp]: "isCont f a \ isCont (\x. fst (f x)) a" by (fact continuous_fst) lemma isCont_snd [simp]: "isCont f a \ isCont (\x. snd (f x)) a" by (fact continuous_snd) lemma isCont_Pair [simp]: "\isCont f a; isCont g a\ \ isCont (\x. (f x, g x)) a" by (fact continuous_Pair) lemma continuous_on_compose_Pair: assumes f: "continuous_on (Sigma A B) (\(a, b). f a b)" assumes g: "continuous_on C g" assumes h: "continuous_on C h" assumes subset: "\c. c \ C \ g c \ A" "\c. c \ C \ h c \ B (g c)" shows "continuous_on C (\c. f (g c) (h c))" using continuous_on_compose2[OF f continuous_on_Pair[OF g h]] subset by auto subsubsection \Connectedness of products\ proposition connected_Times: assumes S: "connected S" and T: "connected T" shows "connected (S \ T)" proof (rule connectedI_const) fix P::"'a \ 'b \ bool" assume P[THEN continuous_on_compose2, continuous_intros]: "continuous_on (S \ T) P" have "continuous_on S (\s. P (s, t))" if "t \ T" for t by (auto intro!: continuous_intros that) from connectedD_const[OF S this] obtain c1 where c1: "\s t. t \ T \ s \ S \ P (s, t) = c1 t" by metis moreover have "continuous_on T (\t. P (s, t))" if "s \ S" for s by (auto intro!: continuous_intros that) from connectedD_const[OF T this] obtain c2 where "\s t. t \ T \ s \ S \ P (s, t) = c2 s" by metis ultimately show "\c. \s\S \ T. P s = c" by auto qed corollary connected_Times_eq [simp]: "connected (S \ T) \ S = {} \ T = {} \ connected S \ connected T" (is "?lhs = ?rhs") proof assume L: ?lhs show ?rhs proof cases assume "S \ {} \ T \ {}" moreover have "connected (fst ` (S \ T))" "connected (snd ` (S \ T))" using continuous_on_fst continuous_on_snd continuous_on_id by (blast intro: connected_continuous_image [OF _ L])+ ultimately show ?thesis by auto qed auto qed (auto simp: connected_Times) subsubsection \Separation axioms\ instance prod :: (t0_space, t0_space) t0_space proof fix x y :: "'a \ 'b" assume "x \ y" then have "fst x \ fst y \ snd x \ snd y" by (simp add: prod_eq_iff) then show "\U. open U \ (x \ U) \ (y \ U)" by (fast dest: t0_space elim: open_vimage_fst open_vimage_snd) qed instance prod :: (t1_space, t1_space) t1_space proof fix x y :: "'a \ 'b" assume "x \ y" then have "fst x \ fst y \ snd x \ snd y" by (simp add: prod_eq_iff) then show "\U. open U \ x \ U \ y \ U" by (fast dest: t1_space elim: open_vimage_fst open_vimage_snd) qed instance prod :: (t2_space, t2_space) t2_space proof fix x y :: "'a \ 'b" assume "x \ y" then have "fst x \ fst y \ snd x \ snd y" by (simp add: prod_eq_iff) then show "\U V. open U \ open V \ x \ U \ y \ V \ U \ V = {}" by (fast dest: hausdorff elim: open_vimage_fst open_vimage_snd) qed lemma isCont_swap[continuous_intros]: "isCont prod.swap a" using continuous_on_eq_continuous_within continuous_on_swap by blast lemma open_diagonal_complement: "open {(x,y) |x y. x \ (y::('a::t2_space))}" proof - have "open {(x, y). x \ (y::'a)}" unfolding split_def by (intro open_Collect_neq continuous_intros) also have "{(x, y). x \ (y::'a)} = {(x, y) |x y. x \ (y::'a)}" by auto finally show ?thesis . qed lemma closed_diagonal: "closed {y. \ x::('a::t2_space). y = (x,x)}" proof - have "{y. \ x::'a. y = (x,x)} = UNIV - {(x,y) | x y. x \ y}" by auto then show ?thesis using open_diagonal_complement closed_Diff by auto qed lemma open_superdiagonal: "open {(x,y) | x y. x > (y::'a::{linorder_topology})}" proof - have "open {(x, y). x > (y::'a)}" unfolding split_def by (intro open_Collect_less continuous_intros) also have "{(x, y). x > (y::'a)} = {(x, y) |x y. x > (y::'a)}" by auto finally show ?thesis . qed lemma closed_subdiagonal: "closed {(x,y) | x y. x \ (y::'a::{linorder_topology})}" proof - have "{(x,y) | x y. x \ (y::'a)} = UNIV - {(x,y) | x y. x > (y::'a)}" by auto then show ?thesis using open_superdiagonal closed_Diff by auto qed lemma open_subdiagonal: "open {(x,y) | x y. x < (y::'a::{linorder_topology})}" proof - have "open {(x, y). x < (y::'a)}" unfolding split_def by (intro open_Collect_less continuous_intros) also have "{(x, y). x < (y::'a)} = {(x, y) |x y. x < (y::'a)}" by auto finally show ?thesis . qed lemma closed_superdiagonal: "closed {(x,y) | x y. x \ (y::('a::{linorder_topology}))}" proof - have "{(x,y) | x y. x \ (y::'a)} = UNIV - {(x,y) | x y. x < y}" by auto then show ?thesis using open_subdiagonal closed_Diff by auto qed end