src/HOLCF/Fix.thy
author wenzelm
Tue, 17 May 2005 18:10:36 +0200
changeset 15983 a53abeedc879
parent 15857 83cb9dae3817
child 16005 42f3f299ee68
permissions -rw-r--r--
renamed show_var_qmarks to show_question_marks;

(*  Title:      HOLCF/Fix.thy
    ID:         $Id$
    Author:     Franz Regensburger
    License:    GPL (GNU GENERAL PUBLIC LICENSE)

definitions for fixed point operator and admissibility
*)

header {* Fixed point operator and admissibility *}

theory Fix
imports Cfun Cprod
begin

consts

iterate	:: "nat=>('a->'a)=>'a=>'a"
Ifix	:: "('a->'a)=>'a"
"fix"	:: "('a->'a)->'a"
adm		:: "('a::cpo=>bool)=>bool"
admw		:: "('a=>bool)=>bool"

primrec
  iterate_0:   "iterate 0 F x = x"
  iterate_Suc: "iterate (Suc n) F x  = F$(iterate n F x)"

defs

Ifix_def:      "Ifix F == lub(range(%i. iterate i F UU))"
fix_def:       "fix == (LAM f. Ifix f)"

adm_def:       "adm P == !Y. chain(Y) --> 
                        (!i. P(Y i)) --> P(lub(range Y))"

admw_def:      "admw P == !F. (!n. P (iterate n F UU)) -->
                            P (lub(range (%i. iterate i F UU)))" 

text {* Binder syntax for @{term fix} *}

syntax
  "@FIX" :: "('a => 'a) => 'a"  (binder "FIX " 10)
  "@FIXP" :: "[patterns, 'a] => 'a"  ("(3FIX <_>./ _)" [0, 10] 10)

syntax (xsymbols)
  "FIX " :: "[idt, 'a] => 'a"  ("(3\<mu>_./ _)" [0, 10] 10)
  "@FIXP" :: "[patterns, 'a] => 'a"  ("(3\<mu>()<_>./ _)" [0, 10] 10)

translations
  "FIX x. LAM y. t" == "fix\<cdot>(LAM x y. t)"
  "FIX x. t" == "fix\<cdot>(LAM x. t)"
  "FIX <xs>. t" == "fix\<cdot>(LAM <xs>. t)"

text {* derive inductive properties of iterate from primitive recursion *}

lemma iterate_Suc2: "iterate (Suc n) F x = iterate n F (F$x)"
apply (induct_tac "n")
apply auto
done

text {*
  The sequence of function iterations is a chain.
  This property is essential since monotonicity of iterate makes no sense.
*}

lemma chain_iterate2: "x << F$x ==> chain (%i. iterate i F x)"
apply (rule chainI)
apply (induct_tac "i")
apply auto
apply (erule monofun_cfun_arg)
done

lemma chain_iterate: "chain (%i. iterate i F UU)"
apply (rule chain_iterate2)
apply (rule minimal)
done

text {*
  Kleene's fixed point theorems for continuous functions in pointed
  omega cpo's
*}

lemma Ifix_eq: "Ifix F =F$(Ifix F)"
apply (unfold Ifix_def)
apply (subst contlub_cfun_arg)
apply (rule chain_iterate)
apply (rule antisym_less)
apply (rule lub_mono)
apply (rule chain_iterate)
apply (rule ch2ch_Rep_CFunR)
apply (rule chain_iterate)
apply (rule allI)
apply (rule iterate_Suc [THEN subst])
apply (rule chain_iterate [THEN chainE])
apply (rule is_lub_thelub)
apply (rule ch2ch_Rep_CFunR)
apply (rule chain_iterate)
apply (rule ub_rangeI)
apply (rule iterate_Suc [THEN subst])
apply (rule is_ub_thelub)
apply (rule chain_iterate)
done

lemma Ifix_least: "F$x=x ==> Ifix(F) << x"
apply (unfold Ifix_def)
apply (rule is_lub_thelub)
apply (rule chain_iterate)
apply (rule ub_rangeI)
apply (induct_tac "i")
apply (simp (no_asm_simp))
apply (simp (no_asm_simp))
apply (rule_tac t = "x" in subst)
apply assumption
apply (erule monofun_cfun_arg)
done

text {* monotonicity and continuity of @{term iterate} *}

lemma monofun_iterate: "monofun(iterate(i))"
apply (rule monofunI [rule_format])
apply (induct_tac "i")
apply (simp)
apply (simp add: less_fun monofun_cfun)
done

text {*
  The following lemma uses @{thm [source] contlub_cfun} which itself is based
  on a diagonalisation lemma for continuous functions with two arguments. In
  this special case it is the application function @{term Rep_CFun}
*}

lemma contlub_iterate: "contlub(iterate(i))"
apply (rule contlubI [rule_format])
apply (induct_tac "i")
apply (simp)
apply (rule lub_const [THEN thelubI, symmetric])
apply (simp del: range_composition)
apply (rule ext)
apply (simplesubst thelub_fun)
apply (rule chainI)
apply (rule less_fun [THEN iffD2])
apply (rule allI)
apply (rule chainE)
apply (rule monofun_Rep_CFun1 [THEN ch2ch_MF2LR])
apply (rule allI)
apply (rule monofun_Rep_CFun2)
apply assumption
apply (rule ch2ch_fun)
apply (rule monofun_iterate [THEN ch2ch_monofun])
apply assumption
apply (subst thelub_fun)
apply (rule monofun_iterate [THEN ch2ch_monofun])
apply assumption
apply (rule contlub_cfun)
apply assumption
apply (erule monofun_iterate [THEN ch2ch_monofun, THEN ch2ch_fun])
done

lemma cont_iterate: "cont(iterate(i))"
apply (rule monocontlub2cont)
apply (rule monofun_iterate)
apply (rule contlub_iterate)
done

text {* a lemma about continuity of @{term iterate} in its third argument *}

lemma monofun_iterate2: "monofun(iterate n F)"
apply (rule monofunI [rule_format])
apply (induct_tac "n")
apply (simp)
apply (simp)
apply (erule monofun_cfun_arg)
done

lemma contlub_iterate2: "contlub(iterate n F)"
apply (rule contlubI [rule_format])
apply (induct_tac "n")
apply (simp)
apply (simp)
apply (rule_tac t = "iterate n F (lub (range (%u. Y u))) " and s = "lub (range (%i. iterate n F (Y i))) " in ssubst)
apply assumption
apply (rule contlub_cfun_arg)
apply (erule monofun_iterate2 [THEN ch2ch_monofun])
done

lemma cont_iterate2: "cont (iterate n F)"
apply (rule monocontlub2cont)
apply (rule monofun_iterate2)
apply (rule contlub_iterate2)
done

text {* monotonicity and continuity of @{term Ifix} *}

lemma monofun_Ifix: "monofun(Ifix)"
apply (rule monofunI [rule_format])
apply (unfold Ifix_def)
apply (rule lub_mono)
apply (rule chain_iterate)
apply (rule chain_iterate)
apply (rule allI)
apply (rule less_fun [THEN iffD1, THEN spec], erule monofun_iterate [THEN monofunE, THEN spec, THEN spec, THEN mp])
done

text {*
  since iterate is not monotone in its first argument, special lemmas must
  be derived for lubs in this argument
*}

lemma chain_iterate_lub: 
"chain(Y) ==> chain(%i. lub(range(%ia. iterate ia (Y i) UU)))"
apply (rule chainI)
apply (rule lub_mono)
apply (rule chain_iterate)
apply (rule chain_iterate)
apply (rule allI)
apply (erule monofun_iterate [THEN ch2ch_monofun, THEN ch2ch_fun, THEN chainE])
done

text {*
  this exchange lemma is analog to the one for monotone functions
  observe that monotonicity is not really needed. The propagation of
  chains is the essential argument which is usually derived from monot.
*}

lemma contlub_Ifix_lemma1: "chain(Y) ==>iterate n (lub(range Y)) y = lub(range(%i. iterate n (Y i) y))"
apply (rule thelub_fun [THEN subst])
apply (erule monofun_iterate [THEN ch2ch_monofun])
apply (simp add: contlub_iterate [THEN contlubE])
done

lemma ex_lub_iterate: "chain(Y) ==> 
          lub(range(%i. lub(range(%ia. iterate i (Y ia) UU)))) = 
          lub(range(%i. lub(range(%ia. iterate ia (Y i) UU))))"
apply (rule antisym_less)
apply (rule is_lub_thelub)
apply (rule contlub_Ifix_lemma1 [THEN ext, THEN subst])
apply assumption
apply (rule chain_iterate)
apply (rule ub_rangeI)
apply (rule lub_mono)
apply (erule monofun_iterate [THEN ch2ch_monofun, THEN ch2ch_fun])
apply (erule chain_iterate_lub)
apply (rule allI)
apply (rule is_ub_thelub)
apply (rule chain_iterate)
apply (rule is_lub_thelub)
apply (erule chain_iterate_lub)
apply (rule ub_rangeI)
apply (rule lub_mono)
apply (rule chain_iterate)
apply (rule contlub_Ifix_lemma1 [THEN ext, THEN subst])
apply assumption
apply (rule chain_iterate)
apply (rule allI)
apply (rule is_ub_thelub)
apply (erule monofun_iterate [THEN ch2ch_monofun, THEN ch2ch_fun])
done

lemma contlub_Ifix: "contlub(Ifix)"
apply (rule contlubI [rule_format])
apply (unfold Ifix_def)
apply (subst contlub_Ifix_lemma1 [THEN ext])
apply assumption
apply (erule ex_lub_iterate)
done

lemma cont_Ifix: "cont(Ifix)"
apply (rule monocontlub2cont)
apply (rule monofun_Ifix)
apply (rule contlub_Ifix)
done

text {* propagate properties of @{term Ifix} to its continuous counterpart *}

lemma fix_eq: "fix$F = F$(fix$F)"
apply (unfold fix_def)
apply (simp add: cont_Ifix)
apply (rule Ifix_eq)
done

lemma fix_least: "F$x = x ==> fix$F << x"
apply (unfold fix_def)
apply (simp add: cont_Ifix)
apply (erule Ifix_least)
done

lemma fix_eqI: 
"[| F$x = x; !z. F$z = z --> x << z |] ==> x = fix$F"
apply (rule antisym_less)
apply (erule allE)
apply (erule mp)
apply (rule fix_eq [symmetric])
apply (erule fix_least)
done

lemma fix_eq2: "f == fix$F ==> f = F$f"
by (simp add: fix_eq [symmetric])

lemma fix_eq3: "f == fix$F ==> f$x = F$f$x"
by (erule fix_eq2 [THEN cfun_fun_cong])

(* fun fix_tac3 thm i  = ((rtac trans i) THEN (rtac (thm RS fix_eq3) i)) *)

lemma fix_eq4: "f = fix$F ==> f = F$f"
apply (erule ssubst)
apply (rule fix_eq)
done

lemma fix_eq5: "f = fix$F ==> f$x = F$f$x"
apply (rule trans)
apply (erule fix_eq4 [THEN cfun_fun_cong])
apply (rule refl)
done

(* fun fix_tac5 thm i  = ((rtac trans i) THEN (rtac (thm RS fix_eq5) i)) *)

(* proves the unfolding theorem for function equations f = fix$... *)
(*
fun fix_prover thy fixeq s = prove_goal thy s (fn prems => [
        (rtac trans 1),
        (rtac (fixeq RS fix_eq4) 1),
        (rtac trans 1),
        (rtac beta_cfun 1),
        (Simp_tac 1)
        ])
*)
(* proves the unfolding theorem for function definitions f == fix$... *)
(*
fun fix_prover2 thy fixdef s = prove_goal thy s (fn prems => [
        (rtac trans 1),
        (rtac (fix_eq2) 1),
        (rtac fixdef 1),
        (rtac beta_cfun 1),
        (Simp_tac 1)
        ])
*)
(* proves an application case for a function from its unfolding thm *)
(*
fun case_prover thy unfold s = prove_goal thy s (fn prems => [
	(cut_facts_tac prems 1),
	(rtac trans 1),
	(stac unfold 1),
	Auto_tac
	])
*)
text {* better access to definitions *}

lemma Ifix_def2: "Ifix=(%x. lub(range(%i. iterate i x UU)))"
apply (rule ext)
apply (unfold Ifix_def)
apply (rule refl)
done

text {* direct connection between @{term fix} and iteration without @{term Ifix} *}

lemma fix_def2: "fix$F = lub(range(%i. iterate i F UU))"
apply (unfold fix_def)
apply (fold Ifix_def)
apply (simp (no_asm_simp) add: cont_Ifix)
done

text {* Lemmas about admissibility and fixed point induction *}

text {* access to definitions *}

lemma admI:
   "(!!Y. [| chain Y; !i. P (Y i) |] ==> P (lub (range Y))) ==> adm P"
apply (unfold adm_def)
apply blast
done

lemma triv_admI: "!x. P x ==> adm P"
apply (rule admI)
apply (erule spec)
done

lemma admD: "[| adm(P); chain(Y); !i. P(Y(i)) |] ==> P(lub(range(Y)))"
apply (unfold adm_def)
apply blast
done

lemma admw_def2: "admw(P) = (!F.(!n. P(iterate n F UU)) --> 
                         P (lub(range(%i. iterate i F UU))))"
apply (unfold admw_def)
apply (rule refl)
done

text {* an admissible formula is also weak admissible *}

lemma adm_impl_admw: "adm(P)==>admw(P)"
apply (unfold admw_def)
apply (intro strip)
apply (erule admD)
apply (rule chain_iterate)
apply assumption
done

text {* fixed point induction *}

lemma fix_ind:
     "[| adm(P); P(UU); !!x. P(x) ==> P(F$x)|] ==> P(fix$F)"
apply (subst fix_def2)
apply (erule admD)
apply (rule chain_iterate)
apply (rule allI)
apply (induct_tac "i")
apply simp
apply simp
done

lemma def_fix_ind: "[| f == fix$F; adm(P);  
        P(UU); !!x. P(x) ==> P(F$x)|] ==> P f"
apply simp
apply (erule fix_ind)
apply assumption
apply fast
done

text {* computational induction for weak admissible formulae *}

lemma wfix_ind: "[| admw(P); !n. P(iterate n F UU)|] ==> P(fix$F)"
apply (subst fix_def2)
apply (rule admw_def2 [THEN iffD1, THEN spec, THEN mp])
apply assumption
apply (rule allI)
apply (erule spec)
done

lemma def_wfix_ind: "[| f == fix$F; admw(P);  
        !n. P(iterate n F UU) |] ==> P f"
apply simp
apply (erule wfix_ind)
apply assumption
done

text {* for chain-finite (easy) types every formula is admissible *}

lemma adm_max_in_chain: 
"!Y. chain(Y::nat=>'a) --> (? n. max_in_chain n Y) ==> adm(P::'a=>bool)"
apply (unfold adm_def)
apply (intro strip)
apply (rule exE)
apply (rule mp)
apply (erule spec)
apply assumption
apply (subst lub_finch1 [THEN thelubI])
apply assumption
apply assumption
apply (erule spec)
done

lemmas adm_chfin = chfin [THEN adm_max_in_chain, standard]

text {* some lemmata for functions with flat/chfin domain/range types *}

lemma adm_chfindom: "adm (%(u::'a::cpo->'b::chfin). P(u$s))"
apply (unfold adm_def)
apply (intro strip)
apply (drule chfin_Rep_CFunR)
apply (erule_tac x = "s" in allE)
apply clarsimp
done

(* adm_flat not needed any more, since it is a special case of adm_chfindom *)

text {* improved admissibility introduction *}

lemma admI2:
 "(!!Y. [| chain Y; !i. P (Y i); !i. ? j. i < j & Y i ~= Y j & Y i << Y j |] 
  ==> P(lub (range Y))) ==> adm P"
apply (unfold adm_def)
apply (intro strip)
apply (erule increasing_chain_adm_lemma)
apply assumption
apply fast
done

text {* admissibility of special formulae and propagation *}

lemma adm_less [simp]: "[|cont u;cont v|]==> adm(%x. u x << v x)"
apply (unfold adm_def)
apply (intro strip)
apply (frule_tac f = "u" in cont2mono [THEN ch2ch_monofun])
apply assumption
apply (frule_tac f = "v" in cont2mono [THEN ch2ch_monofun])
apply assumption
apply (erule cont2contlub [THEN contlubE, THEN spec, THEN mp, THEN ssubst])
apply assumption
apply (erule cont2contlub [THEN contlubE, THEN spec, THEN mp, THEN ssubst])
apply assumption
apply (blast intro: lub_mono)
done

lemma adm_conj [simp]: "[| adm P; adm Q |] ==> adm(%x. P x & Q x)"
by (fast elim: admD intro: admI)

lemma adm_not_free [simp]: "adm(%x. t)"
apply (unfold adm_def)
apply fast
done

lemma adm_not_less: "cont t ==> adm(%x.~ (t x) << u)"
apply (unfold adm_def)
apply (intro strip)
apply (rule contrapos_nn)
apply (erule spec)
apply (rule trans_less)
prefer 2 apply (assumption)
apply (erule cont2mono [THEN monofun_fun_arg])
apply (rule is_ub_thelub)
apply assumption
done

lemma adm_all: "!y. adm(P y) ==> adm(%x.!y. P y x)"
by (fast intro: admI elim: admD)

lemmas adm_all2 = allI [THEN adm_all, standard]

lemma adm_subst: "[|cont t; adm P|] ==> adm(%x. P (t x))"
apply (rule admI)
apply (simplesubst cont2contlub [THEN contlubE, THEN spec, THEN mp])
apply assumption
apply assumption
apply (erule admD)
apply (erule cont2mono [THEN ch2ch_monofun])
apply assumption
apply assumption
done

lemma adm_UU_not_less: "adm(%x.~ UU << t(x))"
by simp

lemma adm_not_UU: "cont(t)==> adm(%x.~ (t x) = UU)"
apply (unfold adm_def)
apply (intro strip)
apply (rule contrapos_nn)
apply (erule spec)
apply (rule chain_UU_I [THEN spec])
apply (erule cont2mono [THEN ch2ch_monofun])
apply assumption
apply (erule cont2contlub [THEN contlubE, THEN spec, THEN mp, THEN subst])
apply assumption
apply assumption
done

lemma adm_eq: "[|cont u ; cont v|]==> adm(%x. u x = v x)"
by (simp add: po_eq_conv)

text {* admissibility for disjunction is hard to prove. It takes 10 Lemmas *}

lemma adm_disj_lemma1: "!n. P(Y n)|Q(Y n) ==> (? i.!j. R i j --> Q(Y(j))) | (!i.? j. R i j & P(Y(j)))"
by fast

lemma adm_disj_lemma2: "[| adm(Q); ? X. chain(X) & (!n. Q(X(n))) & 
      lub(range(Y))=lub(range(X))|] ==> Q(lub(range(Y)))"
by (force elim: admD)

lemma adm_disj_lemma3: "chain Y ==> chain (%m. if m < Suc i then Y (Suc i) else Y m)"
apply (unfold chain_def)
apply (simp)
apply safe
apply (subgoal_tac "ia = i")
apply (simp_all)
done

lemma adm_disj_lemma4: "!j. i < j --> Q(Y(j))  ==> !n. Q( if n < Suc i then Y(Suc i) else Y n)"
by (simp)

lemma adm_disj_lemma5: 
  "!!Y::nat=>'a::cpo. [| chain(Y); ! j. i < j --> Q(Y(j)) |] ==> 
          lub(range(Y)) = lub(range(%m. if m< Suc(i) then Y(Suc(i)) else Y m))"
apply (safe intro!: lub_equal2 adm_disj_lemma3)
prefer 2 apply (assumption)
apply (rule_tac x = "i" in exI)
apply (simp)
done

lemma adm_disj_lemma6: 
  "[| chain(Y::nat=>'a::cpo); ? i. ! j. i < j --> Q(Y(j)) |] ==> 
            ? X. chain(X) & (! n. Q(X(n))) & lub(range(Y)) = lub(range(X))"
apply (erule exE)
apply (rule_tac x = "%m. if m<Suc (i) then Y (Suc (i)) else Y m" in exI)
apply (rule conjI)
apply (rule adm_disj_lemma3)
apply assumption
apply (rule conjI)
apply (rule adm_disj_lemma4)
apply assumption
apply (rule adm_disj_lemma5)
apply assumption
apply assumption
done

lemma adm_disj_lemma7: 
  "[| chain(Y::nat=>'a::cpo); ! i. ? j. i < j & P(Y(j))  |] ==> 
            chain(%m. Y(Least(%j. m<j & P(Y(j)))))"
apply (rule chainI)
apply (rule chain_mono3)
apply assumption
apply (rule Least_le)
apply (rule conjI)
apply (rule Suc_lessD)
apply (erule allE)
apply (erule exE)
apply (rule LeastI [THEN conjunct1])
apply assumption
apply (erule allE)
apply (erule exE)
apply (rule LeastI [THEN conjunct2])
apply assumption
done

lemma adm_disj_lemma8: 
  "[| ! i. ? j. i < j & P(Y(j)) |] ==> ! m. P(Y(LEAST j::nat. m<j & P(Y(j))))"
apply (intro strip)
apply (erule allE)
apply (erule exE)
apply (erule LeastI [THEN conjunct2])
done

lemma adm_disj_lemma9: 
  "[| chain(Y::nat=>'a::cpo); ! i. ? j. i < j & P(Y(j)) |] ==> 
            lub(range(Y)) = lub(range(%m. Y(Least(%j. m<j & P(Y(j))))))"
apply (rule antisym_less)
apply (rule lub_mono)
apply assumption
apply (rule adm_disj_lemma7)
apply assumption
apply assumption
apply (intro strip)
apply (rule chain_mono)
apply assumption
apply (erule allE)
apply (erule exE)
apply (rule LeastI [THEN conjunct1])
apply assumption
apply (rule lub_mono3)
apply (rule adm_disj_lemma7)
apply assumption
apply assumption
apply assumption
apply (intro strip)
apply (rule exI)
apply (rule chain_mono)
apply assumption
apply (rule lessI)
done

lemma adm_disj_lemma10: "[| chain(Y::nat=>'a::cpo); ! i. ? j. i < j & P(Y(j)) |] ==> 
            ? X. chain(X) & (! n. P(X(n))) & lub(range(Y)) = lub(range(X))"
apply (rule_tac x = "%m. Y (Least (%j. m<j & P (Y (j))))" in exI)
apply (rule conjI)
apply (rule adm_disj_lemma7)
apply assumption
apply assumption
apply (rule conjI)
apply (rule adm_disj_lemma8)
apply assumption
apply (rule adm_disj_lemma9)
apply assumption
apply assumption
done

lemma adm_disj_lemma12: "[| adm(P); chain(Y);? i. ! j. i < j --> P(Y(j))|]==>P(lub(range(Y)))"
apply (erule adm_disj_lemma2)
apply (erule adm_disj_lemma6)
apply assumption
done

lemma adm_lemma11: 
"[| adm(P); chain(Y); ! i. ? j. i < j & P(Y(j)) |]==>P(lub(range(Y)))"
apply (erule adm_disj_lemma2)
apply (erule adm_disj_lemma10)
apply assumption
done

lemma adm_disj: "[| adm P; adm Q |] ==> adm(%x. P x | Q x)"
apply (rule admI)
apply (rule adm_disj_lemma1 [THEN disjE])
apply assumption
apply (rule disjI2)
apply (erule adm_disj_lemma12)
apply assumption
apply assumption
apply (rule disjI1)
apply (erule adm_lemma11)
apply assumption
apply assumption
done

lemma adm_imp: "[| adm(%x.~(P x)); adm Q |] ==> adm(%x. P x --> Q x)"
apply (subgoal_tac " (%x. P x --> Q x) = (%x. ~P x | Q x) ")
apply (erule ssubst)
apply (erule adm_disj)
apply assumption
apply (simp)
done

lemma adm_iff: "[| adm (%x. P x --> Q x); adm (%x. Q x --> P x) |]  
            ==> adm (%x. P x = Q x)"
apply (subgoal_tac " (%x. P x = Q x) = (%x. (P x --> Q x) & (Q x --> P x))")
apply (simp)
apply (rule ext)
apply fast
done


lemma adm_not_conj: "[| adm (%x. ~ P x); adm (%x. ~ Q x) |] ==> adm (%x. ~ (P x & Q x))"
apply (subgoal_tac " (%x. ~ (P x & Q x)) = (%x. ~ P x | ~ Q x) ")
apply (rule_tac [2] ext)
prefer 2 apply fast
apply (erule ssubst)
apply (erule adm_disj)
apply assumption
done

lemmas adm_lemmas = adm_not_free adm_imp adm_disj adm_eq adm_not_UU
        adm_UU_not_less adm_all2 adm_not_less adm_not_conj adm_iff

declare adm_lemmas [simp]

end