(* Title: GPV_Bisim.thy
Author: Andreas Lochbihler, ETH Zurich *)
theory GPV_Bisim imports
GPV_Expectation begin
subsection‹Bisimulation for oracles›
text‹Bisimulation is a consequence of parametricity›
lemma exec_gpv_oracle_bisim': assumes *: "X s1 s2" and bisim: "∧s1 s2 x. X s1 s2 ==> rel_spmf (λ(a, s1') (b, s2'). a = b ∧ X s1' s2') (oracle1 s1 x) (oracle2 s2 x)" shows"rel_spmf (λ(a, s1') (b, s2'). a = b ∧ X s1' s2') (exec_gpv oracle1 gpv s1) (exec_gpv oracle2 gpv s2)" by(rule exec_gpv_parametric[of X "(=)""(=)", unfolded gpv.rel_eq rel_prod_conv, THEN rel_funD, THEN rel_funD, THEN rel_funD, OF rel_funI refl, OF rel_funI *])(simp add: bisim)
lemma exec_gpv_oracle_bisim: assumes *: "X s1 s2" and bisim: "∧s1 s2 x. X s1 s2 ==> rel_spmf (λ(a, s1') (b, s2'). a = b ∧ X s1' s2') (oracle1 s1 x) (oracle2 s2 x)" and R: "∧x s1' s2'. [ X s1' s2'; (x, s1') ∈ set_spmf (exec_gpv oracle1 gpv s1); (x, s2') ∈ set_spmf (exec_gpv oracle2 gpv s2) ]==> R (x, s1') (x, s2')" shows"rel_spmf R (exec_gpv oracle1 gpv s1) (exec_gpv oracle2 gpv s2)" apply(rule spmf_rel_mono_strong) apply(rule exec_gpv_oracle_bisim'[OF * bisim]) apply(auto dest: R) done
lemma run_gpv_oracle_bisim: assumes"X s1 s2" and"∧s1 s2 x. X s1 s2 ==> rel_spmf (λ(a, s1') (b, s2'). a = b ∧ X s1' s2') (oracle1 s1 x) (oracle2 s2 x)" shows"run_gpv oracle1 gpv s1 = run_gpv oracle2 gpv s2" using exec_gpv_oracle_bisim'[OF assms] by(fold spmf_rel_eq)(fastforce simp add: spmf_rel_map intro: rel_spmf_mono)
context fixes joint_oracle :: "('s1 × 's2) ==> 'a ==> (('b × 's1) × ('b × 's2)) spmf" and oracle1 :: "'s1 ==> 'a ==> ('b × 's1) spmf" and bad1 :: "'s1 ==> bool" and oracle2 :: "'s2 ==> 'a ==> ('b × 's2) spmf" and bad2 :: "'s2 ==> bool" begin
partial_function (spmf) exec_until_bad :: "('x, 'a, 'b) gpv ==> 's1 ==> 's2 ==> (('x× 's1) × ('x × 's2)) spmf" where "exec_until_bad gpv s1 s2 = (if bad1 s1 ∨ bad2 s2 then pair_spmf (exec_gpv oracle1 gpv s1) (exec_gpv oracle2 gpv s2) else bind_spmf (the_gpv gpv) (λgenerat. case generat of Pure x ==> return_spmf ((x, s1), (x, s2)) | IO out f ==> bind_spmf (joint_oracle (s1, s2) out) (λ((x, s1'), (y, s2')). if bad1 s1' ∨ bad2 s2' then pair_spmf (exec_gpv oracle1 (f x) s1') (exec_gpv oracle2 (f y) s2') else exec_until_bad (f x) s1' s2')))"
lemma exec_until_bad_fixp_induct [case_names adm bottom step]: assumes"ccpo.admissible (fun_lub lub_spmf) (fun_ord (ord_spmf (=))) (λf. P (λgpv s1 s2. f ((gpv, s1), s2)))" and"P (λ_ _ _. return_pmf None)" and"∧exec_until_bad'. P exec_until_bad' ==> P (λgpv s1 s2. if bad1 s1 ∨ bad2 s2 then pair_spmf (exec_gpv oracle1 gpv s1) (exec_gpv oracle2 gpv s2) else bind_spmf (the_gpv gpv) (λgenerat. case generat of Pure x ==> return_spmf ((x, s1), (x, s2)) | IO out f ==> bind_spmf (joint_oracle (s1, s2) out) (λ((x, s1'), (y, s2')). if bad1 s1' ∨ bad2 s2' then pair_spmf (exec_gpv oracle1 (f x) s1') (exec_gpv oracle2 (f y) s2') else exec_until_bad' (f x) s1' s2')))" shows"P exec_until_bad" using assms by(rule exec_until_bad.fixp_induct[unfolded curry_conv[abs_def]])
end
lemma exec_gpv_oracle_bisim_bad_plossless: fixes s1 :: 's1 and s2 :: 's2 and X :: "'s1 ==> 's2 ==> bool" and oracle1 :: "'s1 ==> 'a ==> ('b × 's1) spmf" and oracle2 :: "'s2 ==> 'a ==> ('b × 's2) spmf" assumes *: "if bad2 s2 then X_bad s1 s2 else X s1 s2" and bad: "bad1 s1 = bad2 s2" and bisim: "∧s1 s2 x. [ X s1 s2; x ∈ outs_II]==> rel_spmf (λ(a, s1') (b, s2'). bad1 s1' = bad2 s2' ∧ (if bad2 s2' then X_bad s1' s2' else a = b ∧ X s1' s2')) (oracle1 s1 x) (oracle2 s2 x)" and bad_sticky1: "∧s2. bad2 s2 ==> callee_invariant_on oracle1 (λs1. bad1 s1 ∧ X_bad s1 s2) I" and bad_sticky2: "∧s1. bad1 s1 ==> callee_invariant_on oracle2 (λs2. bad2 s2 ∧ X_bad s1 s2) I" and lossless1: "∧s1 x. [ bad1 s1; x ∈ outs_II]==> lossless_spmf (oracle1 s1 x)" and lossless2: "∧s2 x. [ bad2 s2; x ∈ outs_II]==> lossless_spmf (oracle2 s2 x)" and lossless: "plossless_gpv I gpv" and WT_oracle1: "∧s1. I⊨c oracle1 s1 √"(* stronger than the invariants above because unconditional *) and WT_oracle2: "∧s2. I⊨c oracle2 s2 √" and WT_gpv: "I⊨g gpv √" shows"rel_spmf (λ(a, s1') (b, s2'). bad1 s1' = bad2 s2' ∧ (if bad2 s2' then X_bad s1' s2' else a = b ∧ X s1' s2')) (exec_gpv oracle1 gpv s1) (exec_gpv oracle2 gpv s2)"
(is"rel_spmf ?R ?p ?q") proof - let ?R' = "λ(a, s1') (b, s2'). bad1 s1' = bad2 s2' ∧ (if bad2 s2' then X_bad s1' s2' else a = b ∧ X s1' s2')" from bisim have"∀s1 s2. ∀x ∈ outs_II. X s1 s2 ⟶ rel_spmf ?R' (oracle1 s1 x) (oracle2 s2 x)"by blast thenobtain joint_oracle where oracle1 [symmetric]: "∧s1 s2 x. [ X s1 s2; x ∈ outs_II]==> map_spmf fst (joint_oracle s1 s2 x) = oracle1 s1 x" and oracle2 [symmetric]: "∧s1 s2 x. [ X s1 s2; x ∈ outs_II]==> map_spmf snd (joint_oracle s1 s2 x) = oracle2 s2 x" and3 [rotated 2]: "∧s1 s2 x y y' s1' s2'. [ X s1 s2; x ∈ outs_II; ((y, s1'), (y', s2')) ∈ set_spmf (joint_oracle s1 s2 x) ] ==> bad1 s1' = bad2 s2' ∧ (if bad2 s2' then X_bad s1' s2' else y = y' ∧ X s1' s2')" apply atomize_elim apply(unfold rel_spmf_simps all_conj_distrib[symmetric] all_simps(6) imp_conjR[symmetric]) apply(subst choice_iff[symmetric] ex_simps(6))+ apply fastforce done let ?joint_oracle = "λ(s1, s2). joint_oracle s1 s2" let ?pq = "exec_until_bad ?joint_oracle oracle1 bad1 oracle2 bad2 gpv s1 s2"
have setD: "∧s1 s2 x y y' s1' s2'. [ X s1 s2; x ∈ outs_II; ((y, s1'), (y', s2')) ∈ set_spmf (joint_oracle s1 s2 x) ] ==> (y, s1') ∈ set_spmf (oracle1 s1 x) ∧ (y', s2') ∈ set_spmf (oracle2 s2 x)" unfolding oracle1 oracle2 by(auto intro: rev_image_eqI) show ?thesis proof show"map_spmf fst ?pq = exec_gpv oracle1 gpv s1" proof(rule spmf.leq_antisym) show"ord_spmf (=) (map_spmf fst ?pq) (exec_gpv oracle1 gpv s1)"using * bad WT_gpv lossless proof(induction arbitrary: s1 s2 gpv rule: exec_until_bad_fixp_induct) case adm show ?caseby simp case bottom show ?caseby simp case (step exec_until_bad') show ?case proof(cases "bad2 s2") case True thenhave"weight_spmf (exec_gpv oracle2 gpv s2) = 1" using callee_invariant_on.weight_exec_gpv[OF bad_sticky2 lossless2, of s1 gpv s2]
step.prems weight_spmf_le_1[of "exec_gpv oracle2 gpv s2"] by(simp add: pgen_lossless_gpv_def weight_gpv_def) thenshow ?thesis using True by simp next case False hence"¬ bad1 s1"using step.prems(2) by simp moreover { fix out c r1 s1' r2 s2' assume IO: "IO out c ∈ set_spmf (the_gpv gpv)" and joint: "((r1, s1'), (r2, s2')) ∈ set_spmf (joint_oracle s1 s2 out)" from step.prems(3) IO have out: "out ∈ outs_II"by(rule WT_gpvD) from setD[OF _ out joint] step.prems(1) False have1: "(r1, s1') ∈ set_spmf (oracle1 s1 out)" and2: "(r2, s2') ∈ set_spmf (oracle2 s2 out)"by simp_all hence r1: "r1 ∈ responses_II out"and r2: "r2 ∈ responses_II out" using WT_oracle1 WT_oracle2 out by(blast dest: WT_calleeD)+ have *: "plossless_gpv I (c r2)"using step.prems(4) IO r2 step.prems(3) by(rule plossless_gpv_ContD) thenhave"bad2 s2' ==> weight_spmf (exec_gpv oracle2 (c r2) s2') = 1" and"¬ bad2 s2' ==> ord_spmf (=) (map_spmf fst (exec_until_bad' (c r2) s1' s2')) (exec_gpv oracle1 (c r2) s1')" using callee_invariant_on.weight_exec_gpv[OF bad_sticky2 lossless2, of s1' "c r2" s2']
weight_spmf_le_1[of "exec_gpv oracle2 (c r2) s2'"] WT_gpv_ContD[OF step.prems(3) IO r2] 3[OF joint _ out] step.prems(1) False by(simp_all add: pgen_lossless_gpv_def weight_gpv_def step.IH) } ultimatelyshow ?thesis using False step.prems(1) by(rewrite in"ord_spmf _ _ 🍋" exec_gpv.simps)
(fastforce simp add: split_def bind_map_spmf map_spmf_bind_spmf oracle1 WT_gpv_OutD[OF step.prems(3)] intro!: ord_spmf_bind_reflI split!: generat.split dest: 3) qed qed show"ord_spmf (=) (exec_gpv oracle1 gpv s1) (map_spmf fst ?pq)"using * bad WT_gpv lossless proof(induction arbitrary: gpv s1 s2 rule: exec_gpv_fixp_induct_strong) case adm show ?caseby simp case bottom show ?caseby simp case (step exec_gpv') thenshow ?case proof(cases "bad2 s2") case True thenhave"weight_spmf (exec_gpv oracle2 gpv s2) = 1" using callee_invariant_on.weight_exec_gpv[OF bad_sticky2 lossless2, of s1 gpv s2]
step.prems weight_spmf_le_1[of "exec_gpv oracle2 gpv s2"] by(simp add: pgen_lossless_gpv_def weight_gpv_def) thenshow ?thesis using True by(rewrite exec_until_bad.simps; rewrite exec_gpv.simps)
(clarsimp intro!: ord_spmf_bind_reflI split!: generat.split simp add: step.hyps) next case False hence"¬ bad1 s1"using step.prems(2) by simp moreover { fix out c r1 s1' r2 s2' assume IO: "IO out c ∈ set_spmf (the_gpv gpv)" and joint: "((r1, s1'), (r2, s2')) ∈ set_spmf (joint_oracle s1 s2 out)" from step.prems(3) IO have out: "out ∈ outs_II"by(rule WT_gpvD) from setD[OF _ out joint] step.prems(1) False have1: "(r1, s1') ∈ set_spmf (oracle1 s1 out)" and2: "(r2, s2') ∈ set_spmf (oracle2 s2 out)"by simp_all hence r1: "r1 ∈ responses_II out"and r2: "r2 ∈ responses_II out" using WT_oracle1 WT_oracle2 out by(blast dest: WT_calleeD)+ have *: "plossless_gpv I (c r2)"using step.prems(4) IO r2 step.prems(3) by(rule plossless_gpv_ContD) thenhave"bad2 s2' ==> weight_spmf (exec_gpv oracle2 (c r2) s2') = 1" and"¬ bad2 s2' ==> ord_spmf (=) (exec_gpv' (c r2) s1') (map_spmf fst (exec_until_bad (λ(x, y). joint_oracle x y) oracle1 bad1 oracle2 bad2 (c r2) s1' s2'))" using callee_invariant_on.weight_exec_gpv[OF bad_sticky2 lossless2, of s1' "c r2" s2']
weight_spmf_le_1[of "exec_gpv oracle2 (c r2) s2'"] WT_gpv_ContD[OF step.prems(3) IO r2] 3[OF joint _ out] step.prems(1) False by(simp_all add: pgen_lossless_gpv_def weight_gpv_def step.IH) } ultimatelyshow ?thesis using False step.prems(1) by(rewrite exec_until_bad.simps)
(fastforce simp add: map_spmf_bind_spmf WT_gpv_OutD[OF step.prems(3)] oracle1 bind_map_spmf step.hyps intro!: ord_spmf_bind_reflI split!: generat.split dest: 3) qed qed qed
show"map_spmf snd ?pq = exec_gpv oracle2 gpv s2" proof(rule spmf.leq_antisym) show"ord_spmf (=) (map_spmf snd ?pq) (exec_gpv oracle2 gpv s2)"using * bad WT_gpv lossless proof(induction arbitrary: s1 s2 gpv rule: exec_until_bad_fixp_induct) case adm show ?caseby simp case bottom show ?caseby simp case (step exec_until_bad') show ?case proof(cases "bad2 s2") case True thenhave"weight_spmf (exec_gpv oracle1 gpv s1) = 1" using callee_invariant_on.weight_exec_gpv[OF bad_sticky1 lossless1, of s2 gpv s1]
step.prems weight_spmf_le_1[of "exec_gpv oracle1 gpv s1"] by(simp add: pgen_lossless_gpv_def weight_gpv_def) thenshow ?thesis using True by simp next case False hence"¬ bad1 s1"using step.prems(2) by simp moreover { fix out c r1 s1' r2 s2' assume IO: "IO out c ∈ set_spmf (the_gpv gpv)" and joint: "((r1, s1'), (r2, s2')) ∈ set_spmf (joint_oracle s1 s2 out)" from step.prems(3) IO have out: "out ∈ outs_II"by(rule WT_gpvD) from setD[OF _ out joint] step.prems(1) False have1: "(r1, s1') ∈ set_spmf (oracle1 s1 out)" and2: "(r2, s2') ∈ set_spmf (oracle2 s2 out)"by simp_all hence r1: "r1 ∈ responses_II out"and r2: "r2 ∈ responses_II out" using WT_oracle1 WT_oracle2 out by(blast dest: WT_calleeD)+ have *: "plossless_gpv I (c r1)"using step.prems(4) IO r1 step.prems(3) by(rule plossless_gpv_ContD) thenhave"bad2 s2' ==> weight_spmf (exec_gpv oracle1 (c r1) s1') = 1" and"¬ bad2 s2' ==> ord_spmf (=) (map_spmf snd (exec_until_bad' (c r2) s1' s2')) (exec_gpv oracle2 (c r2) s2')" using callee_invariant_on.weight_exec_gpv[OF bad_sticky1 lossless1, of s2' "c r1" s1']
weight_spmf_le_1[of "exec_gpv oracle1 (c r1) s1'"] WT_gpv_ContD[OF step.prems(3) IO r1] 3[OF joint _ out] step.prems(1) False by(simp_all add: pgen_lossless_gpv_def weight_gpv_def step.IH) } ultimatelyshow ?thesis using False step.prems(1) by(rewrite in"ord_spmf _ _ 🍋" exec_gpv.simps)
(fastforce simp add: split_def bind_map_spmf map_spmf_bind_spmf oracle2 WT_gpv_OutD[OF step.prems(3)] intro!: ord_spmf_bind_reflI split!: generat.split dest: 3) qed qed show"ord_spmf (=) (exec_gpv oracle2 gpv s2) (map_spmf snd ?pq)"using * bad WT_gpv lossless proof(induction arbitrary: gpv s1 s2 rule: exec_gpv_fixp_induct_strong) case adm show ?caseby simp case bottom show ?caseby simp case (step exec_gpv') thenshow ?case proof(cases "bad2 s2") case True thenhave"weight_spmf (exec_gpv oracle1 gpv s1) = 1" using callee_invariant_on.weight_exec_gpv[OF bad_sticky1 lossless1, of s2 gpv s1]
step.prems weight_spmf_le_1[of "exec_gpv oracle1 gpv s1"] by(simp add: pgen_lossless_gpv_def weight_gpv_def) thenshow ?thesis using True by(rewrite exec_until_bad.simps; subst (2) exec_gpv.simps)
(clarsimp intro!: ord_spmf_bind_reflI split!: generat.split simp add: step.hyps) next case False hence"¬ bad1 s1"using step.prems(2) by simp moreover { fix out c r1 s1' r2 s2' assume IO: "IO out c ∈ set_spmf (the_gpv gpv)" and joint: "((r1, s1'), (r2, s2')) ∈ set_spmf (joint_oracle s1 s2 out)" from step.prems(3) IO have out: "out ∈ outs_II"by(rule WT_gpvD) from setD[OF _ out joint] step.prems(1) False have1: "(r1, s1') ∈ set_spmf (oracle1 s1 out)" and2: "(r2, s2') ∈ set_spmf (oracle2 s2 out)"by simp_all hence r1: "r1 ∈ responses_II out"and r2: "r2 ∈ responses_II out" using WT_oracle1 WT_oracle2 out by(blast dest: WT_calleeD)+ have *: "plossless_gpv I (c r1)"using step.prems(4) IO r1 step.prems(3) by(rule plossless_gpv_ContD) thenhave"bad2 s2' ==> weight_spmf (exec_gpv oracle1 (c r1) s1') = 1" and"¬ bad2 s2' ==> ord_spmf (=) (exec_gpv' (c r2) s2') (map_spmf snd (exec_until_bad (λ(x, y). joint_oracle x y) oracle1 bad1 oracle2 bad2 (c r2) s1' s2'))" using callee_invariant_on.weight_exec_gpv[OF bad_sticky1 lossless1, of s2' "c r1" s1']
weight_spmf_le_1[of "exec_gpv oracle1 (c r1) s1'"] WT_gpv_ContD[OF step.prems(3) IO r1] 3[OF joint _ out] step.prems(1) False by(simp_all add: pgen_lossless_gpv_def step.IH weight_gpv_def) } ultimatelyshow ?thesis using False step.prems(1) by(rewrite exec_until_bad.simps)
(fastforce simp add: map_spmf_bind_spmf WT_gpv_OutD[OF step.prems(3)] oracle2 bind_map_spmf step.hyps intro!: ord_spmf_bind_reflI split!: generat.split dest: 3) qed qed qed
have"set_spmf ?pq ⊆ {(as1, bs2). ?R' as1 bs2}"using * bad WT_gpv proof(induction arbitrary: gpv s1 s2 rule: exec_until_bad_fixp_induct) case adm show ?caseby(intro cont_intro ccpo_class.admissible_leI) case bottom show ?caseby simp case step have switch: "set_spmf (exec_gpv oracle1 (c r1) s1') × set_spmf (exec_gpv oracle2 (c r2) s2') ⊆ {((a, s1'), b, s2'). bad1 s1' = bad2 s2' ∧ (if bad2 s2' then X_bad s1' s2' else a = b ∧ X s1' s2')}" if"¬ bad1 s1""I⊨g gpv √""¬ bad2 s2"and X: "X s1 s2"and out: "IO out c ∈ set_spmf (the_gpv gpv)" and joint: "((r1, s1'), (r2, s2')) ∈ set_spmf (joint_oracle s1 s2 out)" and bad2: "bad2 s2'" for out c r1 s1' r2 s2' proof(clarify; rule conjI) from step.prems(3) out have outs: "out ∈ outs_II"by(rule WT_gpv_OutD) from bad2 3[OF joint X this] have bad1: "bad1 s1' ∧ X_bad s1' s2'"by simp_all
have s1': "(r1, s1') ∈ set_spmf (oracle1 s1 out)"and s2': "(r2, s2') ∈ set_spmf (oracle2 s2 out)" using setD[OF X outs joint] by simp_all have resp: "r1 ∈ responses_II out"using WT_oracle1 s1' outs by(rule WT_calleeD) with step.prems(3) out have WT1: "I⊨g c r1 √"by(rule WT_gpv_ContD) have resp: "r2 ∈ responses_II out"using WT_oracle2 s2' outs by(rule WT_calleeD) with step.prems(3) out have WT2: "I⊨g c r2 √"by(rule WT_gpv_ContD)
lemma gpv_stop_parametric': notes [transfer_rule] = the_gpv_parametric' the_gpv_parametric' Done_parametric' corec_gpv_parametric' shows"(rel_gpv'' A C R ===> rel_gpv'' (rel_option A) C (rel_option R)) gpv_stop gpv_stop" unfolding gpv_stop_def by transfer_prover
lemma gpv_stop_parametric [transfer_rule]: shows"(rel_gpv A C ===> rel_gpv (rel_option A) C) gpv_stop gpv_stop" unfolding gpv_stop_def by transfer_prover
lemma gpv_stop_transfer: "(rel_gpv'' A B C ===> rel_gpv'' (pcr_Some A) B (pcr_Some C)) (λx. x) gpv_stop" apply(rule rel_funI)
subgoal for gpv gpv' apply(coinduction arbitrary: gpv gpv') apply(drule rel_gpv''D) apply(auto simp add: spmf_rel_map generat.rel_map rel_fun_def elim!: pcr_SomeE generat.rel_mono_strong rel_spmf_mono) done done
end
lemma gpv_stop_map' [simp]: "gpv_stop (map_gpv' f g h gpv) = map_gpv' (map_option f) g (map_option h) (gpv_stop gpv)" apply(coinduction arbitrary: gpv rule: gpv.coinduct_strong) apply(auto 43 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI generat.rel_refl_strong split!: option.split) done
lemma interaction_bound_gpv_stop [simp]: "interaction_bound consider (gpv_stop gpv) = interaction_bound consider gpv" proof(induction arbitrary: gpv rule: parallel_fixp_induct_strong_1_1[OF complete_lattice_partial_function_definitions complete_lattice_partial_function_definitions interaction_bound.mono interaction_bound.mono interaction_bound_def interaction_bound_def, case_names adm bottom step]) case adm show ?caseby simp case bottom show ?caseby simp next case (step interaction_bound' interaction_bound'') have"(SUP x. interaction_bound' (case x of None ==> Done None | Some input ==> gpv_stop (c input))) = (SUP input. interaction_bound'' (c input))" (is"?lhs = ?rhs"is"(SUP x. ?f x) = _") if"IO out c ∈ set_spmf (the_gpv gpv)"for out c proof - have"?lhs = sup (interaction_bound' (Done None)) (⊔x. ?f (Some x))" by (simp add: UNIV_option_conv image_comp) alsohave"interaction_bound' (Done None) = 0"using step.hyps(1)[of "Done None"] by simp alsohave"(⊔x. ?f (Some x)) = ?rhs"by (simp add: step.IH) finallyshow ?thesis by (simp add: bot_enat_def [symmetric]) qed thenshow ?case by (auto simp add: case_map_generat o_def image_comp cong del: generat.case_cong_weak if_weak_cong intro!: SUP_cong split: generat.split) qed
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.