Theory utp_recursion

section ‹ Fixed-points and Recursion ›

theory utp_recursion
  imports 
    utp_pred_laws
    utp_rel
begin

subsection ‹ Fixed-point Laws ›
  
lemma mu_id: "(μ X ∙ X) = true"
  by (simp add: antisym gfp_upperbound)

lemma mu_const: "(μ X ∙ P) = P"
  by (simp add: gfp_const)

lemma nu_id: "(ν X ∙ X) = false"                                                            
  by (meson lfp_lowerbound utp_pred_laws.bot.extremum_unique)

lemma nu_const: "(ν X ∙ P) = P"
  by (simp add: lfp_const)

lemma mu_refine_intro:
  assumes "(C ⇒ S) ⊑ F(C ⇒ S)" "(C ∧ μ F) = (C ∧ ν F)"
  shows "(C ⇒ S) ⊑ μ F"
proof -
  from assms have "(C ⇒ S) ⊑ ν F"
    by (simp add: lfp_lowerbound)
  with assms show ?thesis
    by (pred_auto)
qed

subsection ‹ Obtaining Unique Fixed-points ›
    
text ‹ Obtaining termination proofs via approximation chains. Theorems and proofs adapted
  from Chapter 2, page 63 of the UTP book~cite‹"Hoare&98"›.  ›

type_synonym 'a chain = "nat ⇒ 'a upred"

definition chain :: "'a chain ⇒ bool" where
  "chain Y = ((Y 0 = false) ∧ (∀ i. Y (Suc i) ⊑ Y i))"

lemma chain0 [simp]: "chain Y ⟹ Y 0 = false"
  by (simp add:chain_def)

lemma chainI:
  assumes "Y 0 = false" "⋀ i. Y (Suc i) ⊑ Y i"
  shows "chain Y"
  using assms by (auto simp add: chain_def)

lemma chainE:
  assumes "chain Y" "⋀ i. ⟦ Y 0 = false; Y (Suc i) ⊑ Y i ⟧ ⟹ P"
  shows "P"
  using assms by (simp add: chain_def)

lemma L274:
  assumes "∀ n. ((E n ∧p X) = (E n ∧ Y))"
  shows "(⨅ (range E) ∧ X) = (⨅ (range E) ∧ Y)"
  using assms by (pred_auto)

text ‹ Constructive chains ›

definition constr ::
  "('a upred ⇒ 'a upred) ⇒ 'a chain ⇒ bool" where
"constr F E ⟷ chain E ∧ (∀ X n. ((F(X) ∧ E(n + 1)) = (F(X ∧ E(n)) ∧ E (n + 1))))"

lemma constrI:
  assumes "chain E" "⋀ X n. ((F(X) ∧ E(n + 1)) = (F(X ∧ E(n)) ∧ E (n + 1)))"
  shows "constr F E"
  using assms by (auto simp add: constr_def)

text ‹ This lemma gives a way of showing that there is a unique fixed-point when
        the predicate function can be built using a constructive function F
        over an approximation chain E ›

lemma chain_pred_terminates:
  assumes "constr F E" "mono F"
  shows "(⨅ (range E) ∧ μ F) = (⨅ (range E) ∧ ν F)"
proof -
  from assms have "∀ n. (E n ∧ μ F) = (E n ∧ ν F)"
  proof (rule_tac allI)
    fix n
    from assms show "(E n ∧ μ F) = (E n ∧ ν F)"
    proof (induct n)
      case 0 thus ?case by (simp add: constr_def)
    next
      case (Suc n)
      note hyp = this
      thus ?case
      proof -
        have "(E (n + 1) ∧ μ F) = (E (n + 1) ∧ F (μ F))"
          using gfp_unfold[OF hyp(3), THEN sym] by (simp add: constr_def)
        also from hyp have "... = (E (n + 1) ∧ F (E n ∧ μ F))"
          by (metis conj_comm constr_def)
        also from hyp have "... = (E (n + 1) ∧ F (E n ∧ ν F))"
          by simp
        also from hyp have "... = (E (n + 1) ∧ ν F)"
          by (metis (no_types, lifting) conj_comm constr_def lfp_unfold)
        ultimately show ?thesis
          by simp
      qed
    qed
  qed
  thus ?thesis
    by (auto intro: L274)
qed

theorem constr_fp_uniq:
  assumes "constr F E" "mono F" "⨅ (range E) = C"
  shows "(C ∧ μ F) = (C ∧ ν F)"
  using assms(1) assms(2) assms(3) chain_pred_terminates by blast
    
subsection ‹ Noetherian Induction Instantiation›
      
text ‹ Contribution from Yakoub Nemouchi.The following generalization was used by Tobias Nipkow
        and Peter Lammich  in \emph{Refine\_Monadic} ›

lemma  wf_fixp_uinduct_pure_ueq_gen:     
  assumes fixp_unfold: "fp B = B (fp B)"
  and              WF: "wf R"
  and     induct_step:
          "⋀f st. ⟦⋀st'. (st',st) ∈ R  ⟹ (((Pre ∧ ⌈e⌉< =u «st'») ⇒ Post) ⊑ f)⟧
               ⟹ fp B = f ⟹((Pre ∧ ⌈e⌉< =u «st») ⇒ Post) ⊑ (B f)"
        shows "((Pre ⇒ Post) ⊑ fp B)"  
proof -  
  { fix st
    have "((Pre ∧ ⌈e⌉< =u «st») ⇒ Post) ⊑ (fp B)" 
    using WF proof (induction rule: wf_induct_rule)
      case (less x)
      hence "(Pre ∧ ⌈e⌉< =u «x» ⇒ Post) ⊑ B (fp B)"
        by (rule induct_step, rel_blast, simp)
      then show ?case
        using fixp_unfold by auto
    qed
  }
  thus ?thesis 
  by pred_simp  
qed
  
text ‹ The next lemma shows that using substitution also work. However it is not that generic
        nor practical for proof automation ... ›

lemma refine_usubst_to_ueq:
  "vwb_lens E ⟹ (Pre ⇒ Post)⟦«st'»/$E⟧ ⊑ f⟦«st'»/$E⟧ = (((Pre ∧ $E =u «st'») ⇒ Post) ⊑ f)"
  by (rel_auto, metis vwb_lens_wb wb_lens.get_put)  

text ‹ By instantiation of @{thm wf_fixp_uinduct_pure_ueq_gen} with @{term μ} and lifting of the 
        well-founded relation we have ... ›
  
lemma mu_rec_total_pure_rule: 
  assumes WF: "wf R"
  and     M: "mono B"  
  and     induct_step:
          "⋀ f st.  ⟦(Pre ∧ (⌈e⌉<,«st»)u ∈u «R» ⇒ Post) ⊑ f⟧
               ⟹ μ B = f ⟹(Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ (B f)"
        shows "(Pre ⇒ Post) ⊑ μ B"  
proof (rule wf_fixp_uinduct_pure_ueq_gen[where fp=μ and Pre=Pre and B=B and R=R and e=e])
  show "μ B = B (μ B)"
    by (simp add: M def_gfp_unfold)
  show "wf R"
    by (fact WF)
  show "⋀f st. (⋀st'. (st', st) ∈ R ⟹ (Pre ∧ ⌈e⌉< =u «st'» ⇒ Post) ⊑ f) ⟹ 
                μ B = f ⟹ 
                (Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ B f"
    by (rule induct_step, rel_simp, simp)
qed

lemma nu_rec_total_pure_rule: 
  assumes WF: "wf R"
  and     M: "mono B"  
  and     induct_step:
          "⋀ f st.  ⟦(Pre ∧ (⌈e⌉<,«st»)u ∈u «R» ⇒ Post) ⊑ f⟧
               ⟹ ν B = f ⟹(Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ (B f)"
        shows "(Pre ⇒ Post) ⊑ ν B"  
proof (rule wf_fixp_uinduct_pure_ueq_gen[where fp=ν and Pre=Pre and B=B and R=R and e=e])
  show "ν B = B (ν B)"
    by (simp add: M def_lfp_unfold)
  show "wf R"
    by (fact WF)
  show "⋀f st. (⋀st'. (st', st) ∈ R ⟹ (Pre ∧ ⌈e⌉< =u «st'» ⇒ Post) ⊑ f) ⟹ 
                ν B = f ⟹ 
                (Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ B f"
    by (rule induct_step, rel_simp, simp)
qed

text ‹Since @{term "B ((Pre ∧ (⌈E⌉<,«st»)u∈u«R» ⇒ Post)) ⊑ B (μ B)"} and 
      @{term "mono B"}, thus,  @{thm mu_rec_total_pure_rule} can be expressed as follows›
  
lemma mu_rec_total_utp_rule: 
  assumes WF: "wf R"
    and     M: "mono B"  
    and     induct_step:
    "⋀st. (Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ (B ((Pre ∧ (⌈e⌉<,«st»)u ∈u «R» ⇒ Post)))"
  shows "(Pre ⇒ Post) ⊑ μ B"  
proof (rule mu_rec_total_pure_rule[where R=R and e=e], simp_all add: assms)
  show "⋀f st. (Pre ∧ (⌈e⌉<, «st»)u ∈u «R» ⇒ Post) ⊑ f ⟹ μ B = f ⟹ (Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ B f"
    by (simp add: M induct_step monoD order_subst2)
qed

lemma nu_rec_total_utp_rule: 
  assumes WF: "wf R"
    and     M: "mono B"  
    and     induct_step:
    "⋀st. (Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ (B ((Pre ∧ (⌈e⌉<,«st»)u ∈u «R» ⇒ Post)))"
  shows "(Pre ⇒ Post) ⊑ ν B"  
proof (rule nu_rec_total_pure_rule[where R=R and e=e], simp_all add: assms)
  show "⋀f st. (Pre ∧ (⌈e⌉<, «st»)u ∈u «R» ⇒ Post) ⊑ f ⟹ ν B = f ⟹ (Pre ∧ ⌈e⌉< =u «st» ⇒ Post) ⊑ B f"
    by (simp add: M induct_step monoD order_subst2)
qed

end