Theory Partial_Function_Set
theory Partial_Function_Set imports Main begin
subsection ‹Setup for ‹partial_function› for sets›
lemma (in complete_lattice) lattice_partial_function_definition:
  "partial_function_definitions (≤) Sup"
by(unfold_locales)(auto intro: Sup_upper Sup_least)
interpretation set: partial_function_definitions "(⊆)" Union
by(rule lattice_partial_function_definition)
lemma fun_lub_Sup: "fun_lub Sup = (Sup :: _ ⇒ _ :: complete_lattice)"
by(fastforce simp add: fun_lub_def fun_eq_iff Sup_fun_def intro: Sup_eqI SUP_upper SUP_least)
lemma set_admissible: "set.admissible (λf :: 'a ⇒ 'b set. ∀x y. y ∈ f x ⟶ P x y)"
by(rule ccpo.admissibleI)(auto simp add: fun_lub_Sup)
abbreviation "mono_set ≡ monotone (fun_ord (⊆)) (⊆)"
lemma fixp_induct_set_scott:
  fixes F :: "'c ⇒ 'c"
  and U :: "'c ⇒ 'b ⇒ 'a set"
  and C :: "('b ⇒ 'a set) ⇒ 'c"
  and P :: "'b ⇒ 'a ⇒ bool"
  and x and y
  assumes mono: "⋀x. mono_set (λf. U (F (C f)) x)"
  and eq: "f ≡ C (ccpo.fixp (fun_lub Sup) (fun_ord (≤)) (λf. U (F (C f))))"
  and inverse2: "⋀f. U (C f) = f"
  and step: "⋀f x y. ⟦ ⋀x y. y ∈ U f x ⟹ P x y; y ∈ U (F f) x ⟧ ⟹ P x y"
  and enforce_variable_ordering: "x = x"
  and elem: "y ∈ U f x"
  shows "P x y"
using step elem set.fixp_induct_uc[of U F C, OF mono eq inverse2 set_admissible, of P]
by blast
lemma fixp_Sup_le:
  defines "le ≡ ((≤) :: _ :: complete_lattice ⇒ _)"
  shows "ccpo.fixp Sup le = ccpo_class.fixp"
proof -
  have "class.ccpo Sup le (<)" unfolding le_def by unfold_locales
  thus ?thesis
    by(simp add: ccpo.fixp_def fixp_def ccpo.iterates_def iterates_def ccpo.iteratesp_def iteratesp_def fun_eq_iff le_def)
qed
lemma fun_ord_le: "fun_ord (≤) = (≤)"
by(auto simp add: fun_ord_def fun_eq_iff le_fun_def)
lemma fixp_induct_set:
  fixes F :: "'c ⇒ 'c"
  and U :: "'c ⇒ 'b ⇒ 'a set"
  and C :: "('b ⇒ 'a set) ⇒ 'c"
  and P :: "'b ⇒ 'a ⇒ bool"
  and x and y
  assumes mono: "⋀x. mono_set (λf. U (F (C f)) x)"
  and eq: "f ≡ C (ccpo.fixp (fun_lub Sup) (fun_ord (≤)) (λf. U (F (C f))))"
  and inverse2: "⋀f. U (C f) = f"
  and step: "⋀f' x y. ⟦ ⋀x. U f' x = U f' x; y ∈ U (F (C (inf (U f) (λx. {y. P x y})))) x ⟧ ⟹ P x y"
    
  and elem: "y ∈ U f x"
  shows "P x y"
proof -
  from mono
  have mono': "mono (λf. U (F (C f)))"
    by(simp add: fun_ord_le mono_def le_fun_def)
  hence eq': "f ≡ C (lfp (λf. U (F (C f))))"
    using eq unfolding fun_ord_le fun_lub_Sup fixp_Sup_le by(simp add: lfp_eq_fixp)
  let ?f = "C (lfp (λf. U (F (C f))))"
  have step': "⋀x y. ⟦ y ∈ U (F (C (inf (U ?f) (λx. {y. P x y})))) x ⟧ ⟹ P x y"
    unfolding eq'[symmetric] by(rule step[OF refl])
  let ?P = "λx. {y. P x y}"
  from mono' have "lfp (λf. U (F (C f))) ≤ ?P"
    by(rule lfp_induct)(auto intro!: le_funI step' simp add: inverse2)
  with elem show ?thesis
    by(subst (asm) eq')(auto simp add: inverse2 le_fun_def)
qed
declaration ‹Partial_Function.init "set" @{term set.fixp_fun}
  @{term set.mono_body} @{thm set.fixp_rule_uc} @{thm set.fixp_induct_uc}
  (SOME @{thm fixp_induct_set})›
lemma [partial_function_mono]:
  shows insert_mono: "mono_set A ⟹ mono_set (λf. insert x (A f))"
  and UNION_mono: "⟦mono_set B; ⋀y. mono_set (λf. C y f)⟧ ⟹ mono_set (λf. ⋃y∈B f. C y f)"
  and set_bind_mono: "⟦mono_set B; ⋀y. mono_set (λf. C y f)⟧ ⟹ mono_set (λf. Set.bind (B f) (λy. C y f))"
  and Un_mono: "⟦ mono_set A; mono_set B ⟧ ⟹ mono_set (λf. A f ∪ B f)"
  and Int_mono: "⟦ mono_set A; mono_set B ⟧ ⟹ mono_set (λf. A f ∩ B f)"
  and Diff_mono1: "mono_set A ⟹ mono_set (λf. A f - X)"
  and image_mono: "mono_set A ⟹ mono_set (λf. g ` A f)"
  and vimage_mono: "mono_set A ⟹ mono_set (λf. g -` A f)"
unfolding bind_UNION by(fast intro!: monotoneI dest: monotoneD)+
partial_function (set) test :: "'a list ⇒ nat ⇒ bool ⇒ int set"
where
  "test xs i j = insert 4 (test [] 0 j ∪ test [] 1 True ∩ test [] 2 False - {5} ∪ uminus ` test [undefined] 0 True ∪ uminus -` test [] 1 False)"
interpretation coset: partial_function_definitions "(⊇)" Inter
by(rule complete_lattice.lattice_partial_function_definition[OF dual_complete_lattice])
lemma fun_lub_Inf: "fun_lub Inf = (Inf :: _ ⇒ _ :: complete_lattice)"
by(auto simp add: fun_lub_def fun_eq_iff Inf_fun_def intro: Inf_eqI INF_lower INF_greatest)
lemma fun_ord_ge: "fun_ord (≥) = (≥)"
by(auto simp add: fun_ord_def fun_eq_iff le_fun_def)
lemma coset_admissible: "coset.admissible (λf :: 'a ⇒ 'b set. ∀x y. P x y ⟶ y ∈ f x)"
by(rule ccpo.admissibleI)(auto simp add: fun_lub_Inf)
abbreviation "mono_coset ≡ monotone (fun_ord (⊇)) (⊇)"
lemma gfp_eq_fixp:
  fixes f :: "'a :: complete_lattice ⇒ 'a"
  assumes f: "monotone (≥) (≥) f"
  shows "gfp f = ccpo.fixp Inf (≥) f"
proof (rule antisym)
  from f have f': "mono f" by(simp add: mono_def monotone_def)
  interpret ccpo Inf "(≥)" "mk_less (≥) :: 'a ⇒ _"
    by(rule ccpo)(rule complete_lattice.lattice_partial_function_definition[OF dual_complete_lattice])
  show "ccpo.fixp Inf (≥) f ≤ gfp f"
    by(rule gfp_upperbound)(subst fixp_unfold[OF f], rule order_refl)
  show "gfp f ≤ ccpo.fixp Inf (≥) f"
    by(rule fixp_lowerbound[OF f])(subst gfp_unfold[OF f'], rule order_refl)
qed
lemma fixp_coinduct_set:
  fixes F :: "'c ⇒ 'c"
  and U :: "'c ⇒ 'b ⇒ 'a set"
  and C :: "('b ⇒ 'a set) ⇒ 'c"
  and P :: "'b ⇒ 'a ⇒ bool"
  and x and y
  assumes mono: "⋀x. mono_coset (λf. U (F (C f)) x)"
  and eq: "f ≡ C (ccpo.fixp (fun_lub Inter) (fun_ord (≥)) (λf. U (F (C f))))"
  and inverse2: "⋀f. U (C f) = f"
  and step: "⋀f' x y. ⟦ ⋀x. U f' x = U f' x; ¬ P x y ⟧ ⟹ y ∈ U (F (C (sup (λx. {y. ¬ P x y}) (U f)))) x"
    
  and elem: "y ∉ U f x"
  shows "P x y"
using elem
proof(rule contrapos_np)
  have mono': "monotone (≥) (≥) (λf. U (F (C f)))"
    and mono'': "mono (λf. U (F (C f)))"
    using mono by(simp_all add: monotone_def fun_ord_def le_fun_def mono_def)
  hence eq': "U f = gfp (λf. U (F (C f)))"
    by(subst eq)(simp add: fun_lub_Inf fun_ord_ge gfp_eq_fixp inverse2)
  let ?P = "λx. {y. ¬ P x y}"
  have "?P ≤ gfp (λf. U (F (C f)))"
    using mono'' by(rule coinduct)(auto intro!:  le_funI dest: step[OF refl] simp add: eq')
  moreover
  assume "¬ P x y"
  ultimately show "y ∈ U f x" by(auto simp add: le_fun_def eq')
qed
declaration ‹Partial_Function.init "coset" @{term coset.fixp_fun}
  @{term coset.mono_body} @{thm coset.fixp_rule_uc} @{thm coset.fixp_induct_uc}
  (SOME @{thm fixp_coinduct_set})›
abbreviation "mono_set' ≡ monotone (fun_ord (⊇)) (⊇)"
lemma [partial_function_mono]:
  shows insert_mono': "mono_set' A ⟹ mono_set' (λf. insert x (A f))"
  and UNION_mono': "⟦mono_set' B; ⋀y. mono_set' (λf. C y f)⟧ ⟹ mono_set' (λf. ⋃y∈B f. C y f)"
  and set_bind_mono': "⟦mono_set' B; ⋀y. mono_set' (λf. C y f)⟧ ⟹ mono_set' (λf. Set.bind (B f) (λy. C y f))"
  and Un_mono': "⟦ mono_set' A; mono_set' B ⟧ ⟹ mono_set' (λf. A f ∪ B f)"
  and Int_mono': "⟦ mono_set' A; mono_set' B ⟧ ⟹ mono_set' (λf. A f ∩ B f)"
unfolding bind_UNION by(fast intro!: monotoneI dest: monotoneD)+
context begin
private partial_function (coset) test2 :: "nat ⇒ nat set"
where "test2 x = insert x (test2 (Suc x))"
private lemma test2_coinduct:
  assumes "P x y"
  and *: "⋀x y. P x y ⟹ y = x ∨ (P (Suc x) y ∨ y ∈ test2 (Suc x))"
  shows "y ∈ test2 x"
using ‹P x y›
apply(rule contrapos_pp)
apply(erule test2.raw_induct[rotated])
apply(simp add: *)
done
end
end