(* Title: ISM/ISM.thy Id: $Id: ISM.thy,v 1.34 2003/09/12 16:13:02 dvo Exp $ Author: David von Oheimb License: (C) 2002 Siemens AG; any non-commercial use is granted *) header {* Interacting State Machines *} theory ISM imports Basis begin types ('p, 'm) msgss = "'p \ 'm list" --{* family of message lists,\\ i.e. i/o port contents or patterns @{typ 'm} indexed by port names @{typ 'p} *} (*<*) translations "(p, m) msgss" \ (type) "p \ m list" (*>*) types ('c, 'p, 'm, 's, 'd) trans = "(('p,'m) msgss \ 's) \ ('c \ 'd) \ (('p,'m) msgss \ 's)" --{* input pattern, local pre-state, command, output pattern, post-state *} consts "input" :: "('c, 'p, 'm, 's, 'd) trans \ ('p, 'm) msgss" "output" :: "('c, 'p, 'm, 's, 'd) trans \ ('p, 'm) msgss" "cmd" :: "('c, 'p, 'm, 's, 'd) trans \ 'c" "dom_of" :: "('c, 'p, 'm, 's, 'd) trans \ 'd" "lstate" :: "('c, 'p, 'm, 's, 'd) trans \ 's" "lstate'":: "('c, 'p, 'm, 's, 'd) trans \ 's" defs input_def : " input \ fst \ fst" output_def : "output \ fst \ snd \ snd" cmd_def : "cmd \ fst \ fst \ snd" dom_of_def : "dom_of \ snd \ fst \ snd" lstate_def : "lstate \ snd \ fst" lstate'_def: "lstate' \ snd \ snd \ snd" (*<*) declare input_def [simp] lstate_def [simp] cmd_def [simp] output_def [simp] lstate'_def [simp] dom_of_def [simp] (*>*) record ('c, 'p, 'm, 's, 'd) "ism" = "inputs" :: "'p set" --{* input port names *} "outputs" :: "'p set" --{* output port names *} "init" :: "'s" --{* initial local state *} "trans" :: "(('c, 'p, 'm, 's, 'd) trans) set" --{* transitions *} (*<*) lemma surjective_ism: "a = \inputs = inputs a, outputs = outputs a, init = init a, trans = trans a\" by simp (*>*) constdefs map_ism ::"('s \ 't) \ ('c, 'p, 'm, 's, 'd) ism \ ('c, 'p, 'm, 't, 'd) ism" "map_ism f a \ \inputs = inputs a, outputs = outputs a, init = f (init a), trans = (upd_fst (upd_snd f) \ upd_snd (upd_snd (upd_snd f))) ` trans a\" (*<*) lemma map_ism_conv [simp]: "\tr. map_ism f \inputs = inp, outputs = out, init = ( ini), trans = tr\ = \inputs = inp, outputs = out, init = (f ini), trans = (\((p,s),(c,d),(p',s')). ((p,f s),(c,d),(p',f s'))) ` tr\" by (auto simp add: map_ism_def upd_snd_def upd_fst_def del: image_eqI intro!: image_eqI) (*>*) subsection "Renaming" constdefs ren_trans :: "'p \ 'p \ ('c, 'p, 'm, 's, 'd) trans \ ('c, 'p, 'm, 's, 'd) trans" "ren_trans pn pn' \ \((p,s),(c,d),(p',s')). ((lmap_subst pn pn' p ,s ),(c,d), (lmap_subst pn pn' p',s'))" subst_elem :: "'a \ 'a \ 'a set \ 'a set" "subst_elem x y A \ if x \ A then A - {x} \ {y} else A" ren_conn :: "'p \ 'p \ ('c, 'p, 'm, 's, 'd) ism \ ('c, 'p, 'm, 's, 'd) ism" "ren_conn pn pn' a \ \inputs = subst_elem pn pn' ( inputs a), outputs = subst_elem pn pn' (outputs a), init = init a, trans = ren_trans pn pn' ` trans a\" subsection "Well-formedness" consts ipns :: "('c, 'p, 'm, 's, 'd) ism \ 'p set" --{* potential input port names *} opns :: "('c, 'p, 'm, 's, 'd) ism \ 'p set" --{* potential output port names *} defs ipns_def : "ipns a \ \lmap_dom`( input`trans a)" opns_def : "opns a \ \lmap_dom`(output`trans a)" constdefs wf_ism :: "('c, 'p, 'm, 's, 'd) ism \ bool" "wf_ism a \ ipns a \ inputs a \ opns a \ outputs a" --{* input and output may overlap ($\leadsto$ direct feedback) *} (*<*) lemma wf_ismI: "\\p s c d p' s' pn. \((p, s), (c, d), (p', s')) \ t; p pn \ []\ \ pn \ Is; \p s c d p' s' pn. \((p, s), (c, d), (p', s')) \ t; p' pn \ []\ \ pn \ Os\ \ wf_ism \inputs = Is, outputs = Os, init = i, trans = t\" by (auto simp add: wf_ism_def ipns_def opns_def) lemma wf_ism_trans_in_inputs: "\wf_ism a; ((p, s), c_d_p'_s') \ trans a\ \ lmap_dom p \ inputs a" apply (clarsimp simp add: wf_ism_def ipns_def UN_subset_iff) apply (erule rev_ballE, fast) apply (auto simp add: lmap_dom_def) done lemma wf_ism_trans_in_outputs: "\wf_ism a; (p_s, c_d, (p',s')) \ trans a\ \ lmap_dom p' \ outputs a" apply (clarsimp simp add: wf_ism_def opns_def UN_subset_iff) apply (erule rev_ballE, fast) apply (auto simp add: lmap_dom_def) done (*>*) text {*\pagebreak*} subsection "Runs" consts runs :: "('c, 'p, 'm, 's, 'd) ism \ ('s list) set" inductive "runs a" intros --{* ignoring commands and global state! *} --{* for technical reasons, traces are built from right to left *} "init": "[init a] \ runs a" "step": "\s#ss \ runs a; ((p,s),(c,d),(p',s')) \ trans a \ \ s'#s#ss \ runs a" -- {* Communication with the environment is unrestricted ($\leadsto$ arbitrary input). *} (*<*) inductive_cases runs_elim_cases: "ss \ runs a" ML_setup {* bind_thm ("runs_step2", rearrange_prems [1,0] (thm "runs.step")) *} (*>*) types ('c, 'p, 'm, 's, 'd) truns = "((('c, 'p, 'm, 's, 'd) trans) list) set" consts truns :: "('c, 'p, 'm, 's, 'd) ism \ ('c, 'p, 'm, 's, 'd) truns" inductive "truns a" intros --{* for technical reasons, traces are built from right to left *} "init": "((p,init a),c,c2) \ trans a \ [((p,init a),c,c2)] \ truns a" "step": "\(c0,c',(p1,s1))#ts \ truns a; ((p1,s1),c,c2) \ trans a\ \ ((p1,s1),c,c2)#(c0,c',(p1,s1))#ts \ truns a" lemma truns2trans [rule_format]: "ts \ truns a \ \t \ set ts. t \ trans a" (*<*) by (erule truns.induct, auto) (*>*) constdefs truns2runs :: "(('c, 'p, 'm, 's, 'd) trans) list \ 's list" "truns2runs ts \ lstate'(hd ts)#map lstate ts" lemma truns2runs [rule_format]: "ts \ truns a \ truns2runs ts \ runs a" (*<*) by (erule truns.induct, auto simp add: truns2runs_def intro: runs.intros) (*>*) lemma lstate_in_truns2runs: "t \ set ts \ lstate t \ set (truns2runs ts)" (*<*) by (simp add: truns2runs_def) (*>*) subsection "Reachability and invariants" constdefs reach :: "('c, 'p, 'm, 's, 'd) ism \ 's set" "reach a \ \set`runs a" inv :: "('c, 'p, 'm, 's, 'd) ism \ ('s \ bool) \ bool" "inv a P \ \s \ reach a. P s" lemma invI: "\P (init a); \x p s c d p' s'. \s \ reach a; P s; ((p,s),(c,d),(p',s')) \ trans a\ \ P s' \ \ inv a P"; (*<*) apply (unfold inv_def reach_def) apply safe apply (subgoal_tac "Ball (set x) P") apply blast apply (erule runs.induct) apply simp apply auto apply (subgoal_tac "sa \ set (sa # ss) \ P sa") apply blast apply simp done (*>*) lemma invE: "\inv a P; s \ reach a\ \ P s" (*<*) by (auto simp: inv_def reach_def split_paired_all) (*>*) lemma runs_reach: "\r \ runs a; s \ set r\ \ s \ reach a" (*<*) by (auto simp add: reach_def) lemma truns_lstate_reach: "\ts \ truns a; ((p, s), c_p'_s') \ set ts\ \ s \ reach a" apply (erule truns2runs [THEN runs_reach]) apply (drule lstate_in_truns2runs) apply simp done (*>*) subsection "Parallel composition" types ('i, 'a) family = "('i \ 'a) \ 'i set" consts all_inputs :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ 'p set" all_outputs :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ 'p set" closed :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ bool" text {*\pagebreak*} defs all_inputs_def : "all_inputs \ \(A,I). \( inputs \ A)`I" all_outputs_def: "all_outputs \ \(A,I). \(outputs \ A)`I" closed_def : "closed A \ all_inputs A = all_outputs A" (*<*) lemma inputs_in_all_inputs: "i \ snd AI \ inputs (fst AI i) \ all_inputs AI" by (auto simp add: all_inputs_def) lemma outputs_in_all_outputs: "i \ snd AI \ outputs (fst AI i) \ all_outputs AI" by (auto simp add: all_outputs_def ran_def) (*>*) constdefs --{* (static) well-formedness: inputs of peers should not overlap *} wf_comp :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ bool" "wf_comp \ \(A,I). \i\I. \j\I. i \ j \ inputs (A i) \ inputs (A j) = {}" --{* outputs of peers may overlap ($\leadsto$ nondeterministic interleaving) *} wf_isms :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ bool" "wf_isms \ \(A,I). \i\I. wf_ism (A i)" (*<*) lemma wf_ismsI: "\AI. \\i. i\snd AI \ wf_ism (fst AI i)\ \ wf_isms AI" by (auto simp add: wf_isms_def) lemma wf_ismsD: "\wf_isms AI; i\snd AI\ \ wf_ism (fst AI i)" by (auto simp add: wf_isms_def) (*>*) types ('p, 'm, 's) conf = "('p, 'm) msgss \ 's" --{* input buffer state and local state *} (*<*) translations "(p, m, s) conf" \ (type) "(p, m) msgss \ s" (*>*) consts comp_trans :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ (('c, 'p, 'm, ('p, 'm, 'i \ 's) conf, 'd) trans) set" inductive "comp_trans AI" intros --{* including feedback *} step: "\i \ snd AI; ((p1, s1), (c, d), (p2, s2)) \ trans (fst AI i)\ \ ((p1[\](-all_outputs AI), (p1[\](all_outputs AI) .@. b, s(i:=s1))), (c, d), (p2[\](-all_inputs AI), (b .@. p2[\](all_inputs AI), s(i:=s2)))) \ comp_trans AI" (*<*) inductive_cases comp_trans_elim_cases: "t \ comp_trans A" (*>*) constdefs ISM_comp :: "('i, ('c, 'p, 'm, 's, 'd) ism) family \ ('c, 'p, 'm, ('p, 'm, 'i \ 's) conf, 'd) ism" "ISM_comp AI \ \inputs = all_inputs AI - all_outputs AI, \outputs = all_outputs AI - all_inputs AI, \init = (\, init \ fst AI), \trans = comp_trans AI\" (* lemma runs_comp_buffers_in_all_inputs_outputs [rule_format]: --{* unused *} "\r \ runs (ISM_comp AI); wf_isms AI\ \ \bs s' cs. r = (bs,s')#cs \ lmap_dom bs \ all_inputs AI \ all_outputs AI" *)(*<*) (*apply (erule runs.induct) apply (simp_all add: ISM_comp_def del: K_Nil_def2) apply (clarsimp elim!: comp_trans_elim_cases) apply (drule wf_ismsD, simp) apply (drule wf_ism_trans_in_outputs, simp) apply (auto simp add: restrict_lmap_def split add: split_if_asm) apply (simp only: lmap_dom_def2 [symmetric]) apply (fast dest: outputs_in_all_outputs) done *)(*>*) lemma runs_closed_comp_past_induct [rule_format]: "\r \ runs (ISM_comp AI); closed AI; wf_isms AI; P \ (init \ fst AI) []; \a p1 p2 cs i b c d s s1 s2. \lmap_dom p1 \ all_outputs AI; (p1 .@. b, s(i:=s1)) # cs \ runs (ISM_comp AI); P (p1 .@. b) (s(i:=s1)) cs; i \ snd AI; ((p1, s1), (c, d), (p2, s2)) \ trans (fst AI i) \ \ P (b .@. p2) (s(i:=s2)) ((p1 .@. b, s(i:=s1)) # cs) \ \ \bs s cs. r = (bs,s)#cs \ P bs s cs" (*<*) apply (erule runs.induct) apply (simp_all add: ISM_comp_def closed_def) apply (simp add: K_Nil_def) apply (clarsimp elim!: comp_trans_elim_cases) apply (drule wf_ismsD, simp) apply (frule (1) wf_ism_trans_in_inputs) apply (drule (1) wf_ism_trans_in_outputs) apply (subgoal_tac "p1[\]all_outputs AI = p1", simp del: restrict_lmap_dom_eq) apply (subgoal_tac "p2[\]all_outputs AI = p2",(*all_inputs!*)simp (no_asm_simp)) apply (simp) apply (simp) apply (erule subset_trans) apply (erule outputs_in_all_outputs) apply (simp) apply (erule subset_trans) apply (erule inputs_in_all_inputs [THEN subset_trans]) apply blast done (*>*) lemma runs_closed_comp_all_imp_all_induct: "\cs \ runs (ISM_comp AI); closed AI; wf_isms AI; P (\, init \ fst AI) \ Q (\, init \ fst AI); \a p1 p2 cs i b c d s s1 s2. \lmap_dom p1 \ all_outputs AI; (p1 .@. b, s(i:=s1)) # cs \ runs (ISM_comp AI); i \ snd AI; ((p1, s1), (c, d), (p2, s2)) \ trans (fst AI i); Ball (set cs) Q; Q (p1 .@. b, s(i:=s1)); Ball (set cs) P; P (p1 .@. b, s(i:=s1)); P (b .@. p2, s(i:=s2)) \ \ Q (b .@. p2, s(i:=s2)) \ \ (\c\set cs. P c) \ (\c\set cs. Q c)" (*<*) apply (erule runs.induct) apply (simp_all add: ISM_comp_def closed_def) apply (clarsimp elim!: comp_trans_elim_cases) apply (drule wf_ismsD, simp) apply (frule (1) wf_ism_trans_in_inputs) apply (drule (1) wf_ism_trans_in_outputs) apply (subgoal_tac "p1[\]all_outputs AI = p1", simp del: restrict_lmap_dom_eq) apply (subgoal_tac "p2[\]all_outputs AI = p2",(*all_inputs!*) simp del: restrict_lmap_dom_eq) apply (simp) apply (simp) apply (erule subset_trans) apply (erule outputs_in_all_outputs) apply (simp) apply (erule subset_trans) apply (erule inputs_in_all_inputs [THEN subset_trans]) apply blast done (*>*) text {*\pagebreak*} subsection "Composite runs" types ('i, 'c, 'g) g_trans = "'i \ ('g \ 'c \ 'g) set" --{* index, input and output patterns, global pre-state, command, post-state *} consts comp_runs:: "('g \ ('i, ('c, 'p, 'm, 's, 'd) ism) family) \ 'g \ ('i, 'c, 'g) g_trans \ ((('p, 'm, 'g \ ('i \ 's)) conf) list) set" inductive "comp_runs AIs g0 g_trans" intros --{* including feedback *} --{* for technical reasons, traces are built from right to left *} "init": "[(\, (g0,init \ fst (AIs g0)))] \ comp_runs AIs g0 g_trans" "step": "\(p1 .@. b, (g1, s(i:=s1)))#cs \ comp_runs AIs g0 g_trans; i \ snd (AIs g1); a = fst (AIs g1) i; ((p1, s1), (c, d), (p2, s2)) \ trans a; lmap_dom p1 \ inputs a \ all_outputs (AIs g1); lmap_dom p2 \ outputs a \ all_inputs (AIs g1); (g1, c, g2) \ g_trans i \ \ (b .@. p2, (g2, s(i:=s2)))# (p1.@. b , (g1, s(i:=s1)))#cs \ comp_runs AIs g0 g_trans" -- {* Changes to global state take effect after output has been performed. *} -- {* Here the environment is assumed to be part of the ISM system;\\\hspace*{2.5ex} communication with the environment may be modeled with suitable ISMs. *} (*<*) inductive_cases comp_runs_elim_cases: "cs \ comp_runs AIs g0 g_trans" (*>*) lemma comp_runs_global_induct: "cs \ comp_runs AIs ginit g_trans \ P (AIs ginit) \ (\g1 c g2 i. \(g1, c, g2) \ g_trans i; i \ snd (AIs g1); P (AIs g1)\ \ P (AIs g2) ) \ \(b,g,s) \ set cs. P (AIs g)" (*<*) by (erule comp_runs.induct, auto) (*>*) (* lemma past_in_comp_runs [rule_format]: "cs' \ comp_runs AIs g0 g_trans \ \c. c \ set cs' \ (\cs. cs' >= c#cs \ c#cs \ comp_runs AIs g0 g_trans)" ( *<* ) apply (erule comp_runs.induct) apply safe apply (force intro: comp_runs.init) apply (drule set_ConsD, safe) apply (blast intro: comp_runs.step) apply (fast intro: postfix_ConsI) done ( *> *) lemma comp_runs_past_induct [rule_format]: "\r \ comp_runs AIs g0 g_trans; P \ g0 (init \ fst (AIs g0)) []; \a p1 p2 cs i b c d s g1 s1 g2 s2. \(p1 .@. b, (g1, s(i:=s1))) # cs \ comp_runs AIs g0 g_trans; P (p1 .@. b) g1 (s(i:=s1)) cs; i \ snd (AIs g1); ((p1, s1), (c, d), (p2, s2)) \ trans (fst (AIs g1) i); (g1, c, g2) \ g_trans i \ \ P (b .@. p2) g2 (s(i:=s2)) ((p1 .@. b, (g1, s(i:=s1))) # cs) \ \ \bs g s cs. r = (bs,(g,s))#cs \ P bs g s cs" (*<*) apply (erule comp_runs.induct) apply (simp_all del: K_Nil_def2) done (*>*) lemma comp_runs_all_imp_all_induct: "\cs \ comp_runs AIs g0 g_trans; P (\, g0, init \ fst (AIs g0)) \ Q (\, g0, init \ fst (AIs g0)); \a p1 p2 cs i b c d s g1 s1 g2 s2. \(p1 .@. b, g1, s(i:=s1)) # cs \ comp_runs AIs g0 g_trans; i \ snd (AIs g1); ((p1, s1), (c, d), (p2, s2)) \ trans (fst (AIs g1) i); (g1, c, g2) \ g_trans i; Ball (set cs) Q; Q (p1 .@. b, g1, s(i:=s1)); Ball (set cs) P; P (p1 .@. b, g1, s(i:=s1)); P (b .@. p2, g2, s(i:=s2)) \ \ Q (b .@. p2, g2, s(i:=s2)) \ \ (\c\set cs. P c) \ (\c\set cs. Q c)" (*<*) apply (erule comp_runs.induct) apply (simp_all) done (*>*) (*<*) lemma comp_runs_g_trans_idD: "(p, g, s) # cs \ comp_runs AIs g0 (\i. {u. \g c. u = (g, c, g)}) \ g = g0" by (drule_tac P = "\bs g s cs. g = g0" in comp_runs_past_induct, auto) (*>*) theorem closed_comp_runs_comp: "\wf_isms (AIs g); closed (AIs g)\ \ runs (ISM_comp (AIs g)) = map (\(b,g,s). (b,s)) ` comp_runs AIs g (\i. {(g,c,g')| g c g'. g = g'})" (*<*) apply (auto simp: ISM_comp_def) apply (erule runs.induct) apply simp_all apply (rule image_eqI) apply (rule_tac [2] comp_runs.init) apply simp apply (tactic {* split_all_tac 1*}, rename_tac b s b' s' cs) apply (erule comp_trans_elim_cases) apply (clarsimp) apply (drule wf_ismsD, simp) apply (frule (1) wf_ism_trans_in_inputs) apply (drule (1) wf_ism_trans_in_outputs) apply (frule comp_runs_g_trans_idD, clarify) apply (rule image_eqI) prefer 2 apply (erule (1) comp_runs.step, rule refl) prefer 5 apply (force) apply (subgoal_tac "p1[\]all_outputs (AIs g) = p1") apply (subgoal_tac "p2[\]all_inputs (AIs g) = p2") apply (simp (no_asm_simp)) apply (simp) apply (erule subset_trans) apply (simp add: closed_def) apply (erule outputs_in_all_outputs) apply (simp add: closed_def) apply (drule sym) apply (simp, erule subset_trans) apply (erule inputs_in_all_inputs) apply force apply force apply fast apply (erule_tac V = "closed (AIs g)" in thin_rl) apply (erule comp_runs.induct, simp_all) apply (rule ssubst [OF arg_cong], rule_tac [2] runs.init) back apply (simp add: K_Nil_def o_def) apply (rule runs.step, assumption) apply (frule comp_runs_g_trans_idD) apply clarsimp apply (subgoal_tac "p1[\]all_outputs (AIs g) = p1") apply (rotate_tac -1, erule subst) apply (subgoal_tac "p2[\]all_inputs (AIs g) = p2") apply (rotate_tac -1, erule subst) apply (drule (2) comp_trans.step) apply auto done (*>*) end