Theory Streams
theory Streams
imports
HOLCF
Nats
WorkerWrapper
begin
section‹Memoisation using streams.›
text ‹
\label{sec:memoisation-example}›
subsection‹Streams.›
text‹The type of infinite streams.›
domain 'a Stream = stcons (lazy sthead :: "'a") (lazy sttail :: "'a Stream") (infixr "&&" 65)
lemma Stream_bisimI[intro]:
"(⋀xs ys. R xs ys
⟹ (xs = ⊥ ∧ ys = ⊥)
∨ (∃h t t'. R t t' ∧ xs = h && t ∧ ys = h && t'))
⟹ Stream_bisim R"
unfolding Stream.bisim_def by auto
fixrec smap :: "('a → 'b) → 'a Stream → 'b Stream"
where
"smap⋅f⋅(x && xs) = f⋅x && smap⋅f⋅xs"
lemma smap_strict[simp]: "smap⋅f⋅⊥ = ⊥"
by fixrec_simp
lemma smap_smap: "smap⋅f⋅(smap⋅g⋅xs) = smap⋅(f oo g)⋅xs"
by (induct xs, simp_all)
fixrec i_th :: "'a Stream → Nat → 'a"
where
"i_th⋅(x && xs) = Nat_case⋅x⋅(i_th⋅xs)"
abbreviation
i_th_syn :: "'a Stream ⇒ Nat ⇒ 'a" (infixl "!!" 100) where
"s !! i ≡ i_th⋅s⋅i"
lemma i_th_strict1[simp]: "⊥ !! i = ⊥"
by fixrec_simp
lemma i_th_strict2[simp]: "s !! ⊥ = ⊥" by (subst i_th.unfold, cases s, simp_all)
lemma i_th_0[simp]: "(s !! 0) = sthead⋅s" by (subst i_th.unfold, cases s, simp_all)
lemma i_th_suc[simp]: "i ≠ ⊥ ⟹ (x && xs) !! (i + 1) = xs !! i" by (subst i_th.unfold, simp)
text‹The infinite stream of natural numbers.›
fixrec nats :: "Nat Stream"
where
"nats = 0 && smap⋅(Λ x. 1 + x)⋅nats"
declare nats.simps[simp del]
subsection‹The wrapper/unwrapper functions.›
definition
unwrapS' :: "(Nat → 'a) → 'a Stream" where
"unwrapS' ≡ Λ f . smap⋅f⋅nats"
lemma unwrapS'_unfold: "unwrapS'⋅f = f⋅0 && smap⋅(f oo (Λ x. 1 + x))⋅nats"
by (unfold unwrapS'_def, subst nats.unfold, simp add: smap_smap)
fixrec unwrapS :: "(Nat → 'a) → 'a Stream"
where
"unwrapS⋅f = f⋅0 && unwrapS⋅(f oo (Λ x. 1 + x))"
declare unwrapS.simps[simp del]
text‹The two versions of @{term "unwrapS"} are equivalent. We could
try to fold some definitions here but it's easier if the stream
constructor is manifest.›
lemma unwrapS_unwrapS'_eq: "unwrapS = unwrapS'" (is "?lhs = ?rhs")
proof(rule cfun_eqI)
fix f show "?lhs⋅f = ?rhs⋅f"
proof(coinduct rule: Stream.coinduct)
let ?R = "λs s'. (∃f. s = f⋅0 && unwrapS⋅(f oo (Λ x. 1 + x))
∧ s' = f⋅0 && smap⋅(f oo (Λ x. 1 + x))⋅nats)"
show "Stream_bisim ?R"
proof
fix s s' assume "?R s s'"
then obtain f where fs: "s = f⋅0 && unwrapS⋅(f oo (Λ x. 1 + x))"
and fs': "s' = f⋅0 && smap⋅(f oo (Λ x. 1 + x))⋅nats"
by blast
have "?R (unwrapS⋅(f oo (Λ x. 1 + x))) (smap⋅(f oo (Λ x. 1 + x))⋅nats)"
by ( rule exI[where x="f oo (Λ x. 1 + x)"]
, subst unwrapS.unfold, subst nats.unfold, simp add: smap_smap)
with fs fs'
show "(s = ⊥ ∧ s' = ⊥)
∨ (∃h t t'.
(∃f. t = f⋅0 && unwrapS⋅(f oo (Λ x. 1 + x))
∧ t' = f⋅0 && smap⋅(f oo (Λ x. 1 + x))⋅nats)
∧ s = h && t ∧ s' = h && t')" by best
qed
show "?R (?lhs⋅f) (?rhs⋅f)"
proof -
have lhs: "?lhs⋅f = f⋅0 && unwrapS⋅(f oo (Λ x. 1 + x))" by (subst unwrapS.unfold, simp)
have rhs: "?rhs⋅f = f⋅0 && smap⋅(f oo (Λ x. 1 + x))⋅nats" by (rule unwrapS'_unfold)
from lhs rhs show ?thesis by best
qed
qed
qed
definition
wrapS :: "'a Stream → Nat → 'a" where
"wrapS ≡ Λ s i . s !! i"
text‹Note the identity requires that @{term "f"} be
strict. \<^citet>‹‹\S6.1› in "GillHutton:2009"› do not make this requirement,
an oversight on their part.
In practice all functions worth memoising are strict in the memoised
argument.›
lemma wrapS_unwrapS_id':
assumes strictF: "(f::Nat → 'a)⋅⊥ = ⊥"
shows "unwrapS⋅f !! n = f⋅n"
using strictF
proof(induct n arbitrary: f rule: Nat_induct)
case bottom with strictF show ?case by simp
next
case zero thus ?case by (subst unwrapS.unfold, simp)
next
case (Suc i f)
have "unwrapS⋅f !! (i + 1) = (f⋅0 && unwrapS⋅(f oo (Λ x. 1 + x))) !! (i + 1)"
by (subst unwrapS.unfold, simp)
also from Suc have "… = unwrapS⋅(f oo (Λ x. 1 + x)) !! i" by simp
also from Suc have "… = (f oo (Λ x. 1 + x))⋅i" by simp
also have "… = f⋅(i + 1)" by (simp add: plus_commute)
finally show ?case .
qed
lemma wrapS_unwrapS_id: "f⋅⊥ = ⊥ ⟹ (wrapS oo unwrapS)⋅f = f"
by (rule cfun_eqI, simp add: wrapS_unwrapS_id' wrapS_def)
subsection‹Fibonacci example.›
definition
fib_body :: "(Nat → Nat) → Nat → Nat" where
"fib_body ≡ Λ r. Nat_case⋅1⋅(Nat_case⋅1⋅(Λ n. r⋅n + r⋅(n + 1)))"
lemma fib_body_strict[simp]: "fib_body⋅r⋅⊥ = ⊥" by (simp add: fib_body_def)
definition
fib :: "Nat → Nat" where
"fib ≡ fix⋅fib_body"
lemma fib_strict[simp]: "fib⋅⊥ = ⊥"
by (unfold fib_def, subst fix_eq, fold fib_def, simp add: fib_body_def)
text‹Apply worker/wrapper.›
definition
fib_work :: "Nat Stream" where
"fib_work ≡ fix⋅(unwrapS oo fib_body oo wrapS)"
definition
fib_wrap :: "Nat → Nat" where
"fib_wrap ≡ wrapS⋅fib_work"
lemma wrapS_unwrapS_fib_body: "wrapS oo unwrapS oo fib_body = fib_body"
proof(rule cfun_eqI)
fix r show "(wrapS oo unwrapS oo fib_body)⋅r = fib_body⋅r"
using wrapS_unwrapS_id[where f="fib_body⋅r"] by simp
qed
lemma fib_ww_eq: "fib = fib_wrap"
using worker_wrapper_body[OF wrapS_unwrapS_fib_body]
by (simp add: fib_def fib_wrap_def fib_work_def)
text‹Optimise.›
fixrec
fib_work_final :: "Nat Stream"
and
fib_f_final :: "Nat → Nat"
where
"fib_work_final = smap⋅fib_f_final⋅nats"
| "fib_f_final = Nat_case⋅1⋅(Nat_case⋅1⋅(Λ n'. fib_work_final !! n' + fib_work_final !! (n' + 1)))"
declare fib_f_final.simps[simp del] fib_work_final.simps[simp del]
definition
fib_final :: "Nat → Nat" where
"fib_final ≡ Λ n. fib_work_final !! n"
text‹
This proof is only fiddly due to the way mutual recursion is encoded:
we need to use Beki\'{c}'s Theorem \<^citep>‹"Bekic:1969"›\footnote{The
interested reader can find some historical commentary in
\<^citet>‹"Harel:1980" and "DBLP:journals/toplas/Sangiorgi09"›.} to massage the
definitions into their final form.
›
lemma fib_work_final_fib_work_eq: "fib_work_final = fib_work" (is "?lhs = ?rhs")
proof -
let ?wb = "Λ r. Nat_case⋅1⋅(Nat_case⋅1⋅(Λ n'. r !! n' + r !! (n' + 1)))"
let ?mr = "Λ (fwf :: Nat Stream, fff). (smap⋅fff⋅nats, ?wb⋅fwf)"
have "?lhs = fst (fix⋅?mr)"
by (simp add: fib_work_final_def split_def csplit_def)
also have "… = (μ fwf. fst (?mr⋅(fwf, μ fff. snd (?mr⋅(fwf, fff)))))"
using fix_cprod[where F="?mr"] by simp
also have "… = (μ fwf. smap⋅(μ fff. ?wb⋅fwf)⋅nats)" by simp
also have "… = (μ fwf. smap⋅(?wb⋅fwf)⋅nats)" by (simp add: fix_const)
also have "… = ?rhs"
unfolding fib_body_def fib_work_def unwrapS_unwrapS'_eq unwrapS'_def wrapS_def
by (simp add: cfcomp1)
finally show ?thesis .
qed
lemma fib_final_fib_eq: "fib_final = fib" (is "?lhs = ?rhs")
proof -
have "?lhs = (Λ n. fib_work_final !! n)" by (simp add: fib_final_def)
also have "… = (Λ n. fib_work !! n)" by (simp only: fib_work_final_fib_work_eq)
also have "… = fib_wrap" by (simp add: fib_wrap_def wrapS_def)
also have "… = ?rhs" by (simp only: fib_ww_eq)
finally show ?thesis .
qed
end