Theory Boustrophedon_Transform_Impl
theory Boustrophedon_Transform_Impl
imports Boustrophedon_Transform Secant_Numbers Tangent_Numbers "HOL-Library.Stream"
begin
subsection ‹Implementation›
text ‹
In the following we will provide some simple functions based on infinite streams
to compute the Seidel triangle and the Boustrophedon transform of a sequence efficiently.
›
text ‹
The core functionality is the following auxiliary function, which produces the next row of the
Seidel triangle from the current row and the corresponding entry in the input sequence.
›
primrec seidel_triangle_rows_step :: "'a :: monoid_add ⇒ 'a list ⇒ 'a list" where
"seidel_triangle_rows_step a [] = [a]"
| "seidel_triangle_rows_step a (x # xs) = a # seidel_triangle_rows_step (a + x) xs"
primrec seidel_triangle_rows_step_tailrec :: "'a :: monoid_add ⇒ 'a list ⇒ 'a list ⇒ 'a list" where
"seidel_triangle_rows_step_tailrec a [] acc = a # acc"
| "seidel_triangle_rows_step_tailrec a (x # xs) acc =
seidel_triangle_rows_step_tailrec (a + x) xs (a # acc)"
lemma seidel_triangle_rows_step_tailrec_correct [simp]:
"seidel_triangle_rows_step_tailrec a xs acc =
rev (seidel_triangle_rows_step a xs) @ acc"
by (induction xs arbitrary: a acc) simp_all
lemma length_seidel_triangle_rows_step [simp]:
"length (seidel_triangle_rows_step a xs) = Suc (length xs)"
by (induction xs arbitrary: a) auto
lemma nth_seidel_triangle_rows_step:
"i ≤ length xs ⟹ seidel_triangle_rows_step a xs ! i = a + sum_list (take i xs)"
by (induction xs arbitrary: i a) (auto simp: nth_Cons add_ac split: nat.splits)
lemma seidel_triangle_rows_step_correct:
fixes a :: "nat ⇒ 'a :: comm_monoid_add"
shows "seidel_triangle_rows_step (a n) (map (seidel_triangle a (n-Suc 0)) (rev [0..<n])) =
map (seidel_triangle a n) [0..<Suc n]"
proof (rule nth_equalityI, goal_cases)
case i: (2 i)
have "seidel_triangle_rows_step (a n) (map (seidel_triangle a (n-1)) (rev [0..<n])) ! i =
a n + sum_list (take i (map (seidel_triangle a (n - Suc 0)) (rev [0..<n])))"
using i by (subst nth_seidel_triangle_rows_step) auto
also have "sum_list (take i (map (seidel_triangle a (n - Suc 0)) (rev [0..<n]))) =
(∑j<i. seidel_triangle a (n - 1) (n - Suc j))"
using i by (subst sum.list_conv_set_nth) (simp_all add: atLeast0LessThan rev_nth)
also have "a n + … = seidel_triangle a n i"
by (rule seidel_triangle_conv_rowsum [symmetric]) (use i in auto)
also have "… = map (seidel_triangle a n) [0..<Suc n] ! i"
using i by (subst nth_map) (auto simp del: upt_Suc)
finally show ?case by simp
qed auto
text ‹
This auxiliary function produces an infinite stream of all the subsequent rows of the Seidel
triangle, given the current row and a stream of the remaining elements of the input sequence.
›
primcorec seidel_triangle_rows_aux :: "'a :: comm_monoid_add stream ⇒ 'a list ⇒ 'a list stream" where
"seidel_triangle_rows_aux as xs =
(let ys = seidel_triangle_rows_step_tailrec (shd as) xs []
in rev ys ## seidel_triangle_rows_aux (stl as) ys)"
lemma seidel_triangle_rows_aux_correct:
"seidel_triangle_rows_aux (sdrop n as)
(map (seidel_triangle (λi. as !! i) (n-Suc 0)) (rev [0..<n])) !! m =
map (seidel_triangle (λi. as !! i) (n + m)) [0..<Suc (n+m)]"
proof (induction m arbitrary: n)
case 0
show ?case
by (simp add: seidel_triangle_rows_step_correct del: upt_Suc)
next
case (Suc m n)
have "seidel_triangle_rows_aux (sdrop n as)
(map (seidel_triangle ((!!) as) (n - 1)) (rev [0..<n])) !! Suc m =
seidel_triangle_rows_aux (sdrop (Suc n) as)
(map (seidel_triangle ((!!) as) n) (rev [0..<Suc n])) !! m"
by (simp add: seidel_triangle_rows_step_correct rev_map del: upt_Suc)
also have "… = map (seidel_triangle ((!!) as) (Suc (n + m))) [0..<n+m+2]"
using Suc.IH[of "Suc n"] by (simp del: upt_Suc)
finally show ?case
by simp
qed
text ‹
This function produces an infinite stream of all the rows of the Seidel triangle of the
sequence given by the input stream.
Note that in the literature the triangle is often printed with every other row
reversed, to emphasise the ``ox-plow'' nature of the recurrence. It is however
mathematically more natural to not do this, so our version does not do this.
›
definition seidel_triangle_rows :: "'a :: comm_monoid_add stream ⇒ 'a list stream" where
"seidel_triangle_rows as = seidel_triangle_rows_aux as []"
lemma seidel_triangle_rows_correct:
"seidel_triangle_rows as !! n = map (seidel_triangle (λi. as !! i) n) [0..<Suc n]"
using seidel_triangle_rows_aux_correct[of 0 as n]
by (simp del: upt_Suc add: seidel_triangle_rows_def)
primcorec boustrophedon_stream_aux :: "'a :: comm_monoid_add stream ⇒ 'a list ⇒ 'a stream" where
"boustrophedon_stream_aux as xs =
(let ys = seidel_triangle_rows_step_tailrec (shd as) xs []
in hd ys ## boustrophedon_stream_aux (stl as) ys)"
lemma boustrophedon_stream_aux_conv_seidel_triangle_rows_aux:
"boustrophedon_stream_aux as xs = smap last (seidel_triangle_rows_aux as xs)"
by (coinduction arbitrary: as xs) (auto simp: hd_rev)
lemma boustrophedon_stream_aux_correct:
"boustrophedon_stream_aux (sdrop n as)
(map (seidel_triangle (λi. as !! i) (n - Suc 0)) (rev [0..<n])) !! m =
boustrophedon (λi. as !! i) (n + m)"
by (subst boustrophedon_stream_aux_conv_seidel_triangle_rows_aux, subst snth_smap,
subst seidel_triangle_rows_aux_correct)
(simp add: boustrophedon_def)
text ‹
This function produces the Boustrophedon transform of a stream.
›
definition boustrophedon_stream :: "'a :: comm_monoid_add stream ⇒ 'a stream" where
"boustrophedon_stream as = boustrophedon_stream_aux as []"
lemma boustrophedon_stream_correct:
"boustrophedon_stream as !! n = boustrophedon (λi. as !! i) n"
using boustrophedon_stream_aux_correct[of 0 as n]
by (simp add: boustrophedon_stream_def)
text ‹
Lastly, we also provide a function to compute a single number in the transformed sequence
to avoid code-generation problems related to streams.
›
fun seidel_triangle_impl_aux :: "(nat ⇒ 'a :: comm_monoid_add) ⇒ 'a list ⇒ nat ⇒ nat ⇒ nat ⇒ 'a" where
"seidel_triangle_impl_aux a xs i n k =
(let ys = seidel_triangle_rows_step_tailrec (a i) xs []
in if n = 0 then ys ! (i - k) else seidel_triangle_impl_aux a ys (i + 1) (n - 1) k)"
lemmas [simp del] = seidel_triangle_impl_aux.simps
lemma seidel_triangle_impl_aux_correct:
assumes "k ≤ n + i" "length xs = i"
shows "seidel_triangle_impl_aux a xs i n k =
seidel_triangle_rows_aux (smap a (fromN i)) xs !! n ! k"
using assms
by (induction n arbitrary: k i xs)
(subst seidel_triangle_impl_aux.simps; simp add: Let_def rev_nth)+
lemma seidel_triangle_code [code]:
"seidel_triangle a n k = (if k > n then 0 else seidel_triangle_impl_aux a [] 0 n k)"
using seidel_triangle_impl_aux_correct[of k n 0 "[]" a]
seidel_triangle_rows_aux_correct[of 0 "smap a nats" n]
by (simp del: upt_Suc)
lemma entringer_number_code [code]:
"entringer_number n k = seidel_triangle (λn. if n = 0 then 1 else 0) n k"
by (subst entringer_number_conv_seidel_triangle) auto
end