(*****************************************************************************
* Clean
*
* HOL-TestGen --- theorem-prover based test case generation
* http://www.brucker.ch/projects/hol-testgen/
*
* Copyright (c) 2005-2007 ETH Zurich, Switzerland
* 2009-2017 Univ. Paris-Sud, France
* 2009-2012 Achim D. Brucker, Germany
* 2015-2017 University Sheffield, UK
* 2018-2019 Université Paris-Saclay, Univ. Paris-Sud, France
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* * Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************)
(*
* Monads --- a base testing theory for sequential computations.
* This file is part of HOL-TestGen.
*)
theory MonadSE
imports Main
begin
section‹Definition : Standard State Exception Monads›
text‹State exception monads in our sense are a direct, pure formulation
automata with a partial transition function.›
subsection‹Definition : Core Types and Operators›
type_synonym ('o, 'σ) MONSE = "'σ ⇀ ('o × 'σ)" (* = '\<sigma> \<Rightarrow> ('o \<times> '\<sigma>)option *)
definition bind_SE :: "('o,'σ)MONSE → ('o → ('o','σ)MONSE) → ('o','σ)MONSE"
where "bind_SE f g = (λσ. case f σ of None → None
| Some (out, σ') → g out σ')"
notation bind_SE (‹bindSE›)
syntax (xsymbols)
"_bind_SE" :: "[pttrn,('o,'σ)MONSE,('o','σ)MONSE] → ('o','σ)MONSE"
(‹(2 _ ← _; _)› [5,8,8]8)
translations
"x ← f; g" == "CONST bind_SE f (% x . g)"
definition unit_SE :: "'o → ('o, 'σ)MONSE" (‹(result _)› 8)
where "unit_SE e = (λσ. Some(e,σ))"
notation unit_SE (‹unitSE›)
text‹In the following, we prove the required Monad-laws›
lemma bind_right_unit[simp]: "(x ← m; result x) = m"
apply (simp add: unit_SE_def bind_SE_def)
apply (rule ext)
apply (case_tac "m σ", simp_all)
done
lemma bind_left_unit [simp]: "(x ← result c; P x) = P c"
by (simp add: unit_SE_def bind_SE_def)
lemma bind_assoc[simp]: "(y ← (x ← m; k x); h y) = (x ← m; (y ← k x; h y))"
apply (simp add: unit_SE_def bind_SE_def, rule ext)
apply (case_tac "m σ", simp_all)
apply (case_tac "a", simp_all)
done
subsection‹Definition : More Operators and their Properties›
definition fail_SE :: "('o, 'σ)MONSE"
where "fail_SE = (λσ. None)"
notation fail_SE (‹failSE›)
definition assert_SE :: "('σ → bool) → (bool, 'σ)MONSE"
where "assert_SE P = (λσ. if P σ then Some(True,σ) else None)"
notation assert_SE (‹assertSE›)
definition assume_SE :: "('σ → bool) → (unit, 'σ)MONSE"
where "assume_SE P = (λσ. if ∃σ . P σ then Some((), SOME σ . P σ) else None)"
notation assume_SE (‹assumeSE›)
lemma bind_left_fail_SE[simp] : "(x ← failSE; P x) = failSE"
by (simp add: fail_SE_def bind_SE_def)
text‹We also provide a "Pipe-free" - variant of the bind operator.
a "standard" programming sequential operator without output frills.›
(* TODO: Eliminate/Modify this. Is a consequence of the Monad-Instantiation. *)
definition bind_SE' :: "('α, 'σ)MONSE → ('β, 'σ)MONSE → ('β, 'σ)MONSE" (infixr ‹;-› 10)
where "(f ;- g) = (_ ← f ; g)"
lemma bind_assoc'[simp]: "((m ;- k);- h ) = (m;- (k;- h))"
by(simp add:bind_SE'_def)
lemma bind_left_unit' [simp]: "((result c);- P) = P"
by (simp add: bind_SE'_def)
lemma bind_left_fail_SE'[simp]: "(failSE;- P) = failSE"
by (simp add: bind_SE'_def)
lemma bind_right_unit'[simp]: "(m;- (result ())) = m"
by (simp add: bind_SE'_def)
text‹The bind-operator in the state-exception monad yields already
a semantics for the concept of an input sequence on the meta-level:›
lemma syntax_test: "(o1 ← f1 ; o2 ← f2; result (post o1 o2)) = X"
oops
definition yieldC :: "('a → 'b) → ('b,'a ) MONSE"
where "yieldC f ≡ (λσ. Some(f σ, σ))"
definition try_SE :: "('o,'σ) MONSE → ('o option,'σ) MONSE" (‹trySE›)
where "trySE ioprog = (λσ. case ioprog σ of
None → Some(None, σ)
| Some(outs, σ') → Some(Some outs, σ'))"
text‹In contrast, mbind as a failure safe operator can roughly be seen
as a foldr on bind - try:
m1 ; try m2 ; try m3; ... Note, that the rough equivalence only holds for
certain predicates in the sequence - length equivalence modulo None,
for example. However, if a conditional is added, the equivalence
can be made precise:›
text‹On this basis, a symbolic evaluation scheme can be established
that reduces mbind-code to try\_SE\_code and ite-cascades.›
definition alt_SE :: "[('o, 'σ)MONSE, ('o, 'σ)MONSE] → ('o, 'σ)MONSE" (infixl ‹⊓SE› 10)
where "(f ⊓SE g) = (λ σ. case f σ of None → g σ
| Some H → Some H)"
definition malt_SE :: "('o, 'σ)MONSE list → ('o, 'σ)MONSE"
where "malt_SE S = foldr alt_SE S failSE"
notation malt_SE (‹⊓SE›)
lemma malt_SE_mt [simp]: "⊓SE [] = failSE"
by(simp add: malt_SE_def)
lemma malt_SE_cons [simp]: "⊓SE (a # S) = (a ⊓SE (⊓SE S))"
by(simp add: malt_SE_def)
subsection‹Definition : Programming Operators and their Properties›
definition "skipSE = unitSE ()"
definition if_SE :: "['σ → bool, ('α, 'σ)MONSE, ('α, 'σ)MONSE] → ('α, 'σ)MONSE"
where "if_SE c E F = (λσ. if c σ then E σ else F σ)"
syntax (xsymbols)
"_if_SE" :: "['σ → bool,('o,'σ)MONSE,('o','σ)MONSE] → ('o','σ)MONSE"
(‹(ifSE _ then _ else _fi)› [5,8,8]8)
translations
"(ifSE cond then T1 else T2 fi)" == "CONST if_SE cond T1 T2"
subsection‹Theory of a Monadic While›
text‹Prerequisites›
fun replicator :: "[('a, 'σ)MONSE, nat] → (unit, 'σ)MONSE" (infixr ‹^^^› 60)
where "f ^^^ 0 = (result ())"
| "f ^^^ (Suc n) = (f ;- f ^^^ n)"
fun replicator2 :: "[('a, 'σ)MONSE, nat, ('b, 'σ)MONSE] → ('b, 'σ)MONSE" (infixr ‹^:^› 60)
where "(f ^:^ 0) M = (M )"
| "(f ^:^ (Suc n)) M = (f ;- ((f ^:^ n) M))"
text‹First Step : Establishing an embedding between partial functions and relations›
(* plongement *)
definition Mon2Rel :: "(unit, 'σ)MONSE → ('σ × 'σ) set"
where "Mon2Rel f = {(x, y). (f x = Some((), y))}"
(* ressortir *)
definition Rel2Mon :: " ('σ × 'σ) set → (unit, 'σ)MONSE "
where "Rel2Mon S = (λ σ. if ∃σ'. (σ, σ') ∈ S then Some((), SOME σ'. (σ, σ') ∈ S) else None)"
lemma Mon2Rel_Rel2Mon_id: assumes det:"single_valued R" shows "(Mon2Rel ∘ Rel2Mon) R = R"
apply (simp add: comp_def Mon2Rel_def Rel2Mon_def,auto)
apply (case_tac "∃σ'. (a, σ') ∈ R", auto)
apply (subst (2) some_eq_ex)
using det[simplified single_valued_def] by auto
lemma Rel2Mon_Id: "(Rel2Mon ∘ Mon2Rel) x = x"
apply (rule ext)
apply (auto simp: comp_def Mon2Rel_def Rel2Mon_def)
apply (erule contrapos_pp, drule HOL.not_sym, simp)
done
lemma single_valued_Mon2Rel: "single_valued (Mon2Rel B)"
by (auto simp: single_valued_def Mon2Rel_def)
text‹Second Step : Proving an induction principle allowing to establish that lfp remains
deterministic›
(* A little complete partial order theory due to Tobias Nipkow *)
definition chain :: "(nat → 'a set) → bool"
where "chain S = (∀i. S i ⊆ S(Suc i))"
lemma chain_total: "chain S ==> S i ≤ S j ∨ S j ≤ S i"
by (metis chain_def le_cases lift_Suc_mono_le)
definition cont :: "('a set => 'b set) => bool"
where "cont f = (∀S. chain S ⟶ f(UN n. S n) = (UN n. f(S n)))"
lemma mono_if_cont: fixes f :: "'a set → 'b set"
assumes "cont f" shows "mono f"
proof
fix a b :: "'a set" assume "a ⊆ b"
let ?S = "λn::nat. if n=0 then a else b"
have "chain ?S" using ‹a ⊆ b› by(auto simp: chain_def)
hence "f(UN n. ?S n) = (UN n. f(?S n))"
using assms by (metis cont_def)
moreover have "(UN n. ?S n) = b" using ‹a ⊆ b› by (auto split: if_splits)
moreover have "(UN n. f(?S n)) = f a ∪ f b" by (auto split: if_splits)
ultimately show "f a ⊆ f b" by (metis Un_upper1)
qed
lemma chain_iterates: fixes f :: "'a set → 'a set"
assumes "mono f" shows "chain(λn. (f^^n) {})"
proof-
{ fix n have "(f ^^ n) {} ⊆ (f ^^ Suc n) {}" using assms
by(induction n) (auto simp: mono_def) }
thus ?thesis by(auto simp: chain_def)
qed
theorem lfp_if_cont:
assumes "cont f" shows "lfp f = (∪n. (f ^^ n) {})" (is "_ = ?U")
proof
show "lfp f ⊆ ?U"
proof (rule lfp_lowerbound)
have "f ?U = (UN n. (f^^Suc n){})"
using chain_iterates[OF mono_if_cont[OF assms]] assms
by(simp add: cont_def)
also have "… = (f^^0){} ∪ …" by simp
also have "… = ?U"
apply(auto simp del: funpow.simps)
by (metis empty_iff funpow_0 old.nat.exhaust)
finally show "f ?U ⊆ ?U" by simp
qed
next
{ fix n p assume "f p ⊆ p"
have "(f^^n){} ⊆ p"
proof(induction n)
case 0 show ?case by simp
next
case Suc
from monoD[OF mono_if_cont[OF assms] Suc] ‹f p ⊆ p›
show ?case by simp
qed
}
thus "?U ⊆ lfp f" by(auto simp: lfp_def)
qed
lemma single_valued_UN_chain:
assumes "chain S" "(!!n. single_valued (S n))"
shows "single_valued(UN n. S n)"
proof(auto simp: single_valued_def)
fix m n x y z assume "(x, y) ∈ S m" "(x, z) ∈ S n"
with chain_total[OF assms(1), of m n] assms(2)
show "y = z" by (auto simp: single_valued_def)
qed
lemma single_valued_lfp:
fixes f :: "('a × 'a) set → ('a × 'a) set"
assumes "cont f" "∧r. single_valued r ==> single_valued (f r)"
shows "single_valued(lfp f)"
unfolding lfp_if_cont[OF assms(1)]
proof(rule single_valued_UN_chain[OF chain_iterates[OF mono_if_cont[OF assms(1)]]])
fix n show "single_valued ((f ^^ n) {})"
by(induction n)(auto simp: assms(2))
qed
text‹Third Step: Definition of the Monadic While ‹ ››
definition Γ :: "['σ → bool,('σ × 'σ) set] → (('σ × 'σ) set → ('σ × 'σ) set)"
where "Γ b cd = (λcw. {(s,t). if b s then (s, t) ∈ cd O cw else s = t})"
definition while_SE :: "['σ → bool, (unit, 'σ)MONSE] → (unit, 'σ)MONSE"
where "while_SE c B ≡ (Rel2Mon(lfp(Γ c (Mon2Rel B))))"
syntax (xsymbols)
"_while_SE" :: "['σ → bool, (unit, 'σ)MONSE] → (unit, 'σ)MONSE"
(‹(whileSE _ do _ od)› [8,8]8)
translations
"whileSE c do b od" == "CONST while_SE c b"
lemma cont_Γ: "cont (Γ c b)"
by (auto simp: cont_def Γ_def)
text‹The fixpoint theory now allows us to establish that the lfp constructed over
@{term Mon2Rel} remains deterministic›
theorem single_valued_lfp_Mon2Rel: "single_valued (lfp(Γ c (Mon2Rel B)))"
apply(rule single_valued_lfp, simp_all add: cont_Γ)
apply(auto simp: Γ_def single_valued_def)
apply(metis single_valued_Mon2Rel[of "B"] single_valued_def)
done
lemma Rel2Mon_if:
"Rel2Mon {(s, t). if b s then (s, t) ∈ Mon2Rel c O lfp (Γ b (Mon2Rel c)) else s = t} σ =
(if b σ then Rel2Mon (Mon2Rel c O lfp (Γ b (Mon2Rel c))) σ else Some ((), σ))"
by (simp add: Rel2Mon_def)
lemma Rel2Mon_homomorphism:
assumes determ_X: "single_valued X" and determ_Y: "single_valued Y"
shows "Rel2Mon (X O Y) = ((Rel2Mon X) ;- (Rel2Mon Y))"
proof -
have relational_partial_next_in_O: "∧x E F. (∃y. (x, y) ∈ (E O F)) ==> (∃y. (x, y) ∈ E)"
by (auto)
have some_eq_intro: "∧ X x y . single_valued X ==> (x, y) ∈ X ==> (SOME y. (x, y) ∈ X) = y"
by (auto simp: single_valued_def)
show ?thesis
apply (simp add: Rel2Mon_def bind_SE'_def bind_SE_def)
apply (rule ext, rename_tac "σ")
apply (case_tac " ∃ σ'. (σ, σ') ∈ X O Y")
apply (simp only: HOL.if_True)
apply (frule relational_partial_next_in_O)
apply (auto simp: single_valued_relcomp some_eq_intro determ_X determ_Y relcomp.relcompI)
by blast
qed
text‹Putting everything together, the theory of embedding and the invariance of
determinism of the while-body, gives us the usual unfold-theorem:›
theorem while_SE_unfold:
"(whileSE b do c od) = (ifSE b then (c ;- (whileSE b do c od)) else result () fi)"
apply (simp add: if_SE_def bind_SE'_def while_SE_def unit_SE_def)
apply (subst lfp_unfold [OF mono_if_cont, OF cont_Γ])
apply (rule ext)
apply (subst Γ_def)
apply (auto simp: Rel2Mon_if Rel2Mon_homomorphism bind_SE'_def Rel2Mon_Id [simplified comp_def]
single_valued_Mon2Rel single_valued_lfp_Mon2Rel )
done
lemma bind_cong : " f σ = g σ ==> (x ← f ; M x)σ = (x ← g ; M x)σ"
unfolding bind_SE'_def bind_SE_def by simp
lemma bind'_cong : " f σ = g σ ==> (f ;- M )σ = (g ;- M )σ"
unfolding bind_SE'_def bind_SE_def by simp
lemma ifSE_True [simp]: "(ifSE (λ x. True) then c else d fi) = c"
apply(rule ext) by (simp add: MonadSE.if_SE_def)
lemma ifSE_False [simp]: "(ifSE (λ x. False) then c else d fi) = d"
apply(rule ext) by (simp add: MonadSE.if_SE_def)
lemma ifSE_cond_cong : "f σ = g σ ==>
(ifSE f then c else d fi) σ =
(ifSE g then c else d fi) σ"
unfolding if_SE_def by simp
lemma whileSE_skip[simp] : "(whileSE (λ x. False) do c od) = skipSE"
apply(rule ext,subst MonadSE.while_SE_unfold)
by (simp add: MonadSE.if_SE_def skipSE_def)
end
¤ Dauer der Verarbeitung: 0.18 Sekunden
¤
*© Formatika GbR, Deutschland
|
|