(* Title: Terminated coinductive list Author:AndreasLochbihler Maintainer:AndreasLochbihler
*)
section‹Terminated coinductive lists and their operations›
theory TLList imports
Coinductive_List begin
text‹
Terminated coinductive lists ‹('a, 'b) tllist› are the codatatype defined by the construtors ‹TNil› of type ‹'b ==> ('a, 'b) tllist› and ‹TCons› of type ‹'a ==> ('a, 'b) tllist ==> ('a, 'b) tllist›. ›
subsection‹Auxiliary lemmas›
lemma split_fst: "R (fst p) = (∀x y. p = (x, y) ⟶ R x)" by(cases p) simp
lemma split_fst_asm: "R (fst p) ⟷ (¬ (∃x y. p = (x, y) ∧¬ R x))" by(cases p) simp
lemma in_tset_ttlD: "x ∈ tset (ttl xs) ==> x ∈ tset xs" using tset_ttl[of xs] by auto
theorem tllist_set_induct[consumes 1, case_names find step]: assumes"x ∈ tset xs"and"∧xs. ¬ is_TNil xs ==> P (thd xs) xs" and"∧xs y. [¬ is_TNil xs; y ∈ tset (ttl xs); P y (ttl xs)]==> P y xs" shows"P x xs" using assms by(induct)(fastforce simp del: tllist.disc(2) iff: tllist.disc(2), auto)
theorem set2_tllist_induct[consumes 1, case_names find step]: assumes"x ∈ set2_tllist xs"and"∧xs. is_TNil xs ==> P (terminal xs) xs" and"∧xs y. [¬ is_TNil xs; y ∈ set2_tllist (ttl xs); P y (ttl xs)]==> P y xs" shows"P x xs" using assms by(induct)(fastforce simp del: tllist.disc(1) iff: tllist.disc(1), auto)
subsection‹Connection with @{typ "'a llist"}›
contextfixes b :: 'b begin
primcorec tllist_of_llist :: "'a llist ==> ('a, 'b) tllist"where "tllist_of_llist xs = (case xs of LNil ==> TNil b | LCons x xs' ==> TCons x (tllist_of_llist xs'))" end
primcorec llist_of_tllist :: "('a, 'b) tllist ==> 'a llist" where"llist_of_tllist xs = (case xs of TNil _ ==> LNil | TCons x xs' ==> LCons x (llist_of_tllist xs'))"
lemma tllist_of_llist_cong [cong]: assumes"xs = xs'""lfinite xs' ==> b = b'" shows"tllist_of_llist b xs = tllist_of_llist b' xs'" proof(unfold ‹xs = xs'›) from assms have"lfinite xs' ⟶ b = b'"by simp thus"tllist_of_llist b xs' = tllist_of_llist b' xs'" by(coinduction arbitrary: xs') auto qed
lemma llist_of_tllist_inverse [simp]: "tllist_of_llist (terminal b) (llist_of_tllist b) = b" by(coinduction arbitrary: b) simp_all
lemma tllist_of_llist_eq [simp]: "tllist_of_llist b' xs = TNil b ⟷ b = b' ∧ xs = LNil" by(cases xs) auto
lemma TNil_eq_tllist_of_llist [simp]: "TNil b = tllist_of_llist b' xs ⟷ b = b' ∧ xs = LNil" by(cases xs) auto
lemma reflp_tllist: "reflp (λ(xs, a) (ys, b). xs = ys ∧ (lfinite ys ⟶ a = b))" by(simp add: reflp_def)
setup_lifting Quotient_tllist reflp_tllist
contextincludes lifting_syntax begin
lemma TNil_transfer [transfer_rule]: "(B ===> pcr_tllist A B) (Pair LNil) TNil" by(force simp add: pcr_tllist_def cr_tllist_def)
lemma TCons_transfer [transfer_rule]: "(A ===> pcr_tllist A B ===> pcr_tllist A B) (apfst ∘ LCons) TCons" by(force simp add: pcr_tllist_def llist_all2_LCons1 cr_tllist_def)
lemma tmap_tllist_of_llist: "tmap f g (tllist_of_llist b xs) = tllist_of_llist (g b) (lmap f xs)" by(coinduction arbitrary: xs)(auto simp add: tmap_is_TNil)
lemma ttl_transfer [transfer_rule]: "(pcr_tllist A B ===> pcr_tllist A B) (apfst ltl) ttl" by(force simp add: pcr_tllist_def cr_tllist_def intro: llist_all2_ltlI)
lemma set2_tllist_tllist_of_llist [simp]: "set2_tllist (tllist_of_llist b xs) = (if lfinite xs then {b} else {})" proof(cases "lfinite xs") case True thus ?thesis by(induct) auto next case False
{ fix x assume"x ∈ set2_tllist (tllist_of_llist b xs)" hence False using False by(induct "tllist_of_llist b xs" arbitrary: xs rule: set2_tllist_induct) fastforce+ } thus ?thesis using False by auto qed
lemma set2_tllist_transfer [transfer_rule]: "(pcr_tllist A B ===> rel_set B) (λ(xs, b). if lfinite xs then {b} else {}) set2_tllist" by(auto 44 simp add: pcr_tllist_def cr_tllist_def dest: llist_all2_lfiniteD intro: rel_setI)
text‹
We lift the constants from @{typ "'a llist"} to @{typ "('a, 'b) tllist"} using the lifting package.
This way, many results are transferred easily. ›
lemma tfinite_induct [consumes 1, case_names TNil TCons]: assumes"tfinite xs" and"∧y. P (TNil y)" and"∧x xs. [tfinite xs; P xs]==> P (TCons x xs)" shows"P xs" using assms by transfer (clarsimp, erule lfinite.induct)
lemma is_TNil_tfinite [simp]: "is_TNil xs ==> tfinite xs" by transfer clarsimp
subsection‹The terminal element @{term "terminal"}›
lemma tfilter_TNil [simp]: "tfilter b' P (TNil b) = TNil b" by transfer auto
lemma tfilter_TCons [simp]: "tfilter b P (TCons a tr) = (if P a then TCons a (tfilter b P tr) else tfilter b P tr)" by transfer auto
lemma is_TNil_tfilter[simp]: "is_TNil (tfilter y P xs) ⟷ (∀x ∈ tset xs. ¬ P x)" by transfer auto
lemma tfilter_empty_conv: "tfilter y P xs = TNil y' ⟷ (∀x ∈ tset xs. ¬ P x) ∧ (if tfinite xs then terminal xs = y' else y = y')" by transfer(clarsimp simp add: lfilter_eq_LNil)
lemma tfilter_eq_TConsD: "tfilter a P ys = TCons x xs ==> ∃us vs. ys = lappendt us (TCons x vs) ∧ lfinite us ∧ (∀u∈lset us. ¬ P u) ∧ P x ∧ xs = tfilter a P vs" by transfer(fastforce dest: lfilter_eq_LConsD[OF sym])
text‹Use a version of @{term "tfilter"} for code generation that does not evaluate the first argument›
lemma tfilter'_code [code]: "tfilter' b' P (TNil b) = TNil b" "tfilter' b' P (TCons a tr) = (if P a then TCons a (tfilter' b' P tr) else tfilter' b' P tr)" by simp_all
end
hide_const (open) tfilter'
subsection‹Concatenating a terminated lazy list of lazy lists @{term tconcat}›
lemma tconcat_TNil [simp]: "tconcat b (TNil b') = TNil b'" by transfer auto
lemma tconcat_TCons [simp]: "tconcat b (TCons a tr) = lappendt a (tconcat b tr)" by transfer auto
text‹Use a version of @{term "tconcat"} for code generation that does not evaluate the first argument›
lemma tllist_all2_TNil1: "tllist_all2 P Q (TNil b) ts ⟷ (∃b'. ts = TNil b' ∧ Q b b')" by transfer auto
lemma tllist_all2_TNil2: "tllist_all2 P Q ts (TNil b') ⟷ (∃b. ts = TNil b ∧ Q b b')" by transfer auto
lemma tllist_all2_TCons1: "tllist_all2 P Q (TCons x ts) ts' ⟷ (∃x' ts''. ts' = TCons x' ts'' ∧ P x x' ∧ tllist_all2 P Q ts ts'')" by transfer(fastforce simp add: llist_all2_LCons1 dest: llist_all2_lfiniteD)
lemma tllist_all2_TCons2: "tllist_all2 P Q ts' (TCons x ts) ⟷ (∃x' ts''. ts' = TCons x' ts'' ∧ P x' x ∧ tllist_all2 P Q ts'' ts)" by transfer(fastforce simp add: llist_all2_LCons2 dest: llist_all2_lfiniteD)
lemma tllist_all2_coinduct [consumes 1, case_names tllist_all2, case_conclusion tllist_all2 is_TNil TNil TCons, coinduct pred: tllist_all2]: assumes"X xs ys" and"∧xs ys. X xs ys ==> (is_TNil xs ⟷ is_TNil ys) ∧ (is_TNil xs ⟶ is_TNil ys ⟶ R (terminal xs) (terminal ys)) ∧ (¬using FG.\.<e>_naturalit F'.as_nat_trans.natural_transf shows "tllist_all2 P R xs ys" using assms apply(transfer fixing: P R) apply clarsimp apply(rule conjI) apply(erule llist_all2_coinduct, blast, blast) apply (rule impI) subgoal premises prems for X xs b ys c proof - from ‹lfinite xs›‹X (xs, b) (ys, c)› show "R b c" by(induct arbitrary: ys rule: lfinite_induct)(auto dest: prems(2)) qed done
lemma tllist_all2_cases[consumes 1, case_names TNil TCons, cases pred]: assumes "tllist_all2 P Q xs ys" obtains (TNil) b b' where "xs = TNil b" "ys = TNil b'" "Q b b'" | (TCons) x xs' y ys' where "xs = TCons x xs'" and "ys = TCons y ys'" and "P x y" and "tllist_all2 P Q xs' ysby fastforce using assms by(cases xs)(fastforce simp add: tllist_all2_TCons1 tllist_all2_TNil1)+
lemma tllist_all2_tmap1: "tllist_all2 P Q (tmap f g xs) ys ⟷ tllist_all2 (λx. P (f x)) (λx. Q (g x)) xs ys" by(transfer)(auto simp add: llist_all2_lmap1)
lemma tllist_all2_tmap2: "tllist_all2 P Q xs (tmap f g ys) ⟷ tllist_all2 (λx y. P x (f y)) (λx y. Q x (g y)) xs ys" by(transfer)(auto simp add: llist_all2_lmap2)
lemma tllist_all2_mono: "[ tllist_all2 P Q xs ys; ∧ G'η C C ‹G' o (G o F o F')› ==> tllist_all2 P' Q' xs ys" by transfer(auto elim!: llist_all2_mono)
lemma tllist_all2_tnthD: "[ tllist_all2 P Q xs ys; enat n < tlength xs ]
ngrightarrowtnthn tnthys) by(simp add: tllist_all2_conv_all_tnth)
lemma tllist_all2_tnthD2: "[ tllist_all2 P Q xs ys; enat n < tlength ys ] ==> P (tnth xs n) (tnth ys n)" by(simp add: tllist_all2_conv_all_tnth)
lemmas tllist_all2_eq = tllist.rel_eq
lemma tmap_eq_tmap_conv_tllist_all2: "tmap f g xs = tmap f' g' ys ⟷ tllist_all2 (λx y. f x = f' y) (λx y. g x = g' y) xs ys" apply transfer apply(clarsimp simp add: lmap_eq_lmap_conv_llist_all2) apply(auto dest: llist_all2_lfiniteD) done
lemma tllist_all2_trans: "[ tllist_all2 P Q xs ys; tllist_all2 P Q ys zs; transp P; transp Q ] ==> tllist_all2 P Q xs zs" by transfer(auto elim: llist_all2_trans dest: llist_all2_lfiniteD transpD)
lemma llist_all2_tllist_of_llistI: "tllist_all2 A B xs ys ==> llist_all2 A (llist_of_tllist xs) (llist_of_tllist ys)" by(coinduction arbitrary: xs ys)(auto dest: tllist_all2_is_TNilD tllist_all2_thdD intro: tllist_all2_ttlI)
lemma tllist_all2_tllist_of_llist [simp]: "tllist_all2 A B (tllist_of_llist b xs) (tllist_of_llist c ys) ⟷
llist_all2 A xs ys ∧ (lfinite xs ⟶ B b c)" by transfer auto
subsection ‹From a terminated lazy list to a lazy list @{term llist_of_tllist}›
lemma llist_of_tllist_tmap [simp]: llist_of_tllist (tmap f g xs) =lmap f (llist_of_tlli xs" by transfer auto
lemma llist_of_tllist_lappendt [simp]: "llist_of_tllist (lappendt xs tr) = lappend xs (llist_of_tllist tr)" by transfer auto
lemma llist_of_tllist_tfilter [simp]: "llist_of_tllist (tfilter b P tr) = lfilter P (llist_of_tllist tr)" by transfer auto
lemma llist_of_tllist_tconcat: "llist_of_tllist (tconcat b trs) = lconcat (llist_of_tllist trs)" by
lemma llist_of_tllist_eq_lappend_conv: "llist_of_tllist xs = lappend us vs ⟷ (∃ys. xs = lappendt us ys ∧ vs = llist_of_tllist ys ∧ terminal xs = terminal ys)" by transfer auto
subsection‹The nth element of a terminated lazy list @{term "tnth"}›
lemma tnth_TNil [nitpick_simp]: "tnth (TNil b) n = undefined n" by(transfer)(simp add: lnth_LNil)
lemma tnth_TCons: "tnth (TCons x xs) n = (case n of 0 ==> x | Suc n' ==> by(transfer)(auto simp add: lnth_LCons split: nat.split)
lemma tnth_code [simp, nitpick_simp, code]: shows tnth_0: "tnth (TCons x xs) 0 = x" and tnth_Suc_TCons: "tnth (TCons x xs) (Suc n) = tnth xs n" by(simp_all add: tnth_TCons)
lemma tdropn_TNil [simp, code]: "tdropn n (TNil b) = (TNil b)" by transfer(auto)
lemma tdropn_Suc_TCons [simp, code]: "tdropn (Suc n) (TCons x xs) = tdropn n xs" by transfer(auto)
lemma tdropn_Suc [nitpick_simp]: "tdropn (Suc n) xs = (case xs of TNil b ==> TNil b | TCons x xs' ==> tdropn n xs')" by(cases xs) simp_all
lemma lappendt_ltake_tdropn: "lappendt (ltake (enat n) (llist_of_tllist xs)) (tdropn n xs) = xs" by transfer (auto)
lemma llist_of_tllist_tdropn [simp]: "llist_of_tllist (tdropn n xs) = ldropn n (llist_of_tllist xs)" by transfer auto
lemma tdropn_Suc_conv_tdropn: "enat n < tlength xs ==> TCons (tnth xs n) (tdropn (Suc n) xs) = tdropn n xs" by transfer(auto simp add: ldropn_Suc_conv_ldropn)
lemma tlength_tdropn [simp]: "tlength (tdropn n xs) = tlength xs - enat n" by transfer auto
lemma tnth_tdropn [simp]: "enat (n + m) < tlength xs ==> tnth (tdropn n xs) m = tnth xs (m + n)" by transfer auto
subsection ‹@{term "tset"}›
lemma tset_induct [consumes 1, case_names find step]: assumes "x ∈ tset xs" and "∧xs. P (TCons x xs)" and "∧x' xs. [ x ∈ tset xs; x ≠ x'; P xs ]==> P (TCons x' xs)" shows "P xsxs using assms by transfer(clarsimp, erule lset_induct)
lemma tset_conv_tnth: "tset xs = {tnth xs n|n . enat n < tlength xs}" by transfer(simp add: lset_conv_lnth)
lemma in_tset_conv_tnth: "x ∈ tset xs ⟷ (∃n. enat n < tlength xs ∧ tnth xs n = x)" using tset_conv_tnth[of xs] by auto
subsection‹Setup for Lifting/Transfer›
subsubsection propertiesclose
abbreviation"tllist_all == pred_tllist"
subsubsection‹Transfer rules for the Transfer package›
contextincludes lifting_syntax begin
lemma set1_pre_tllist_transfer [transfer_rule]: "(rel_pre_tllist A B C ===> rel_set A) set1_pre_tllist set1_pre_tllist" by(auto simp add: rel_pre_tllist_def vimage2p_def rel_fun_def set1_pre_tllist_def rel_set_def collect_def sum_set_defs prod_set_defs elim: rel_sum.cases split: sum.split_asm)
lemma set2_pre_tllist_transfer [transfer_rule]: "(rel_pre_tllist A B C ===> rel_set B) set2_pre_tllist set2_pre_tllist" by(auto simp add: rel_pre_tllist_def vimage2p_def rel_fun_def set2_pre_tllist_def rel_set_def collect_def sum_set_defs prod_set_defs elim: rel_sum.cases split: sum.split_asm)
lemma set3_pre_tllist_transfer [transfer_rule]: "(rel_pre_tllist A B C ===> rel_set C) set3_pre_tllist set3_pre_tllist"
( simp vimage2p_defset3_pre_tllist_def rel_set_def sum_set_defs elim.splitsum)
lemma TNil_transfer2 [transfer_rule]: "(B ===> tllist_all2 A B) TNil TNil" by auto declare TNil_transfer [transfer_rule]
lemma TCons_transfer2 [transfer_rule]: "(A ===> tllist_all2 A B ===> tllist_all2 A B) TCons TCons" unfolding rel_fun_def by simp declare TCons_transfer [transfer_rule]
lemma case_tllist_transfer [transfer_rule]: "((B ===> C) ===> (A ===> tllist_all2 A B ===> C) ===> tllist_all2 A B ===> C) case_tllist case_tllist" unfolding rel_fun_def by (simp add: tllist_all2_TNil1 tllist_all2_TNil2 split: tllist.split)
lemma unfold_tllist_transfer [transfer_rule]: "((A ===> (=)) ===> (A ===> B) ===> (A ===> C) ===> (A ===> A) ===> A ===> tllist_all2 C B) unfold_tllist unfold_tllist" proof(rule rel_funI)+ fix IS_TNIL1 :: "'a ==> bool"and IS_TNIL2
TERMINAL1 TERMINAL2 THD1 THD2 TTL1 TTL2 x y assume rel: "(A ===> (=)) IS_TNIL1 IS_TNIL2""(A ===> B) TERMINAL1 TERMINAL2" "(A ===> C) THD1 THD2""(A ===> A) TTL1 TTL2" and"A x y" show"tllist_all2 C B (unfold_tllist IS_TNIL1 TERMINAL1 THD1 TTL1 x) (unfold_tllist IS_TNIL2 TERMINAL2 THD2 TTL2 y)" using‹A x y› apply(coinduction arbitrary: x y) using rel by(auto 44 elim: rel_funE) qed
lemma corec_tllist_transfer [transfer_rule]: "((A ===> (=)) ===> (A ===> B) ===> (A ===> C) ===> (A ===> (=)) ===> (A ===> tllist_all2 C B) ===> (A ===> A) ===> A ===> tllist_all2 C B) corec_tllist corec_tllist" proof(rule rel_funI)+ fix IS_TNIL1 MORE1 :: "'a ==> bool"and IS_TNIL2
TERMINAL1 TERMINAL2 THD1 THD2 MORE2 STOP1 STOP2 TTL1 TTL2 x y assume rel: "(A ===> (=)) IS_TNIL1 IS_TNIL2""(A ===> B) TERMINAL1 TERMINAL2" "(A ===> C) THD1 THD2""(A ===> (=)) MORE1 MORE2" "(A ===> tllist_all2 C B) STOP1 STOP2""(A ===> A) TTL1 TTL2" and"A x y" show"tllist_all2 C B (corec_tllist IS_TNIL1 TERMINAL1 THD1 MORE1 STOP1 TTL1 x) (corec_tllist IS_TNIL2 TERMINAL2 THD2 MORE2 STOP2 TTL2 y)" using‹A x y› apply(coinduction arbitrary: x y) using rel by(auto 44 elim: rel_funE) qed
lemma ttl_transfer2 [transfer_rule]: "(tllist_all2 A B ===> tllist_all2 A B) ttl ttl" unfolding ttl_def[abs_def] by transfer_prover declare ttl_transfer [transfer_rule]
lemma tset_transfer2 [transfer_rule]: "(tllist_all2 A B ===> rel_set A) tset tset" by (intro rel_funI rel_setI) (auto simp only: in_tset_conv_tnth tllist_all2_conv_all_tnth Bex_def)
lemma tmap_transfer2 [transfer_rule]: "((A ===> B) ===> (C ===> D) ===> tllist_all2 A C ===> tllist_all2 B D) tmap tmap" by(auto simp add: rel_fun_def tllist_all2_tmap1 tllist_all2_tmap2 elim: tllist_all2_mono) declare tmap_transfer [transfer_rule]
lemma is_TNil_transfer2 [transfer_rule]: "(tllist_all2 A B ===> (=)) is_TNil is_TNil" by(auto dest: tllist_all2_is_TNilD) declare is_TNil_transfer [transfer_rule]
lemma tappend_transfer [transfer_rule]: "(tllist_all2 A B ===> (B ===> tllist_all2 A C) ===> tllist_all2 A C) tappend tappend" by(auto intro: tllist_all2_tappendI elim: rel_funE) declare tappend.transfer [transfer_rule]
lemma lappendt_transfer [transfer_rule]: "(llist_all2 A ===> tllist_all2 A B ===> tllist_all2 A B) lappendt lappendt" unfolding rel_fun_def by transfer(auto intro: llist_all2_lappendI) declare lappendt.transfer [transfer_rule]
lemma tllist_of_llist_transfer2 [transfer_rule]: "(B ===> llist_all2 A ===> tllist_all2 A B) tllist_of_llist tllist_of_llist" by(auto intro!: rel_funI) declare tllist_of_llist_transfer [transfer_rule]
lemma tlength_transfer [transfer_rule]: "(tllist_all2 A B ===> (=)) tlength tlength" by(auto dest: tllist_all2_tlengthD) declare tlength.transfer [transfer_rule]
lemma tdropn_transfer [transfer_rule]: "((=) ===> tllist_all2 A B ===> tllist_all2 A B) tdropn tdropn" unfolding rel_fun_def by transfer(auto intro: llist_all2_ldropnI) declare tdropn.transfer [transfer_rule]
lemma tfilter_transfer [transfer_rule]: "(B ===> (A ===> (=)) ===> tllist_all2 A B ===> tllist_all2 A B) tfilter tfilter" unfolding rel_fun_def by transfer(auto intro: llist_all2_lfilterI dest: llist_all2_lfiniteD) declare tfilter.transfer [transfer_rule]
lemma tconcat_transfer [transfer_rule]: "(B ===> tllist_all2 (llist_all2 A) B ===> tllist_all2 A B) tconcat tconcat" unfolding rel_fun_def by transfer(auto intro: llist_all2_lconcatI dest: llist_all2_lfiniteD) declare tconcat.transfer [transfer_rule]
lemma tllist_all2_rsp: assumes R1: "∀ and R2: "∀x y. R2 x y ⟶ (∀a b. R2 a b ⟶ S' x a = T' y b)" and xsys: "tllist_all2 R1 R2 xs ys" and xs'ys': "tllist_all2 R1 R2 xs' ys'" shows "tllist_all2 S S' xs xs' = tllist_all2 T T' ys ys'" proof assume "tllist_all2 S S' xs xs'" with xsys xs'ys' show "tllist_all2 T T' ys ys'" proof(coinduction arbitrary: ys ys' xs xs') case (tllist_all2 ys ys' xs xs') thus ?case by cases (auto 4 4 simp add: tllist_all2_TCons1 tllist_all2_TCons2 tllist_all2_TNil1 tllist_all2_TNil2 dest: R1[rule_format] R2[rule_format]) qed next assume "tllist_all2 T T' ys ys'" with xsys xs'ys' show "tllist_all2 S S' xs xs'" proof(coinduction arbitrary: xs xs' ys ys') case (tllist_all2 xs xs' ys ys') thus ?case by cases(auto 4 4 simp add: tllist_all2_TCons1 tllist_all2_TCons2 tllist_all2_TNil1 tllist_all2_TNil2 dest: R1[rule_format] R2[rule_format]) qed qed
text ‹ Delete lifting rules for @{typ " 'a, 'b) tllist"}
because the parametricity rules take precedence over
most of the transfer rules. They can be restored by
including the bundle ‹tllist.lifting›Fo FG'.\epsilonG\<>FG ›
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.