krauss@40107: (* Title: HOL/Partial_Function.thy krauss@40107: Author: Alexander Krauss, TU Muenchen krauss@40107: *) krauss@40107: krauss@40107: header {* Partial Function Definitions *} krauss@40107: krauss@40107: theory Partial_Function krauss@40107: imports Complete_Partial_Order Option krauss@40107: uses krauss@40107: "Tools/Function/function_lib.ML" krauss@40107: "Tools/Function/partial_function.ML" krauss@40107: begin krauss@40107: krauss@40107: setup Partial_Function.setup krauss@40107: krauss@40107: subsection {* Axiomatic setup *} krauss@40107: krauss@40107: text {* This techical locale constains the requirements for function krauss@42949: definitions with ccpo fixed points. *} krauss@40107: krauss@40107: definition "fun_ord ord f g \ (\x. ord (f x) (g x))" krauss@40107: definition "fun_lub L A = (\x. L {y. \f\A. y = f x})" krauss@40107: definition "img_ord f ord = (\x y. ord (f x) (f y))" krauss@40107: definition "img_lub f g Lub = (\A. g (Lub (f ` A)))" krauss@40107: krauss@40107: lemma call_mono[partial_function_mono]: "monotone (fun_ord ord) ord (\f. f t)" krauss@40107: by (rule monotoneI) (auto simp: fun_ord_def) krauss@40107: krauss@40288: lemma let_mono[partial_function_mono]: krauss@40288: "(\x. monotone orda ordb (\f. b f x)) krauss@40288: \ monotone orda ordb (\f. Let t (b f))" krauss@40288: by (simp add: Let_def) krauss@40288: krauss@40107: lemma if_mono[partial_function_mono]: "monotone orda ordb F krauss@40107: \ monotone orda ordb G krauss@40107: \ monotone orda ordb (\f. if c then F f else G f)" krauss@40107: unfolding monotone_def by simp krauss@40107: krauss@40107: definition "mk_less R = (\x y. R x y \ \ R y x)" krauss@40107: krauss@40107: locale partial_function_definitions = krauss@40107: fixes leq :: "'a \ 'a \ bool" krauss@40107: fixes lub :: "'a set \ 'a" krauss@40107: assumes leq_refl: "leq x x" krauss@40107: assumes leq_trans: "leq x y \ leq y z \ leq x z" krauss@40107: assumes leq_antisym: "leq x y \ leq y x \ x = y" krauss@40107: assumes lub_upper: "chain leq A \ x \ A \ leq x (lub A)" krauss@40107: assumes lub_least: "chain leq A \ (\x. x \ A \ leq x z) \ leq (lub A) z" krauss@40107: krauss@40107: lemma partial_function_lift: krauss@40107: assumes "partial_function_definitions ord lb" krauss@40107: shows "partial_function_definitions (fun_ord ord) (fun_lub lb)" (is "partial_function_definitions ?ordf ?lubf") krauss@40107: proof - krauss@40107: interpret partial_function_definitions ord lb by fact krauss@40107: krauss@40107: { fix A a assume A: "chain ?ordf A" krauss@40107: have "chain ord {y. \f\A. y = f a}" (is "chain ord ?C") krauss@40107: proof (rule chainI) krauss@40107: fix x y assume "x \ ?C" "y \ ?C" krauss@40107: then obtain f g where fg: "f \ A" "g \ A" krauss@40107: and [simp]: "x = f a" "y = g a" by blast krauss@40107: from chainD[OF A fg] krauss@40107: show "ord x y \ ord y x" unfolding fun_ord_def by auto krauss@40107: qed } krauss@40107: note chain_fun = this krauss@40107: krauss@40107: show ?thesis krauss@40107: proof krauss@40107: fix x show "?ordf x x" krauss@40107: unfolding fun_ord_def by (auto simp: leq_refl) krauss@40107: next krauss@40107: fix x y z assume "?ordf x y" "?ordf y z" krauss@40107: thus "?ordf x z" unfolding fun_ord_def krauss@40107: by (force dest: leq_trans) krauss@40107: next krauss@40107: fix x y assume "?ordf x y" "?ordf y x" krauss@40107: thus "x = y" unfolding fun_ord_def krauss@40107: by (force intro!: ext dest: leq_antisym) krauss@40107: next krauss@40107: fix A f assume f: "f \ A" and A: "chain ?ordf A" krauss@40107: thus "?ordf f (?lubf A)" krauss@40107: unfolding fun_lub_def fun_ord_def krauss@40107: by (blast intro: lub_upper chain_fun[OF A] f) krauss@40107: next krauss@40107: fix A :: "('b \ 'a) set" and g :: "'b \ 'a" krauss@40107: assume A: "chain ?ordf A" and g: "\f. f \ A \ ?ordf f g" krauss@40107: show "?ordf (?lubf A) g" unfolding fun_lub_def fun_ord_def krauss@40107: by (blast intro: lub_least chain_fun[OF A] dest: g[unfolded fun_ord_def]) krauss@40107: qed krauss@40107: qed krauss@40107: krauss@40107: lemma ccpo: assumes "partial_function_definitions ord lb" krauss@40107: shows "class.ccpo ord (mk_less ord) lb" krauss@40107: using assms unfolding partial_function_definitions_def mk_less_def krauss@40107: by unfold_locales blast+ krauss@40107: krauss@40107: lemma partial_function_image: krauss@40107: assumes "partial_function_definitions ord Lub" krauss@40107: assumes inj: "\x y. f x = f y \ x = y" krauss@40107: assumes inv: "\x. f (g x) = x" krauss@40107: shows "partial_function_definitions (img_ord f ord) (img_lub f g Lub)" krauss@40107: proof - krauss@40107: let ?iord = "img_ord f ord" krauss@40107: let ?ilub = "img_lub f g Lub" krauss@40107: krauss@40107: interpret partial_function_definitions ord Lub by fact krauss@40107: show ?thesis krauss@40107: proof krauss@40107: fix A x assume "chain ?iord A" "x \ A" krauss@40107: then have "chain ord (f ` A)" "f x \ f ` A" krauss@40107: by (auto simp: img_ord_def intro: chainI dest: chainD) krauss@40107: thus "?iord x (?ilub A)" krauss@40107: unfolding inv img_lub_def img_ord_def by (rule lub_upper) krauss@40107: next krauss@40107: fix A x assume "chain ?iord A" krauss@40107: and 1: "\z. z \ A \ ?iord z x" krauss@40107: then have "chain ord (f ` A)" krauss@40107: by (auto simp: img_ord_def intro: chainI dest: chainD) krauss@40107: thus "?iord (?ilub A) x" krauss@40107: unfolding inv img_lub_def img_ord_def krauss@40107: by (rule lub_least) (auto dest: 1[unfolded img_ord_def]) krauss@40107: qed (auto simp: img_ord_def intro: leq_refl dest: leq_trans leq_antisym inj) krauss@40107: qed krauss@40107: krauss@40107: context partial_function_definitions krauss@40107: begin krauss@40107: krauss@40107: abbreviation "le_fun \ fun_ord leq" krauss@40107: abbreviation "lub_fun \ fun_lub lub" krauss@40107: abbreviation "fixp_fun == ccpo.fixp le_fun lub_fun" krauss@40107: abbreviation "mono_body \ monotone le_fun leq" krauss@40107: krauss@40107: text {* Interpret manually, to avoid flooding everything with facts about krauss@40107: orders *} krauss@40107: krauss@40107: lemma ccpo: "class.ccpo le_fun (mk_less le_fun) lub_fun" krauss@40107: apply (rule ccpo) krauss@40107: apply (rule partial_function_lift) krauss@40107: apply (rule partial_function_definitions_axioms) krauss@40107: done krauss@40107: krauss@40107: text {* The crucial fixed-point theorem *} krauss@40107: krauss@40107: lemma mono_body_fixp: krauss@40107: "(\x. mono_body (\f. F f x)) \ fixp_fun F = F (fixp_fun F)" krauss@40107: by (rule ccpo.fixp_unfold[OF ccpo]) (auto simp: monotone_def fun_ord_def) krauss@40107: krauss@40107: text {* Version with curry/uncurry combinators, to be used by package *} krauss@40107: krauss@40107: lemma fixp_rule_uc: krauss@40107: fixes F :: "'c \ 'c" and krauss@40107: U :: "'c \ 'b \ 'a" and krauss@40107: C :: "('b \ 'a) \ 'c" krauss@40107: assumes mono: "\x. mono_body (\f. U (F (C f)) x)" krauss@40107: assumes eq: "f \ C (fixp_fun (\f. U (F (C f))))" krauss@40107: assumes inverse: "\f. C (U f) = f" krauss@40107: shows "f = F f" krauss@40107: proof - krauss@40107: have "f = C (fixp_fun (\f. U (F (C f))))" by (simp add: eq) krauss@40107: also have "... = C (U (F (C (fixp_fun (\f. U (F (C f)))))))" krauss@40107: by (subst mono_body_fixp[of "%f. U (F (C f))", OF mono]) (rule refl) krauss@40107: also have "... = F (C (fixp_fun (\f. U (F (C f)))))" by (rule inverse) krauss@40107: also have "... = F f" by (simp add: eq) krauss@40107: finally show "f = F f" . krauss@40107: qed krauss@40107: krauss@40107: text {* Rules for @{term mono_body}: *} krauss@40107: krauss@40107: lemma const_mono[partial_function_mono]: "monotone ord leq (\f. c)" krauss@40107: by (rule monotoneI) (rule leq_refl) krauss@40107: krauss@40107: end krauss@40107: krauss@40107: krauss@40107: subsection {* Flat interpretation: tailrec and option *} krauss@40107: krauss@40107: definition krauss@40107: "flat_ord b x y \ x = b \ x = y" krauss@40107: krauss@40107: definition krauss@40107: "flat_lub b A = (if A \ {b} then b else (THE x. x \ A - {b}))" krauss@40107: krauss@40107: lemma flat_interpretation: krauss@40107: "partial_function_definitions (flat_ord b) (flat_lub b)" krauss@40107: proof krauss@40107: fix A x assume 1: "chain (flat_ord b) A" "x \ A" krauss@40107: show "flat_ord b x (flat_lub b A)" krauss@40107: proof cases krauss@40107: assume "x = b" krauss@40107: thus ?thesis by (simp add: flat_ord_def) krauss@40107: next krauss@40107: assume "x \ b" krauss@40107: with 1 have "A - {b} = {x}" krauss@40107: by (auto elim: chainE simp: flat_ord_def) krauss@40107: then have "flat_lub b A = x" krauss@40107: by (auto simp: flat_lub_def) krauss@40107: thus ?thesis by (auto simp: flat_ord_def) krauss@40107: qed krauss@40107: next krauss@40107: fix A z assume A: "chain (flat_ord b) A" krauss@40107: and z: "\x. x \ A \ flat_ord b x z" krauss@40107: show "flat_ord b (flat_lub b A) z" krauss@40107: proof cases krauss@40107: assume "A \ {b}" krauss@40107: thus ?thesis krauss@40107: by (auto simp: flat_lub_def flat_ord_def) krauss@40107: next krauss@40107: assume nb: "\ A \ {b}" krauss@40107: then obtain y where y: "y \ A" "y \ b" by auto krauss@40107: with A have "A - {b} = {y}" krauss@40107: by (auto elim: chainE simp: flat_ord_def) krauss@40107: with nb have "flat_lub b A = y" krauss@40107: by (auto simp: flat_lub_def) krauss@40107: with z y show ?thesis by auto krauss@40107: qed krauss@40107: qed (auto simp: flat_ord_def) krauss@40107: krauss@40107: interpretation tailrec!: krauss@40107: partial_function_definitions "flat_ord undefined" "flat_lub undefined" krauss@40107: by (rule flat_interpretation) krauss@40107: krauss@40107: interpretation option!: krauss@40107: partial_function_definitions "flat_ord None" "flat_lub None" krauss@40107: by (rule flat_interpretation) krauss@40107: krauss@42949: declaration {* Partial_Function.init "tailrec" @{term tailrec.fixp_fun} krauss@43080: @{term tailrec.mono_body} @{thm tailrec.fixp_rule_uc} NONE *} krauss@42949: krauss@42949: declaration {* Partial_Function.init "option" @{term option.fixp_fun} krauss@43080: @{term option.mono_body} @{thm option.fixp_rule_uc} NONE *} krauss@42949: krauss@42949: krauss@40107: abbreviation "option_ord \ flat_ord None" krauss@40107: abbreviation "mono_option \ monotone (fun_ord option_ord) option_ord" krauss@40107: krauss@40107: lemma bind_mono[partial_function_mono]: krauss@40107: assumes mf: "mono_option B" and mg: "\y. mono_option (\f. C y f)" krauss@40107: shows "mono_option (\f. Option.bind (B f) (\y. C y f))" krauss@40107: proof (rule monotoneI) krauss@40107: fix f g :: "'a \ 'b option" assume fg: "fun_ord option_ord f g" krauss@40107: with mf krauss@40107: have "option_ord (B f) (B g)" by (rule monotoneD[of _ _ _ f g]) krauss@40107: then have "option_ord (Option.bind (B f) (\y. C y f)) (Option.bind (B g) (\y. C y f))" krauss@40107: unfolding flat_ord_def by auto krauss@40107: also from mg krauss@40107: have "\y'. option_ord (C y' f) (C y' g)" krauss@40107: by (rule monotoneD) (rule fg) krauss@40107: then have "option_ord (Option.bind (B g) (\y'. C y' f)) (Option.bind (B g) (\y'. C y' g))" krauss@40107: unfolding flat_ord_def by (cases "B g") auto krauss@40107: finally (option.leq_trans) krauss@40107: show "option_ord (Option.bind (B f) (\y. C y f)) (Option.bind (B g) (\y'. C y' g))" . krauss@40107: qed krauss@40107: krauss@40252: hide_const (open) chain krauss@40107: krauss@40107: end krauss@40107: