diff --git a/thys/Extended_Finite_State_Machine_Inference/Code_Generation.thy b/thys/Extended_Finite_State_Machine_Inference/Code_Generation.thy --- a/thys/Extended_Finite_State_Machine_Inference/Code_Generation.thy +++ b/thys/Extended_Finite_State_Machine_Inference/Code_Generation.thy @@ -1,447 +1,445 @@ section\Code Generation\ text\This theory is used to generate an executable Scala implementation of the inference tool which can be used to infer real EFSMs from real traces. Certain functions are replaced with native implementations. These can be found at \url{https://github.com/jmafoster1/efsm-inference/blob/master/inference-tool/src/main/scala/inference/Dirties.scala}.\ theory Code_Generation imports "HOL-Library.Code_Target_Numeral" Inference SelectionStrategies "heuristics/Store_Reuse_Subsumption" "heuristics/Increment_Reset" "heuristics/Same_Register" "heuristics/Distinguishing_Guards" "heuristics/PTA_Generalisation" "heuristics/Weak_Subsumption" "heuristics/Least_Upper_Bound" EFSM_Dot "code-targets/Code_Target_FSet" "code-targets/Code_Target_Set" "code-targets/Code_Target_List" efsm2sal begin declare One_nat_def [simp del] (* Let's use the native operators for booleans and pairs *) code_printing constant HOL.conj \ (Scala) "_ && _" | constant HOL.disj \ (Scala) "_ || _" | constant "HOL.equal :: bool \ bool \ bool" \ (Scala) infix 4 "==" | constant "fst" \ (Scala) "_.'_1" | constant "snd" \ (Scala) "_.'_2"| constant "(1::nat)" \ (Scala) "Nat.Nata((1))" (* This gives us a speedup as we don't need to check that a register is undefined in the initial state if there is no way to get back there. This is true by definition. *) definition "initially_undefined_context_check_full = initially_undefined_context_check" (* This gives us a speedup because we can check this before we have to call out to z3 *) fun mutex :: "'a gexp \ 'a gexp \ bool" where "mutex (Eq (V v) (L l)) (Eq (V v') (L l')) = (if v = v' then l \ l' else False)" | "mutex (gexp.In v l) (Eq (V v') (L l')) = (v = v' \ l' \ set l)" | "mutex (Eq (V v') (L l')) (gexp.In v l) = (v = v' \ l' \ set l)" | "mutex (gexp.In v l) (gexp.In v' l') = (v = v' \ set l \ set l' = {})" | "mutex _ _ = False" lemma mutex_not_gval: "mutex x y \ gval (gAnd y x) s \ true" unfolding gAnd_def apply (induct x y rule: mutex.induct) apply simp_all apply (case_tac "s v") apply (case_tac "s v'") apply simp apply simp apply (case_tac "s v") apply (case_tac "s v'") apply simp apply simp apply (metis maybe_negate_true maybe_or_false trilean.distinct(1) value_eq.simps(3)) apply (case_tac "s v") apply (case_tac "s v'") apply simp apply simp apply simp - apply (case_tac "s v") - apply (case_tac "s v'") - apply simp + apply (case_tac "s v'") + apply simp apply simp - apply simp - apply (case_tac "s v") + apply (case_tac "s v") apply (case_tac "s v'") by auto (* (\(i, s1) \ set (get_ins (Guard t1)). \(i', s2) \ set (get_ins (Guard t2)). i = i' \ \ (set s2) \ (set s1) \ restricted_once (I i) (Guard t2)) *) definition choice_cases :: "transition \ transition \ bool" where "choice_cases t1 t2 = ( if \(x, y) \ set (List.product (Guards t1) (Guards t2)). mutex x y then False else if Guards t1 = Guards t2 then satisfiable (fold gAnd (rev (Guards t1)) (gexp.Bc True)) else satisfiable ((fold gAnd (rev (Guards t1@Guards t2)) (gexp.Bc True))) )" lemma existing_mutex_not_true: "\x\set G. \y\set G. mutex x y \ \ apply_guards G s" apply clarify apply (simp add: apply_guards_rearrange) apply (case_tac "y \ set (x#G)") defer apply simp apply (simp only: apply_guards_rearrange) apply simp apply (simp only: apply_guards_double_cons) using mutex_not_gval by auto lemma [code]: "choice t t' = choice_cases t t'" apply (simp only: choice_alt choice_cases_def) apply (case_tac "\x\set (map (\(x, y). mutex x y) (List.product (Guards t) (Guards t'))). x") apply (simp add: choice_alt_def) apply (metis existing_mutex_not_true Un_iff set_append) apply (case_tac "Guards t = Guards t'") apply (simp add: choice_alt_def apply_guards_append) apply (simp add: fold_apply_guards rev_apply_guards satisfiable_def) apply (simp add: choice_alt_def satisfiable_def) by (metis foldr_append foldr_apply_guards foldr_conv_fold) fun guardMatch_code :: "vname gexp list \ vname gexp list \ bool" where "guardMatch_code [(gexp.Eq (V (vname.I i)) (L (Num n)))] [(gexp.Eq (V (vname.I i')) (L (Num n')))] = (i = 0 \ i' = 0)" | "guardMatch_code _ _ = False" lemma [code]: "guardMatch t1 t2 = guardMatch_code (Guards t1) (Guards t2)" apply (simp add: guardMatch_def) using guardMatch_code.elims(2) by fastforce fun outputMatch_code :: "output_function list \ output_function list \ bool" where "outputMatch_code [L (Num n)] [L (Num n')] = True" | "outputMatch_code _ _ = False" lemma [code]: "outputMatch t1 t2 = outputMatch_code (Outputs t1) (Outputs t2)" by (metis outputMatch_code.elims(2) outputMatch_code.simps(1) outputMatch_def) fun always_different_outputs :: "vname aexp list \ vname aexp list \ bool" where "always_different_outputs [] [] = False" | "always_different_outputs [] (a#_) = True" | "always_different_outputs (a#_) [] = True" | "always_different_outputs ((L v)#t) ((L v')#t') = (if v = v' then always_different_outputs t t' else True)" | "always_different_outputs (h#t) (h'#t') = always_different_outputs t t'" lemma always_different_outputs_outputs_never_equal: "always_different_outputs O1 O2 \ apply_outputs O1 s \ apply_outputs O2 s" apply(induct O1 O2 rule: always_different_outputs.induct) by (simp_all add: apply_outputs_def) fun tests_input_equality :: "nat \ vname gexp \ bool" where "tests_input_equality i (gexp.Eq (V (vname.I i')) (L _)) = (i = i')" | "tests_input_equality _ _ = False" fun no_illegal_updates_code :: "update_function list \ nat \ bool" where "no_illegal_updates_code [] _ = True" | "no_illegal_updates_code ((r', u)#t) r = (r \ r' \ no_illegal_updates_code t r)" lemma no_illegal_updates_code_aux: "(\u\set u. fst u \ r) = no_illegal_updates_code u r" proof(induct u) case Nil then show ?case by simp next case (Cons a u) then show ?case apply (cases a) apply (case_tac aa) by auto qed lemma no_illegal_updates_code [code]: "no_illegal_updates t r = no_illegal_updates_code (Updates t) r" by (simp add: no_illegal_updates_def no_illegal_updates_code_aux) fun input_updates_register_aux :: "update_function list \ nat option" where "input_updates_register_aux ((n, V (vname.I n'))#_) = Some n'" | "input_updates_register_aux (h#t) = input_updates_register_aux t" | "input_updates_register_aux [] = None" definition input_updates_register :: "transition_matrix \ (nat \ String.literal)" where "input_updates_register e = ( case fthe_elem (ffilter (\(_, t). input_updates_register_aux (Updates t) \ None) e) of (_, t) \ (case input_updates_register_aux (Updates t) of Some n \ (n, Label t) ) )" definition "dirty_directly_subsumes e1 e2 s1 s2 t1 t2 = (if t1 = t2 then True else directly_subsumes e1 e2 s1 s2 t1 t2)" definition "always_different_outputs_direct_subsumption m1 m2 s s' t2 = ((\p c1 c. obtains s c1 m1 0 <> p \ obtains s' c m2 0 <> p \ (\i. can_take_transition t2 i c)))" lemma always_different_outputs_direct_subsumption: "always_different_outputs (Outputs t1) (Outputs t2) \ always_different_outputs_direct_subsumption m1 m2 s s' t2 \ \ directly_subsumes m1 m2 s s' t1 t2" apply (simp add: directly_subsumes_def always_different_outputs_direct_subsumption_def) apply (erule exE) apply (erule conjE) apply (erule exE)+ apply (rule_tac x=c1 in exI) apply (rule_tac x=c in exI) by (metis always_different_outputs_outputs_never_equal bad_outputs) definition negate :: "'a gexp list \ 'a gexp" where "negate g = gNot (fold gAnd g (Bc True))" lemma gval_negate_cons: "gval (negate (a # G)) s = gval (gNot a) s \? gval (negate G) s" apply (simp only: negate_def gval_gNot gval_fold_equiv_gval_foldr) by (simp only: foldr.simps comp_def gval_gAnd de_morgans_2) lemma negate_true_guard: "(gval (negate G) s = true) = (gval (fold gAnd G (Bc True)) s = false)" by (metis (no_types, lifting) gval_gNot maybe_double_negation maybe_not.simps(1) negate_def) lemma gval_negate_not_invalid: "(gval (negate gs) (join_ir i ra) \ invalid) = (gval (fold gAnd gs (Bc True)) (join_ir i ra) \ invalid)" by (metis gval_gNot maybe_not_invalid negate_def) definition "dirty_always_different_outputs_direct_subsumption = always_different_outputs_direct_subsumption" lemma [code]: "always_different_outputs_direct_subsumption m1 m2 s s' t = ( if Guards t = [] then recognises_and_visits_both m1 m2 s s' else dirty_always_different_outputs_direct_subsumption m1 m2 s s' t )" apply (simp add: always_different_outputs_direct_subsumption_def) apply (simp add: recognises_and_visits_both_def) apply safe apply (rule_tac x=p in exI) apply auto[1] using can_take_transition_empty_guard apply blast apply (metis always_different_outputs_direct_subsumption_def dirty_always_different_outputs_direct_subsumption_def) by (simp add: always_different_outputs_direct_subsumption_def dirty_always_different_outputs_direct_subsumption_def) definition guard_subset_subsumption :: "transition \ transition \ bool" where "guard_subset_subsumption t1 t2 = (Label t1 = Label t2 \ Arity t1 = Arity t2 \ set (Guards t1) \ set (Guards t2) \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2)" lemma guard_subset_subsumption: "guard_subset_subsumption t1 t2 \ directly_subsumes a b s s' t1 t2" apply (rule subsumes_in_all_contexts_directly_subsumes) apply (simp add: subsumes_def guard_subset_subsumption_def) by (metis can_take_def can_take_transition_def can_take_subset) definition "guard_subset_eq_outputs_updates t1 t2 = (Label t1 = Label t2 \ Arity t1 = Arity t2 \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ set (Guards t2) \ set (Guards t1))" definition "guard_superset_eq_outputs_updates t1 t2 = (Label t1 = Label t2 \ Arity t1 = Arity t2 \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ set (Guards t2) \ set (Guards t1))" definition is_generalisation_of :: "transition \ transition \ nat \ nat \ bool" where "is_generalisation_of t' t i r = ( t' = remove_guard_add_update t i r \ i < Arity t \ r \ set (map fst (Updates t)) \ (length (filter (tests_input_equality i) (Guards t)) \ 1) )" lemma tests_input_equality: "(\v. gexp.Eq (V (vname.I xb)) (L v) \ set G) = (1 \ length (filter (tests_input_equality xb) G))" proof(induct G) case Nil then show ?case by simp next case (Cons a G) then show ?case apply (cases a) apply simp apply simp apply (case_tac x21) apply simp apply simp apply (case_tac "x2 = vname.I xb") apply simp defer defer apply simp+ apply (case_tac x22) apply auto[1] apply simp+ apply (case_tac x22) using tests_input_equality.elims(2) by auto qed lemma [code]: "Store_Reuse.is_generalisation_of x xa xb xc = is_generalisation_of x xa xb xc" apply (simp add: Store_Reuse.is_generalisation_of_def is_generalisation_of_def) using tests_input_equality by blast definition iEFSM2dot :: "iEFSM \ nat \ unit" where "iEFSM2dot _ _ = ()" definition logStates :: "iEFSM \ nat \ unit" where "logStates _ _ = ()" (* This is the infer function but with logging *) (* function infer_with_log :: "nat \ nat \ iEFSM \ strategy \ update_modifier \ (transition_matrix \ bool) \ (iEFSM \ nondeterministic_pair fset) \ iEFSM" where "infer_with_log stepNo k e r m check np = ( let scores = if k = 1 then score_1 e r else (k_score k e r) in case inference_step e scores m check np of None \ e | Some new \ let temp = iEFSM2dot new stepNo; temp2 = logStates (size (S new)) (size (S e)) in if (S new) |\| (S e) then infer_with_log (stepNo + 1) k new r m check np else e )" *) (* function infer_with_log :: "(cfstate \ cfstate) set \ nat \ iEFSM \ strategy \ update_modifier \ (transition_matrix \ bool) \ (iEFSM \ nondeterministic_pair fset) \ iEFSM" where *) function infer_with_log :: "(cfstate \ cfstate) set \ nat \ iEFSM \ strategy \ update_modifier \ (transition_matrix \ bool) \ (iEFSM \ nondeterministic_pair fset) \ iEFSM" where "infer_with_log failedMerges k e r m check np = ( let scores = if k = 1 then score_1 e r else (k_score k e r) in case inference_step failedMerges e (ffilter (\s. (S1 s, S2 s) \ failedMerges \ (S2 s, S1 s) \ failedMerges) scores) m check np of (None, _) \ e | (Some new, failedMerges) \ if (Inference.S new) |\| (Inference.S e) then let temp2 = logStates new (size (Inference.S e)) in infer_with_log failedMerges k new r m check np else e )" by auto termination apply (relation "measures [\(_, _, e, _). size (Inference.S e)]") apply simp by (metis (no_types, lifting) case_prod_conv measures_less size_fsubset) lemma infer_empty: "infer f k {||} r m check np = {||}" by (simp add: score_1_def S_def fprod_empty k_score_def) (* lemma [code]: "infer f k e r m check np = infer_with_log f k e r m check np" sorry *) (* declare make_pta_fold [code] *) declare GExp.satisfiable_def [code del] declare initially_undefined_context_check_full_def [code del] declare generalise_output_context_check_def [code del] declare dirty_always_different_outputs_direct_subsumption_def [code del] declare diff_outputs_ctx_def [code del] declare random_member_def [code del] declare dirty_directly_subsumes_def [code del] declare recognises_and_visits_both_def [code del] declare initially_undefined_context_check_def [code del] declare can_still_take_ctx_def [code del] code_printing constant infer \ (Scala) "Code'_Generation.infer'_with'_log" | constant recognises_and_visits_both \ (Scala) "Dirties.recognisesAndGetsUsToBoth" | constant iEFSM2dot \ (Scala) "PrettyPrinter.iEFSM2dot(_, _)" | constant logStates \ (Scala) "Log.logStates(_, _)" | constant "dirty_directly_subsumes" \ (Scala) "Dirties.scalaDirectlySubsumes" | constant "GExp.satisfiable" \ (Scala) "Dirties.satisfiable" | constant "initially_undefined_context_check_full" \ (Scala) "Dirties.initiallyUndefinedContextCheck" | constant "generalise_output_context_check" \ (Scala) "Dirties.generaliseOutputContextCheck" | constant "dirty_always_different_outputs_direct_subsumption" \ (Scala) "Dirties.alwaysDifferentOutputsDirectSubsumption" | constant "diff_outputs_ctx" \ (Scala) "Dirties.diffOutputsCtx" | constant "can_still_take" \ (Scala) "Dirties.canStillTake" | constant "random_member" \ (Scala) "Dirties.randomMember" code_printing constant "show_nat" \ (Scala) "Code'_Numeral.integer'_of'_nat((_)).toString()" | constant "show_int" \ (Scala) "Code'_Numeral.integer'_of'_int((_)).toString()" | constant "join" \ (Scala) "_.mkString((_))" (* Mapping finfuns to Scala native Maps *) code_printing type_constructor finfun \ (Scala) "Map[_, _]" | constant "finfun_const" \ (Scala) "scala.collection.immutable.Map().withDefaultValue((_))" | constant "finfun_update" \ (Scala) "_ + (_ -> _)" | constant "finfun_apply" \ (Scala) "_((_))" | constant "finfun_to_list" \ (Scala) "_.keySet.toList" declare finfun_to_list_const_code [code del] declare finfun_to_list_update_code [code del] definition mismatched_updates :: "transition \ transition \ bool" where "mismatched_updates t1 t2 = (\r \ set (map fst (Updates t1)). r \ set (map fst (Updates t2)))" lemma [code]: "directly_subsumes e1 e2 s1 s2 t1 t2 = (if t1 = t2 then True else dirty_directly_subsumes e1 e2 s1 s2 t1 t2)" by (simp add: directly_subsumes_reflexive dirty_directly_subsumes_def) export_code (* Essentials *) try_heuristics_check learn infer_with_log nondeterministic make_pta AExp.enumerate_vars (* Logical connectives *) gAnd gOr gNot Lt Le Ge Ne (* Scoring functions *) naive_score naive_score_eq_bonus exactly_equal naive_score_outputs naive_score_comprehensive naive_score_comprehensive_eq_high leaves (* Heuristics *) same_register insert_increment_2 heuristic_1 heuristic_2 distinguish weak_subsumption lob (* Nondeterminism metrics *) nondeterministic_pairs nondeterministic_pairs_labar nondeterministic_pairs_labar_dest (* Utilities *) min max drop_pta_guards test_log iefsm2dot efsm2dot guards2sal guards2sal_num fold_In max_int enumerate_vars derestrict in Scala (* file "../../inference-tool/src/main/scala/inference/Inference.scala" *) end diff --git a/thys/Extended_Finite_State_Machine_Inference/examples/Drinks_Subsumption.thy b/thys/Extended_Finite_State_Machine_Inference/examples/Drinks_Subsumption.thy --- a/thys/Extended_Finite_State_Machine_Inference/examples/Drinks_Subsumption.thy +++ b/thys/Extended_Finite_State_Machine_Inference/examples/Drinks_Subsumption.thy @@ -1,154 +1,153 @@ -subsection{*Example*} -text{*This theory shows how contexts can be used to prove transition subsumption.*} +subsection\Example\ +text\This theory shows how contexts can be used to prove transition subsumption.\ theory Drinks_Subsumption imports "Extended_Finite_State_Machine_Inference.Subsumption" "Extended_Finite_State_Machines.Drinks_Machine_2" begin lemma stop_at_3: "\obtains 1 c drinks2 3 r t" proof(induct t arbitrary: r) case Nil then show ?case by (simp add: obtains_base) next case (Cons a t) then show ?case apply (case_tac a) apply (simp add: obtains_step) apply clarify apply (simp add: in_possible_steps[symmetric]) by (simp add: drinks2_def) qed lemma no_1_2: "\obtains 1 c drinks2 2 r t" proof(induct t arbitrary: r) case Nil then show ?case by (simp add: obtains_base) next case (Cons a t) then show ?case apply (case_tac a) apply (simp add: obtains_step) apply clarify apply (simp add: in_possible_steps[symmetric]) apply (simp add: drinks2_def) apply clarsimp apply (simp add: drinks2_def[symmetric]) apply (erule disjE) apply simp apply (erule disjE) apply simp by (simp add: stop_at_3) qed lemma no_change_1_1: "obtains 1 c drinks2 1 r t \ c = r" proof(induct t) case Nil then show ?case by (simp add: obtains_base) next case (Cons a t) then show ?case apply (case_tac a) apply (simp add: obtains_step) apply clarify apply (simp add: in_possible_steps[symmetric]) apply (simp add: drinks2_def) apply clarsimp apply (simp add: drinks2_def[symmetric]) apply (erule disjE) apply (simp add: vend_nothing_def apply_updates_def) by (simp add: no_1_2) qed lemma obtains_1: "obtains 1 c drinks2 0 <> t \ c $ 2 = Some (Num 0)" proof(induct t) case Nil then show ?case by (simp add: obtains_base) next case (Cons a t) then show ?case apply (case_tac a) apply (simp add: obtains_step) apply clarify apply (simp add: in_possible_steps[symmetric]) apply (simp add: drinks2_def) - apply clarsimp apply (simp add: drinks2_def[symmetric]) apply (simp add: select_def can_take apply_updates_def) using no_change_1_1 by fastforce qed lemma obtains_1_1_2: "obtains 1 c1 drinks2 1 r t \ obtains 1 c2 drinks 1 r t \ c1 = r \ c2 = r" proof(induct t arbitrary: r) case Nil then show ?case by (simp add: obtains_base) next case (Cons a t) then show ?case apply (case_tac a) apply (simp add: obtains_step) apply clarify apply (simp add: in_possible_steps[symmetric]) apply (simp add: drinks2_def drinks_def) apply clarsimp apply (simp add: drinks2_def[symmetric] drinks_def[symmetric]) apply safe using Cons.prems(1) no_change_1_1 apply blast apply (simp add: coin_def vend_nothing_def) using Cons.prems(1) no_change_1_1 apply blast apply (simp add: vend_fail_def vend_nothing_def apply_updates_def) using Cons.prems(1) no_change_1_1 apply blast apply (metis drinks_rejects_future numeral_eq_one_iff obtains.cases obtains_recognises semiring_norm(85)) using no_1_2 apply blast using no_1_2 apply blast using Cons.prems(1) no_change_1_1 apply blast using no_1_2 apply blast using no_1_2 apply blast using no_1_2 by blast qed lemma obtains_1_c2: "obtains 1 c1 drinks2 0 <> t \ obtains 1 c2 drinks 0 <> t \ c2 $ 2 = Some (Num 0)" proof(induct t) case Nil then show ?case by (simp add: obtains_base) next case (Cons a t) then show ?case apply (case_tac a) apply (simp add: obtains_step) apply clarify apply (simp add: in_possible_steps[symmetric]) apply (simp add: drinks2_def drinks_def) apply clarsimp apply (simp add: drinks2_def[symmetric] drinks_def[symmetric]) apply (simp add: select_def can_take apply_updates_def) using obtains_1_1_2 by fastforce qed lemma directly_subsumes: "directly_subsumes drinks2 drinks 1 1 vend_fail vend_nothing" apply (rule direct_subsumption[of _ _ _ _ "\c2. c2 $ 2 = Some (Num 0)"]) apply (simp add: obtains_1_c2) apply (rule subsumption) apply (simp add: vend_fail_def vend_nothing_def) apply (simp add: vend_fail_def vend_nothing_def can_take value_gt_true) apply (simp add: vend_fail_def vend_nothing_def) by (simp add: posterior_separate_def vend_fail_def vend_nothing_def) lemma directly_subsumes_flip: "directly_subsumes drinks2 drinks 1 1 vend_nothing vend_fail" apply (rule direct_subsumption[of _ _ _ _ "\c2. c2 $ 2 = Some (Num 0)"]) apply (simp add: obtains_1_c2) apply (rule subsumption) apply (simp add: vend_fail_def vend_nothing_def) apply (simp add: vend_fail_def vend_nothing_def can_take value_gt_true) apply (simp add: vend_fail_def vend_nothing_def can_take value_gt_true) by (simp add: posterior_separate_def vend_fail_def vend_nothing_def) end diff --git a/thys/Extended_Finite_State_Machine_Inference/heuristics/Least_Upper_Bound.thy b/thys/Extended_Finite_State_Machine_Inference/heuristics/Least_Upper_Bound.thy --- a/thys/Extended_Finite_State_Machine_Inference/heuristics/Least_Upper_Bound.thy +++ b/thys/Extended_Finite_State_Machine_Inference/heuristics/Least_Upper_Bound.thy @@ -1,955 +1,955 @@ section\Least Upper Bound\ text\The simplest way to merge a pair of transitions with identical outputs and updates is to simply take the least upper bound of their \emph{guards}. This theory presents several variants on this theme.\ theory Least_Upper_Bound imports "../Inference" begin fun literal_args :: "'a gexp \ bool" where "literal_args (Bc v) = False" | "literal_args (Eq (V _) (L _)) = True" | "literal_args (In _ _) = True" | "literal_args (Eq _ _) = False" | "literal_args (Gt va v) = False" | "literal_args (Nor v va) = (literal_args v \ literal_args va)" lemma literal_args_eq: "literal_args (Eq a b) \ \v l. a = (V v) \ b = (L l)" apply (cases a) apply simp apply (cases b) by auto definition "all_literal_args t = (\g \ set (Guards t). literal_args g)" fun merge_in_eq :: "vname \ value \ vname gexp list \ vname gexp list" where "merge_in_eq v l [] = [Eq (V v) (L l)]" | "merge_in_eq v l ((Eq (V v') (L l'))#t) = (if v = v' \ l \ l' then (In v [l, l'])#t else (Eq (V v') (L l'))#(merge_in_eq v l t))" | "merge_in_eq v l ((In v' l')#t) = (if v = v' then (In v (remdups (l#l')))#t else (In v' l')#(merge_in_eq v l t))" | "merge_in_eq v l (h#t) = h#(merge_in_eq v l t)" fun merge_in_in :: "vname \ value list \ vname gexp list \ vname gexp list" where "merge_in_in v l [] = [In v l]" | "merge_in_in v l ((Eq (V v') (L l'))#t) = (if v = v' then (In v (List.insert l' l))#t else (Eq (V v') (L l'))#(merge_in_in v l t))" | "merge_in_in v l ((In v' l')#t) = (if v = v' then (In v (List.union l l'))#t else (In v' l')#(merge_in_in v l t))" | "merge_in_in v l (h#t) = h#(merge_in_in v l t)" fun merge_guards :: "vname gexp list \ vname gexp list \ vname gexp list" where "merge_guards [] g2 = g2" | "merge_guards ((Eq (V v) (L l))#t) g2 = merge_guards t (merge_in_eq v l g2)" | "merge_guards ((In v l)#t) g2 = merge_guards t (merge_in_in v l g2)" | "merge_guards (h#t) g2 = h#(merge_guards t g2)" text\The ``least upper bound'' (lob) heuristic simply disjoins the guards of two transitions with identical outputs and updates.\ definition lob_aux :: "transition \ transition \ transition option" where "lob_aux t1 t2 = (if Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ all_literal_args t1 \ all_literal_args t2 then Some \Label = Label t1, Arity = Arity t1, Guards = remdups (merge_guards (Guards t1) (Guards t2)), Outputs = Outputs t1, Updates = Updates t1\ else None)" fun lob :: update_modifier where "lob t1ID t2ID s new _ old _ = (let t1 = (get_by_ids new t1ID); t2 = (get_by_ids new t2ID) in case lob_aux t1 t2 of None \ None | Some lob_t \ Some (replace_transitions new [(t1ID, lob_t), (t2ID, lob_t)]) )" lemma lob_aux_some: "Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ all_literal_args t1 \ all_literal_args t2 \ Label t = Label t1 \ Arity t = Arity t1 \ Guards t = remdups (merge_guards (Guards t1) (Guards t2)) \ Outputs t = Outputs t1 \ Updates t = Updates t1 \ lob_aux t1 t2 = Some t" by (simp add: lob_aux_def) fun has_corresponding :: "vname gexp \ vname gexp list \ bool" where "has_corresponding g [] = False" | "has_corresponding (Eq (V v) (L l)) ((Eq (V v') (L l'))#t) = (if v = v' \ l = l' then True else has_corresponding (Eq (V v) (L l)) t)" | "has_corresponding (In v' l') ((Eq (V v) (L l))#t) = (if v = v' \ l \ set l' then True else has_corresponding (In v' l') t)" | "has_corresponding (In v l) ((In v' l')#t) = (if v = v' \ set l' \ set l then True else has_corresponding (In v l) t)" | "has_corresponding g (h#t) = has_corresponding g t" lemma no_corresponding_bc: "\has_corresponding (Bc x1) G1" apply (induct G1) by auto lemma no_corresponding_gt: "\has_corresponding (Gt x1 y1) G1" apply (induct G1) by auto lemma no_corresponding_nor: "\has_corresponding (Nor x1 y1) G1" apply (induct G1) by auto lemma has_corresponding_eq: "has_corresponding (Eq x21 x22) G1 \ (Eq x21 x22) \ set G1" proof(induct G1) case (Cons a G1) then show ?case apply (cases a) apply simp subgoal for x21a x22a apply (case_tac "x21a") apply simp apply (case_tac "x22a") apply clarify apply simp apply (case_tac "x21") apply simp apply (case_tac "x22") apply (metis has_corresponding.simps(2)) by auto by auto qed auto lemma has_corresponding_In: "has_corresponding (In v l) G1 \ (\l'. (In v l') \ set G1 \ set l' \ set l) \ (\l' \ set l. (Eq (V v) (L l')) \ set G1)" proof(induct G1) case (Cons a G1) then show ?case apply (cases a) apply simp defer apply simp apply simp defer apply simp apply simp subgoal for x21 x22 apply (case_tac x21) apply simp apply (case_tac x22) apply fastforce apply simp+ done by metis qed auto lemma gval_each_one: "g \ set G \ apply_guards G s \ gval g s = true" using apply_guards_cons apply_guards_rearrange by blast lemma has_corresponding_apply_guards: "\g\set G2. has_corresponding g G1 \ apply_guards G1 s \ apply_guards G2 s" proof(induct G2) case (Cons a G2) then show ?case apply (cases a) apply (simp add: no_corresponding_bc) apply simp apply (metis (full_types) has_corresponding_eq append_Cons append_self_conv2 apply_guards_append apply_guards_rearrange) apply (simp add: no_corresponding_gt) apply simp subgoal for v l apply (insert has_corresponding_In[of v l G1]) apply simp apply (erule disjE) apply clarsimp subgoal for l' apply (insert apply_guards_rearrange[of "In v l'" G1 s]) apply simp apply (simp only: apply_guards_cons[of "In v l" G2]) apply (simp only: apply_guards_cons[of "In v l'" G1]) apply simp apply (cases "s v") apply simp by force apply clarsimp subgoal for l' apply (insert apply_guards_rearrange[of "Eq (V v) (L l')" G1 s]) apply simp apply (simp only: apply_guards_cons[of "In v l" G2]) apply (simp only: apply_guards_cons[of "Eq (V v) (L l')" G1]) apply (cases "s v") apply simp apply simp using trilean.distinct(1) by presburger done by (simp add: no_corresponding_nor) qed auto lemma correspondence_subsumption: "Label t1 = Label t2 \ Arity t1 = Arity t2 \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ \g \ set (Guards t2). has_corresponding g (Guards t1) \ subsumes t2 c t1" by (simp add: can_take_def can_take_transition_def has_corresponding_apply_guards subsumption) definition "is_lob t1 t2 = ( Label t1 = Label t2 \ Arity t1 = Arity t2 \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ (\g \ set (Guards t2). has_corresponding g (Guards t1)))" lemma is_lob_direct_subsumption: "is_lob t1 t2 \ directly_subsumes e1 e2 s s' t2 t1" apply (rule subsumes_in_all_contexts_directly_subsumes) by (simp add: is_lob_def correspondence_subsumption) fun has_distinguishing :: "vname gexp \ vname gexp list \ bool" where "has_distinguishing g [] = False" | "has_distinguishing (Eq (V v) (L l)) ((Eq (V v') (L l'))#t) = (if v = v' \ l \ l' then True else has_distinguishing (Eq (V v) (L l)) t)" | "has_distinguishing (In (I v') l') ((Eq (V (I v)) (L l))#t) = (if v = v' \ l \ set l' then True else has_distinguishing (In (I v') l') t)" | "has_distinguishing (In (I v) l) ((In (I v') l')#t) = (if v = v' \ set l' \ set l then True else has_distinguishing (In (I v) l) t)" | "has_distinguishing g (h#t) = has_distinguishing g t" lemma has_distinguishing: "has_distinguishing g G \ (\v l. g = (Eq (V v) (L l))) \ (\v l. g = In v l)" proof(induct G) case (Cons a G) then show ?case apply (cases g) apply simp apply (case_tac x21) apply simp apply (case_tac x22) by auto qed auto lemma has_distinguishing_Eq: "has_distinguishing (Eq (V v) (L l)) G \ \l'. (Eq (V v) (L l')) \ set G \ l \ l'" proof (induct G) case (Cons a G) then show ?case apply (cases a) apply simp apply (case_tac x21) apply simp apply (case_tac x22) apply (metis has_distinguishing.simps(2) list.set_intros(1) list.set_intros(2)) by auto qed auto lemma ex_mutex: "Eq (V v) (L l) \ set G1 \ Eq (V v) (L l') \ set G2 \ l \ l' \ apply_guards G1 s \ \ apply_guards G2 s" apply (simp add: apply_guards_def Bex_def) apply (rule_tac x="Eq (V v) (L l')" in exI) apply simp apply (case_tac "s v") by auto lemma has_distinguishing_In: "has_distinguishing (In v l) G \ (\l' i. v = I i \ Eq (V v) (L l') \ set G \ l' \ set l) \ (\l' i. v = I i \ In v l' \ set G \ set l' \ set l)" proof(induct G) case (Cons a G) then show ?case apply (case_tac v) subgoal for x apply simp apply (cases a) apply simp subgoal for x21 x22 apply (case_tac x21) apply simp apply (case_tac x22) apply (case_tac x2) apply fastforce apply simp+ done subgoal by simp subgoal for x41 apply (case_tac x41) apply (simp, metis) by auto by auto by auto qed auto lemma Eq_apply_guards: "Eq (V v) (L l) \ set G1 \ apply_guards G1 s \ s v = Some l" apply (simp add: apply_guards_rearrange) apply (simp add: apply_guards_cons) apply (cases "s v") apply simp apply simp using trilean.distinct(1) by presburger lemma In_neq_apply_guards: "In v l \ set G2 \ Eq (V v) (L l') \ set G1 \ l' \ set l \ apply_guards G1 s \ \apply_guards G2 s" proof(induct G1) case (Cons a G1) then show ?case apply (simp add: apply_guards_def Bex_def) apply (rule_tac x="In v l" in exI) using Eq_apply_guards[of v l' "a#G1" s] by (simp add: Cons.prems(4) image_iff) qed auto lemma In_apply_guards: "In v l \ set G1 \ apply_guards G1 s \ \v' \ set l. s v = Some v'" apply (simp add: apply_guards_rearrange) apply (simp add: apply_guards_cons) apply (cases "s v") apply simp apply simp by (meson image_iff trilean.simps(2)) lemma input_not_constrained_aval_swap_inputs: "\ aexp_constrains a (V (I v)) \ aval a (join_ir i c) = aval a (join_ir (list_update i v x) c)" apply(induct a rule: aexp_induct_separate_V_cases) apply simp apply (metis aexp_constrains.simps(2) aval.simps(2) input2state_nth input2state_out_of_bounds join_ir_def length_list_update not_le nth_list_update_neq vname.simps(5)) using join_ir_def by auto lemma input_not_constrained_gval_swap_inputs: "\ gexp_constrains a (V (I v)) \ gval a (join_ir i c) = gval a (join_ir (i[v := x]) c)" proof(induct a) case (Bc x) then show ?case by (metis (full_types) gval.simps(1) gval.simps(2)) next case (Eq x1a x2) then show ?case using input_not_constrained_aval_swap_inputs by auto next case (Gt x1a x2) then show ?case using input_not_constrained_aval_swap_inputs by auto next case (In x1a x2) then show ?case apply simp apply (case_tac "join_ir i c x1a") apply (case_tac "join_ir (i[v := x]) c x1a") apply simp apply (metis In.prems aval.simps(2) gexp_constrains.simps(5) input_not_constrained_aval_swap_inputs option.discI) apply (case_tac "join_ir (i[v := x]) c x1a") apply (metis In.prems aval.simps(2) gexp_constrains.simps(5) input_not_constrained_aval_swap_inputs option.discI) by (metis In.prems aval.simps(2) gexp_constrains.simps(5) input_not_constrained_aval_swap_inputs) qed auto lemma test_aux: "\g\set (removeAll (In (I v) l) G1). \ gexp_constrains g (V (I v)) \ apply_guards G1 (join_ir i c) \ x \ set l \ apply_guards G1 (join_ir (i[v := x]) c)" proof(induct G1) case (Cons a G1) then show ?case apply (simp only: apply_guards_cons) apply (case_tac "a = In (I v) l") apply simp apply (case_tac "join_ir i c (I v)") apply simp apply (case_tac "join_ir (i[v := x]) c (I v)") apply (metis join_ir_nth le_less_linear length_list_update list_update_beyond option.discI) apply simp apply (metis join_ir_nth le_less_linear length_list_update list_update_beyond nth_list_update_eq option.inject trilean.distinct(1)) apply (case_tac "join_ir (i[v := x]) c (I v)") apply (metis join_ir_nth le_less_linear length_list_update list_update_beyond option.discI) apply simp using input_not_constrained_gval_swap_inputs by auto qed auto lemma test: assumes p1: "In (I v) l \ set G2" and p2: "In (I v) l' \ set G1" and p3: "x \ set l'" and p4: "x \ set l" and p5: "apply_guards G1 (join_ir i c)" and p6: "length i = a" and p7: "\g \ set (removeAll (In (I v) l') G1). \ gexp_constrains g (V (I v))" shows "\i. length i = a \ apply_guards G1 (join_ir i c) \ (length i = a \ \ apply_guards G2 (join_ir i c))" apply (rule_tac x="list_update i v x" in exI) apply standard apply (simp add: p6) apply standard using p3 p5 p7 test_aux apply blast using p1 p4 apply (simp add: apply_guards_rearrange) apply (simp add: apply_guards_cons join_ir_def) apply (case_tac "input2state (i[v := x]) $ v") apply simp apply simp by (metis input2state_nth input2state_within_bounds length_list_update nth_list_update_eq option.inject) definition get_Ins :: "vname gexp list \ (nat \ value list) list" where "get_Ins G = map (\g. case g of (In (I v) l) \ (v, l)) (filter (\g. case g of (In (I _) _ ) \ True | _ \ False) G)" lemma get_Ins_Cons_equiv: "\v l. a = In (I v) l \ get_Ins (a # G) = get_Ins G" apply (simp add: get_Ins_def) apply (cases a) apply simp+ apply (metis (full_types) vname.exhaust vname.simps(6)) by simp lemma Ball_Cons: "(\x \ set (a#l). P x) = (P a \ (\x \ set l. P x))" by simp lemma In_in_get_Ins: "(In (I v) l \ set G) = ((v, l) \ set (get_Ins G))" proof(induct G) case Nil then show ?case by (simp add: get_Ins_def) next case (Cons a G) then show ?case apply (simp add: get_Ins_def) apply (cases a) apply simp+ subgoal for x by (case_tac x, auto) apply auto done qed definition "check_get_Ins G = (\(v, l') \ set (get_Ins G). \g \ set (removeAll (In (I v) l') G). \ gexp_constrains g (V (I v)))" lemma no_Ins: "[] = get_Ins G \ set G - {In (I i) l} = set G" proof(induct G) case (Cons a G) then show ?case apply (cases a) apply (simp add: get_Ins_Cons_equiv insert_Diff_if)+ subgoal for x41 x42 apply (case_tac x41) apply simp apply (metis In_in_get_Ins equals0D list.set(1) list.set_intros(1)) apply (simp add: get_Ins_Cons_equiv) done by (simp add: get_Ins_Cons_equiv insert_Diff_if) qed auto lemma test2: "In (I i) l \ set (Guards t2) \ In (I i) l' \ set (Guards t1) \ length ia = Arity t1 \ apply_guards (Guards t1) (join_ir ia c) \ x \ set l' \ x \ set l \ \(v, l')\insert (0, []) (set (get_Ins (Guards t1))). \g\set (removeAll (In (I v) l') (Guards t1)). \ gexp_constrains g (V (I v)) \ Arity t1 = Arity t2 \ \i. length i = Arity t2 \ apply_guards (Guards t1) (join_ir i c) \ (length i = Arity t2 \ \ apply_guards (Guards t2) (join_ir i c))" using test[of i l "Guards t2" l' "Guards t1" x ia c "Arity t2"] apply simp apply (case_tac "\g\set (Guards t1) - {In (I i) l'}. \ gexp_constrains g (V (I i))") apply simp apply simp using In_in_get_Ins by blast lemma distinguishing_subsumption: assumes p1: "\g \ set (Guards t2). has_distinguishing g (Guards t1)" and p2: "Arity t1 = Arity t2" and p3: "\i. can_take_transition t1 i c" and p4: "(\(v, l') \ insert (0, []) (set (get_Ins (Guards t1))). \g \ set (removeAll (In (I v) l') (Guards t1)). \ gexp_constrains g (V (I v)))" shows "\ subsumes t2 c t1" proof- show ?thesis apply (rule bad_guards) apply (simp add: can_take_transition_def can_take_def p2) apply (insert p1, simp add: Bex_def) apply (erule exE) apply (case_tac "\v l. x = (Eq (V v) (L l))") apply (metis can_take_def can_take_transition_def ex_mutex p2 p3 has_distinguishing_Eq) apply (case_tac "\v l. x = In v l") defer using has_distinguishing apply blast apply clarify apply (case_tac "\l' i. v = I i \ Eq (V v) (L l') \ set (Guards t1) \ l' \ set l") apply (metis In_neq_apply_guards can_take_def can_take_transition_def p2 p3) apply (case_tac "(\l' i. v = I i \ In v l' \ set (Guards t1) \ set l' \ set l)") defer using has_distinguishing_In apply blast apply simp apply (erule conjE) apply (erule exE)+ apply (erule conjE) apply (insert p3, simp only: can_take_transition_def can_take_def) apply (case_tac "\x. x \ set l' \ x \ set l") apply (erule exE)+ apply (erule conjE)+ apply (insert p4 p2) using test2 apply blast by auto qed definition "lob_distinguished t1 t2 = ( (\g \ set (Guards t2). has_distinguishing g (Guards t1)) \ Arity t1 = Arity t2 \ (\(v, l') \ insert (0, []) (set (get_Ins (Guards t1))). \g \ set (removeAll (In (I v) l') (Guards t1)). \ gexp_constrains g (V (I v))))" lemma must_be_another: "1 < size (fset_of_list b) \ x \ set b \ \x' \ set b. x \ x'" proof(induct b) case (Cons a b) then show ?case apply (simp add: Bex_def) by (metis List.finite_set One_nat_def card.insert card_gt_0_iff card_mono fset_of_list.rep_eq insert_absorb le_0_eq less_nat_zero_code less_numeral_extra(4) not_less_iff_gr_or_eq set_empty2 subsetI) qed auto lemma another_swap_inputs: "apply_guards G (join_ir i c) \ filter (\g. gexp_constrains g (V (I a))) G = [In (I a) b] \ xa \ set b \ apply_guards G (join_ir (i[a := xa]) c)" proof(induct G) case (Cons g G) then show ?case apply (simp add: apply_guards_cons) apply (case_tac "gexp_constrains g (V (I a))") defer using input_not_constrained_gval_swap_inputs apply auto[1] apply simp apply (case_tac "join_ir i c (I a) \ Some ` set b") defer apply simp apply clarify apply standard using apply_guards_def input_not_constrained_gval_swap_inputs apply (simp add: filter_empty_conv) apply (case_tac "join_ir i c (I a)") apply simp apply (case_tac "join_ir (i[a := xa]) c (I a)") apply simp apply (metis image_eqI trilean.distinct(1)) apply simp apply (metis image_eqI trilean.distinct(1)) apply (case_tac "join_ir i c (I a)") apply simp apply simp apply (metis image_eqI trilean.distinct(1)) apply (case_tac "join_ir i c (I a)") apply simp apply (case_tac "join_ir (i[a := xa]) c (I a)") apply simp apply (metis join_ir_nth le_less_linear length_list_update list_update_beyond option.discI) apply simp apply standard apply (metis (no_types, lifting) Cons.hyps Cons.prems(2) filter_empty_conv removeAll_id set_ConsD test_aux) by (metis in_these_eq join_ir_nth le_less_linear length_list_update list_update_beyond nth_list_update_eq these_image_Some_eq) qed auto lemma lob_distinguished_2_not_subsumes: "\(i, l) \ set (get_Ins (Guards t2)). filter (\g. gexp_constrains g (V (I i))) (Guards t2) = [(In (I i) l)] \ (\l' \ set l. i < Arity t1 \ Eq (V (I i)) (L l') \ set (Guards t1) \ size (fset_of_list l) > 1) \ Arity t1 = Arity t2 \ \i. can_take_transition t2 i c \ \ subsumes t1 c t2" apply (rule bad_guards) apply simp apply (simp add: can_take_def can_take_transition_def Bex_def) apply clarify apply (case_tac "\x' \ set b. x \ x'") defer apply (simp add: must_be_another) apply (simp add: Bex_def) apply (erule exE) apply (rule_tac x="list_update i a xa" in exI) apply simp apply standard apply (simp add: another_swap_inputs) by (metis Eq_apply_guards input2state_nth join_ir_def length_list_update nth_list_update_eq option.inject vname.simps(5)) definition "lob_distinguished_2 t1 t2 = (\(i, l) \ set (get_Ins (Guards t2)). filter (\g. gexp_constrains g (V (I i))) (Guards t2) = [(In (I i) l)] \ (\l' \ set l. i < Arity t1 \ Eq (V (I i)) (L l') \ set (Guards t1) \ size (fset_of_list l) > 1) \ Arity t1 = Arity t2)" lemma lob_distinguished_3_not_subsumes: "\(i, l) \ set (get_Ins (Guards t2)). filter (\g. gexp_constrains g (V (I i))) (Guards t2) = [(In (I i) l)] \ (\(i', l') \ set (get_Ins (Guards t1)). i = i' \ set l' \ set l) \ Arity t1 = Arity t2 \ \i. can_take_transition t2 i c \ \ subsumes t1 c t2" apply (rule bad_guards) apply simp apply (simp add: can_take_def can_take_transition_def Bex_def) apply (erule exE)+ apply (erule conjE)+ apply (erule exE)+ apply (erule conjE)+ apply (case_tac "\x. x \ set b \ x \ set ba") defer apply auto[1] apply (erule exE)+ apply (erule conjE)+ apply (rule_tac x="list_update i a x" in exI) apply simp apply standard using another_swap_inputs apply blast by (metis In_apply_guards In_in_get_Ins input2state_not_None input2state_nth join_ir_def nth_list_update_eq option.distinct(1) option.inject vname.simps(5)) definition "lob_distinguished_3 t1 t2 = (\(i, l) \ set (get_Ins (Guards t2)). filter (\g. gexp_constrains g (V (I i))) (Guards t2) = [(In (I i) l)] \ (\(i', l') \ set (get_Ins (Guards t1)). i = i' \ set l' \ set l) \ Arity t1 = Arity t2)" fun is_In :: "'a gexp \ bool" where "is_In (In _ _) = True" | "is_In _ = False" text\The ``greatest upper bound'' (gob) heuristic is similar to \texttt{lob} but applies a more intellegent approach to guard merging.\ definition gob_aux :: "transition \ transition \ transition option" where "gob_aux t1 t2 = (if Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ all_literal_args t1 \ all_literal_args t2 then Some \Label = Label t1, Arity = Arity t1, Guards = remdups (filter (Not \ is_In) (merge_guards (Guards t1) (Guards t2))), Outputs = Outputs t1, Updates = Updates t1\ else None)" fun gob :: update_modifier where "gob t1ID t2ID s new _ old _ = (let t1 = (get_by_ids new t1ID); t2 = (get_by_ids new t2ID) in case gob_aux t1 t2 of None \ None | Some gob_t \ Some (replace_transitions new [(t1ID, gob_t), (t2ID, gob_t)]) )" text\The ``Gung Ho'' heuristic simply drops the guards of both transitions, making them identical.\ definition gung_ho_aux :: "transition \ transition \ transition option" where "gung_ho_aux t1 t2 = (if Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ all_literal_args t1 \ all_literal_args t2 then Some \Label = Label t1, Arity = Arity t1, Guards = [], Outputs = Outputs t1, Updates = Updates t1\ else None)" fun gung_ho :: update_modifier where "gung_ho t1ID t2ID s new _ old _ = (let t1 = (get_by_ids new t1ID); t2 = (get_by_ids new t2ID) in case gung_ho_aux t1 t2 of None \ None | Some gob_t \ Some (replace_transitions new [(t1ID, gob_t), (t2ID, gob_t)]) )" lemma guard_subset_eq_outputs_updates_subsumption: "Label t1 = Label t2 \ Arity t1 = Arity t2 \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ set (Guards t2) \ set (Guards t1) \ subsumes t2 c t1" apply (simp add: subsumes_def) by (meson can_take_def can_take_subset can_take_transition_def) lemma guard_subset_eq_outputs_updates_direct_subsumption: "Label t1 = Label t2 \ Arity t1 = Arity t2 \ Outputs t1 = Outputs t2 \ Updates t1 = Updates t2 \ set (Guards t2) \ set (Guards t1) \ directly_subsumes m1 m2 s1 s2 t2 t1" apply (rule subsumes_in_all_contexts_directly_subsumes) by (simp add: guard_subset_eq_outputs_updates_subsumption) lemma unconstrained_input: "\g\set G. \ gexp_constrains g (V (I i)) \ apply_guards G (join_ir ia c) \ apply_guards G (join_ir (ia[i := x']) c)" proof(induct G) case (Cons a G) then show ?case apply (simp add: apply_guards_cons) using input_not_constrained_gval_swap_inputs[of a i ia c x'] by simp qed auto lemma each_input_guarded_once_cons: "\i\\ (enumerate_gexp_inputs ` set (a # G)). length (filter (\g. gexp_constrains g (V (I i))) (a # G)) \ 1 \ \i\\ (enumerate_gexp_inputs ` set G). length (filter (\g. gexp_constrains g (V (I i))) G) \ 1" apply (simp add: Ball_def) apply clarify proof - fix x :: nat and xa :: "vname gexp" assume a1: "\x. (x \ enumerate_gexp_inputs a \ length (if gexp_constrains a (V (I x)) then a # filter (\g. gexp_constrains g (V (I x))) G else filter (\g. gexp_constrains g (V (I x))) G) \ 1) \ ((\xa\set G. x \ enumerate_gexp_inputs xa) \ length (if gexp_constrains a (V (I x)) then a # filter (\g. gexp_constrains g (V (I x))) G else filter (\g. gexp_constrains g (V (I x))) G) \ 1)" assume a2: "xa \ set G" assume "x \ enumerate_gexp_inputs xa" then have "if gexp_constrains a (V (I x)) then length (a # filter (\g. gexp_constrains g (V (I x))) G) \ 1 else length (filter (\g. gexp_constrains g (V (I x))) G) \ 1" using a2 a1 by fastforce then show "length (filter (\g. gexp_constrains g (V (I x))) G) \ 1" by (metis (no_types) impossible_Cons le_cases order.trans) qed lemma literal_args_can_take: "\g\set G. \i v s. g = Eq (V (I i)) (L v) \ g = In (I i) s \ s \ [] \ \i\\ (enumerate_gexp_inputs ` set G). i < a \ \i\\ (enumerate_gexp_inputs ` set G). length (filter (\g. gexp_constrains g (V (I i))) G) \ 1 \ \i. length i = a \ apply_guards G (join_ir i c)" proof(induct G) case Nil then show ?case using Ex_list_of_length by auto next case (Cons a G) then show ?case apply simp apply (case_tac "\y\set G. \i\enumerate_gexp_inputs y. length (filter (\g. gexp_constrains g (V (I i))) G) \ 1") defer using each_input_guarded_once_cons apply auto[1] apply (simp add: ball_Un) apply clarsimp apply (induct a) apply simp apply simp - subgoal for _ x2 i ia + subgoal for x2 i ia apply (case_tac x2) apply (rule_tac x="list_update i ia x1" in exI) apply (simp add: apply_guards_cons unconstrained_input filter_empty_conv) apply simp+ done apply simp subgoal for _ x2 i ia apply (case_tac x2) apply simp subgoal for aa apply (rule_tac x="list_update i ia aa" in exI) apply (simp add: apply_guards_cons unconstrained_input filter_empty_conv) done done by simp qed lemma "(SOME x'. x' \ (v::value)) \ v" proof(induct v) case (Num x) then show ?case by (metis (full_types) someI_ex value.simps(4)) next case (Str x) then show ?case by (metis (full_types) someI_ex value.simps(4)) qed lemma opposite_gob_subsumption: "\g \ set (Guards t1). \i v s. g = Eq (V (I i)) (L v) \ (g = In (I i) s \ s \ []) \ \g \ set (Guards t2). \i v s. g = Eq (V (I i)) (L v) \ (g = In (I i) s \ s \ []) \ \ i. \v. Eq (V (I i)) (L v) \ set (Guards t1) \ (\g \ set (Guards t2). \ gexp_constrains g (V (I i))) \ Arity t1 = Arity t2 \ \i \ enumerate_inputs t2. i < Arity t2 \ \i \ enumerate_inputs t2. length (filter (\g. gexp_constrains g (V (I i))) (Guards t2)) \ 1 \ \ subsumes t1 c t2" apply (rule bad_guards) apply (simp add: enumerate_inputs_def can_take_transition_def can_take_def Bex_def) using literal_args_can_take[of "Guards t2" "Arity t2" c] apply simp apply clarify subgoal for i ia v apply (rule_tac x="list_update ia i (Eps (\x'. x' \ v))" in exI) apply simp apply standard apply (simp add: apply_guards_def) using input_not_constrained_gval_swap_inputs apply simp apply (simp add: apply_guards_def Bex_def) apply (rule_tac x="Eq (V (I i)) (L v)" in exI) apply (simp add: join_ir_def) apply (case_tac "input2state (ia[i := SOME x'. x' \ v]) $ i") apply simp apply simp apply (case_tac "i < length ia") apply (simp add: input2state_nth) apply (case_tac v) apply (metis (mono_tags) someI_ex value.simps(4)) apply (metis (mono_tags) someI_ex value.simps(4)) by (metis input2state_within_bounds length_list_update) done fun is_lit_eq :: "vname gexp \ nat \ bool" where "is_lit_eq (Eq (V (I i)) (L v)) i' = (i = i')" | "is_lit_eq _ _ = False" lemma "(\v. Eq (V (I i)) (L v) \ set G) = (\g \ set G. is_lit_eq g i)" by (metis is_lit_eq.elims(2) is_lit_eq.simps(1)) fun is_lit_eq_general :: "vname gexp \ bool" where "is_lit_eq_general (Eq (V (I _)) (L _)) = True" | "is_lit_eq_general _ = False" fun is_input_in :: "vname gexp \ bool" where "is_input_in (In (I i) s) = (s \ [])" | "is_input_in _ = False" definition "opposite_gob t1 t2 = ( (\g \ set (Guards t1). is_lit_eq_general g \ is_input_in g) \ (\g \ set (Guards t2). is_lit_eq_general g \ is_input_in g) \ (\ i \ (enumerate_inputs t1 \ enumerate_inputs t2). (\g \ set (Guards t1). is_lit_eq g i) \ (\g \ set (Guards t2). \ gexp_constrains g (V (I i)))) \ Arity t1 = Arity t2 \ (\i \ enumerate_inputs t2. i < Arity t2) \ (\i \ enumerate_inputs t2. length (filter (\g. gexp_constrains g (V (I i))) (Guards t2)) \ 1))" lemma "is_lit_eq_general g \ is_input_in g \ \i v s. g = Eq (V (I i)) (L v) \ g = In (I i) s \ s \ []" by (meson is_input_in.elims(2) is_lit_eq_general.elims(2)) lemma opposite_gob_directly_subsumption: "opposite_gob t1 t2 \ \ subsumes t1 c t2" apply (rule opposite_gob_subsumption) unfolding opposite_gob_def apply (meson is_input_in.elims(2) is_lit_eq_general.elims(2))+ apply (metis is_lit_eq.elims(2)) by auto fun get_in :: "'a gexp \ ('a \ value list) option" where "get_in (In v s) = Some (v, s)" | "get_in _ = None" lemma not_subset_not_in: "(\ s1 \ s2) = (\i. i \ s1 \ i \ s2)" by auto lemma get_in_is: "(get_in x = Some (v, s1)) = (x = In v s1)" by (induct x, auto) lemma gval_rearrange: "g \ set G \ gval g s = true \ apply_guards (removeAll g G) s \ apply_guards G s" proof(induct G) case (Cons a G) then show ?case apply (simp only: apply_guards_cons) apply standard apply (metis apply_guards_cons removeAll.simps(2)) by (metis apply_guards_cons removeAll.simps(2) removeAll_id) qed auto lemma singleton_list: "(length l = 1) = (\e. l = [e])" by (induct l, auto) lemma remove_restricted: "g \ set G \ gexp_constrains g (V v) \ restricted_once v G \ not_restricted v (removeAll g G)" apply (simp add: restricted_once_def not_restricted_def singleton_list) apply clarify subgoal for e apply (case_tac "e = g") defer apply (metis (no_types, lifting) DiffE Diff_insert_absorb Set.set_insert empty_set filter.simps(2) filter_append in_set_conv_decomp insert_iff list.set(2)) apply (simp add: filter_empty_conv) proof - fix e :: "'a gexp" assume "filter (\g. gexp_constrains g (V v)) G = [g]" then have "{g \ set G. gexp_constrains g (V v)} = {g}" by (metis (no_types) empty_set list.simps(15) set_filter) then show "\g\set G - {g}. \ gexp_constrains g (V v)" by blast qed done lemma unrestricted_input_swap: "not_restricted (I i) G \ apply_guards G (join_ir iaa c) \ apply_guards (removeAll g G) (join_ir (iaa[i := ia]) c)" proof(induct G) case (Cons a G) then show ?case apply (simp add: apply_guards_cons not_restricted_def) apply safe apply (meson neq_Nil_conv) apply (metis input_not_constrained_gval_swap_inputs list.distinct(1)) by (metis list.distinct(1)) qed auto lemma apply_guards_remove_restricted: "g \ set G \ gexp_constrains g (V (I i)) \ restricted_once (I i) G \ apply_guards G (join_ir iaa c) \ apply_guards (removeAll g G) (join_ir (iaa[i := ia]) c)" proof(induct G) case (Cons a G) then show ?case apply simp apply safe apply (rule unrestricted_input_swap) apply (simp add: not_restricted_def restricted_once_def) apply (meson apply_guards_subset set_subset_Cons) apply (simp add: apply_guards_rearrange not_restricted_def restricted_once_def unrestricted_input_swap) by (metis apply_guards_cons filter.simps(2) filter_empty_conv input_not_constrained_gval_swap_inputs list.inject restricted_once_def singleton_list) qed auto lemma In_swap_inputs: "In (I i) s2 \ set G \ restricted_once (I i) G \ ia \ set s2 \ apply_guards G (join_ir iaa c) \ apply_guards G (join_ir (iaa[i := ia]) c)" using apply_guards_remove_restricted[of "In (I i) s2" G i iaa c ia] apply simp apply (rule gval_rearrange[of "In (I i) s2"]) apply simp apply (metis filter_empty_conv gval_each_one input_not_constrained_gval_swap_inputs length_0_conv not_restricted_def remove_restricted test_aux) by blast definition these :: "'a option list \ 'a list" where "these as = map (\x. case x of Some y \ y) (filter (\x. x \ None) as)" lemma these_cons: "these (a#as) = (case a of None \ these as | Some x \ x#(these as))" apply (cases a) apply (simp add: these_def) by (simp add: these_def) definition get_ins :: "vname gexp list \ (nat \ value list) list" where "get_ins g = map (\(v, s). case v of I i \ (i, s)) (filter (\(v, _). case v of I _ \ True | R _ \ False) (these (map get_in g)))" lemma in_get_ins: "(I x1a, b) \ set (these (map get_in G)) \ In (I x1a) b \ set G" proof(induct G) case Nil then show ?case by (simp add: these_def) next case (Cons a G) then show ?case apply simp apply (simp add: these_cons) apply (cases a) by auto qed lemma restricted_head: "\v. restricted_once v (Eq (V x2) (L x1) # G) \ not_restricted v (Eq (V x2) (L x1) # G) \ not_restricted x2 G" apply (erule_tac x=x2 in allE) by (simp add: restricted_once_def not_restricted_def) fun atomic :: "'a gexp \ bool" where "atomic (Eq (V _) (L _)) = True" | "atomic (In _ _) = True" | "atomic _ = False" lemma restricted_max_once_cons: "\v. restricted_once v (g#gs) \ not_restricted v (g#gs) \ \v. restricted_once v gs \ not_restricted v gs" apply (simp add: restricted_once_def not_restricted_def) apply safe subgoal for v by (erule_tac x=v in allE) (metis (mono_tags, lifting) list.distinct(1) list.inject singleton_list) done lemma not_restricted_swap_inputs: "not_restricted (I x1a) G \ apply_guards G (join_ir i r) \ apply_guards G (join_ir (i[x1a := x1]) r)" proof(induct G) case (Cons a G) then show ?case apply (simp add: apply_guards_cons not_restricted_cons) using input_not_constrained_gval_swap_inputs by auto qed auto end