Theory Fix

(*  Title:      HOL/HOLCF/Fix.thy
    Author:     Franz Regensburger
    Author:     Brian Huffman
*)

section ‹Fixed point operator and admissibility›

theory Fix
  imports Cfun
begin

default_sort pcpo


subsection ‹Iteration›

primrec iterate :: "nat  ('a::cpo  'a)  ('a  'a)"
  where
    "iterate 0 = (Λ F x. x)"
  | "iterate (Suc n) = (Λ F x. F(iterate nFx))"

text ‹Derive inductive properties of iterate from primitive recursion›

lemma iterate_0 [simp]: "iterate 0Fx = x"
  by simp

lemma iterate_Suc [simp]: "iterate (Suc n)Fx = F(iterate nFx)"
  by simp

declare iterate.simps [simp del]

lemma iterate_Suc2: "iterate (Suc n)Fx = iterate nF(Fx)"
  by (induct n) simp_all

lemma iterate_iterate: "iterate mF(iterate nFx) = iterate (m + n)Fx"
  by (induct m) simp_all

text ‹The sequence of function iterations is a chain.›

lemma chain_iterate [simp]: "chain (λi. iterate iF)"
  by (rule chainI, unfold iterate_Suc2, rule monofun_cfun_arg, rule minimal)


subsection ‹Least fixed point operator›

definition "fix" :: "('a  'a)  'a"
  where "fix = (Λ F. i. iterate iF)"

text ‹Binder syntax for termfix

abbreviation fix_syn :: "('a  'a)  'a"  (binder μ 10)
  where "fix_syn (λx. f x)  fix(Λ x. f x)"

notation (ASCII)
  fix_syn  (binder FIX 10)

text ‹Properties of termfix

text ‹direct connection between termfix and iteration›

lemma fix_def2: "fixF = (i. iterate iF)"
  by (simp add: fix_def)

lemma iterate_below_fix: "iterate nf  fixf"
  unfolding fix_def2
  using chain_iterate by (rule is_ub_thelub)

text ‹
  Kleene's fixed point theorems for continuous functions in pointed
  omega cpo's
›

lemma fix_eq: "fixF = F(fixF)"
  apply (simp add: fix_def2)
  apply (subst lub_range_shift [of _ 1, symmetric])
   apply (rule chain_iterate)
  apply (subst contlub_cfun_arg)
   apply (rule chain_iterate)
  apply simp
  done

lemma fix_least_below: "Fx  x  fixF  x"
  apply (simp add: fix_def2)
  apply (rule lub_below)
   apply (rule chain_iterate)
  apply (induct_tac i)
   apply simp
  apply simp
  apply (erule rev_below_trans)
  apply (erule monofun_cfun_arg)
  done

lemma fix_least: "Fx = x  fixF  x"
  by (rule fix_least_below) simp

lemma fix_eqI:
  assumes fixed: "Fx = x"
    and least: "z. Fz = z  x  z"
  shows "fixF = x"
  apply (rule below_antisym)
   apply (rule fix_least [OF fixed])
  apply (rule least [OF fix_eq [symmetric]])
  done

lemma fix_eq2: "f  fixF  f = Ff"
  by (simp add: fix_eq [symmetric])

lemma fix_eq3: "f  fixF  fx = Ffx"
  by (erule fix_eq2 [THEN cfun_fun_cong])

lemma fix_eq4: "f = fixF  f = Ff"
  by (erule ssubst) (rule fix_eq)

lemma fix_eq5: "f = fixF  fx = Ffx"
  by (erule fix_eq4 [THEN cfun_fun_cong])

text ‹strictness of termfix

lemma fix_bottom_iff: "fixF =   F = "
  apply (rule iffI)
   apply (erule subst)
   apply (rule fix_eq [symmetric])
  apply (erule fix_least [THEN bottomI])
  done

lemma fix_strict: "F =   fixF = "
  by (simp add: fix_bottom_iff)

lemma fix_defined: "F    fixF  "
  by (simp add: fix_bottom_iff)

text termfix applied to identity and constant functions›

lemma fix_id: "(μ x. x) = "
  by (simp add: fix_strict)

lemma fix_const: "(μ x. c) = c"
  by (subst fix_eq) simp


subsection ‹Fixed point induction›

lemma fix_ind: "adm P  P   (x. P x  P (Fx))  P (fixF)"
  unfolding fix_def2
  apply (erule admD)
   apply (rule chain_iterate)
  apply (rule nat_induct, simp_all)
  done

lemma cont_fix_ind: "cont F  adm P  P   (x. P x  P (F x))  P (fix(Abs_cfun F))"
  by (simp add: fix_ind)

lemma def_fix_ind: "f  fixF; adm P; P ; x. P x  P (Fx)  P f"
  by (simp add: fix_ind)

lemma fix_ind2:
  assumes adm: "adm P"
  assumes 0: "P " and 1: "P (F)"
  assumes step: "x. P x; P (Fx)  P (F(Fx))"
  shows "P (fixF)"
  unfolding fix_def2
  apply (rule admD [OF adm chain_iterate])
  apply (rule nat_less_induct)
  apply (case_tac n)
   apply (simp add: 0)
  apply (case_tac nat)
   apply (simp add: 1)
  apply (frule_tac x=nat in spec)
  apply (simp add: step)
  done

lemma parallel_fix_ind:
  assumes adm: "adm (λx. P (fst x) (snd x))"
  assumes base: "P  "
  assumes step: "x y. P x y  P (Fx) (Gy)"
  shows "P (fixF) (fixG)"
proof -
  from adm have adm': "adm (case_prod P)"
    unfolding split_def .
  have "P (iterate iF) (iterate iG)" for i
    by (induct i) (simp add: base, simp add: step)
  then have "i. case_prod P (iterate iF, iterate iG)"
    by simp
  then have "case_prod P (i. (iterate iF, iterate iG))"
    by - (rule admD [OF adm'], simp, assumption)
  then have "case_prod P (i. iterate iF, i. iterate iG)"
    by (simp add: lub_Pair)
  then have "P (i. iterate iF) (i. iterate iG)"
    by simp
  then show "P (fixF) (fixG)"
    by (simp add: fix_def2)
qed

lemma cont_parallel_fix_ind:
  assumes "cont F" and "cont G"
  assumes "adm (λx. P (fst x) (snd x))"
  assumes "P  "
  assumes "x y. P x y  P (F x) (G y)"
  shows "P (fix(Abs_cfun F)) (fix(Abs_cfun G))"
  by (rule parallel_fix_ind) (simp_all add: assms)


subsection ‹Fixed-points on product types›

text ‹
  Bekic's Theorem: Simultaneous fixed points over pairs
  can be written in terms of separate fixed points.
›

lemma fix_cprod:
  "fix(F::'a × 'b  'a × 'b) =
   (μ x. fst (F(x, μ y. snd (F(x, y)))),
    μ y. snd (F(μ x. fst (F(x, μ y. snd (F(x, y)))), y)))"
  (is "fixF = (?x, ?y)")
proof (rule fix_eqI)
  have *: "fst (F(?x, ?y)) = ?x"
    by (rule trans [symmetric, OF fix_eq], simp)
  have "snd (F(?x, ?y)) = ?y"
    by (rule trans [symmetric, OF fix_eq], simp)
  with * show "F(?x, ?y) = (?x, ?y)"
    by (simp add: prod_eq_iff)
next
  fix z
  assume F_z: "Fz = z"
  obtain x y where z: "z = (x, y)" by (rule prod.exhaust)
  from F_z z have F_x: "fst (F(x, y)) = x" by simp
  from F_z z have F_y: "snd (F(x, y)) = y" by simp
  let ?y1 = "μ y. snd (F(x, y))"
  have "?y1  y"
    by (rule fix_least) (simp add: F_y)
  then have "fst (F(x, ?y1))  fst (F(x, y))"
    by (simp add: fst_monofun monofun_cfun)
  with F_x have "fst (F(x, ?y1))  x"
    by simp
  then have *: "?x  x"
    by (simp add: fix_least_below)
  then have "snd (F(?x, y))  snd (F(x, y))"
    by (simp add: snd_monofun monofun_cfun)
  with F_y have "snd (F(?x, y))  y"
    by simp
  then have "?y  y"
    by (simp add: fix_least_below)
  with z * show "(?x, ?y)  z"
    by simp
qed

end