paulson@5899: (* Title: HOL/UNITY/PPROD.thy paulson@5899: Author: Lawrence C Paulson, Cambridge University Computer Laboratory paulson@5899: Copyright 1998 University of Cambridge paulson@5899: paulson@7188: Abstraction over replicated components (PLam) paulson@7188: General products of programs (Pi operation) paulson@13786: paulson@13786: Some dead wood here! paulson@5899: *) paulson@5899: haftmann@16417: theory PPROD imports Lift_prog begin paulson@5899: haftmann@35416: definition PLam :: "[nat set, nat => ('b * ((nat=>'b) * 'c)) program] haftmann@35416: => ((nat=>'b) * 'c) program" where paulson@13805: "PLam I F == \i \ I. lift i (F i)" paulson@5899: paulson@5899: syntax wenzelm@35054: "_PLam" :: "[pttrn, nat set, 'b set] => (nat => 'b) set" ("(3plam _:_./ _)" 10) paulson@5899: translations wenzelm@35054: "plam x : A. B" == "CONST PLam A (%x. B)" paulson@5899: paulson@13786: paulson@13786: (*** Basic properties ***) paulson@13786: paulson@13812: lemma Init_PLam [simp]: "Init (PLam I F) = (\i \ I. lift_set i (Init (F i)))" paulson@13812: by (simp add: PLam_def lift_def lift_set_def) paulson@13786: paulson@13812: lemma PLam_empty [simp]: "PLam {} F = SKIP" paulson@13812: by (simp add: PLam_def) paulson@13786: paulson@13812: lemma PLam_SKIP [simp]: "(plam i : I. SKIP) = SKIP" wenzelm@46577: by (simp add: PLam_def JN_constant) paulson@13786: wenzelm@60773: lemma PLam_insert: "PLam (insert i I) F = (lift i (F i)) \ (PLam I F)" paulson@13786: by (unfold PLam_def, auto) paulson@13786: paulson@13805: lemma PLam_component_iff: "((PLam I F) \ H) = (\i \ I. lift i (F i) \ H)" paulson@13812: by (simp add: PLam_def JN_component_iff) paulson@13786: paulson@13805: lemma component_PLam: "i \ I ==> lift i (F i) \ (PLam I F)" paulson@13786: apply (unfold PLam_def) paulson@13786: (*blast_tac doesn't use HO unification*) paulson@13786: apply (fast intro: component_JN) paulson@13786: done paulson@13786: paulson@13786: paulson@13786: (** Safety & Progress: but are they used anywhere? **) paulson@13786: paulson@13812: lemma PLam_constrains: paulson@13812: "[| i \ I; \j. F j \ preserves snd |] wenzelm@61943: ==> (PLam I F \ (lift_set i (A \ UNIV)) co wenzelm@61943: (lift_set i (B \ UNIV))) = wenzelm@61943: (F i \ (A \ UNIV) co (B \ UNIV))" paulson@13812: apply (simp add: PLam_def JN_constrains) paulson@13786: apply (subst insert_Diff [symmetric], assumption) paulson@13812: apply (simp add: lift_constrains) paulson@13786: apply (blast intro: constrains_imp_lift_constrains) paulson@13786: done paulson@13786: paulson@13812: lemma PLam_stable: paulson@13812: "[| i \ I; \j. F j \ preserves snd |] wenzelm@61943: ==> (PLam I F \ stable (lift_set i (A \ UNIV))) = wenzelm@61943: (F i \ stable (A \ UNIV))" paulson@13812: by (simp add: stable_def PLam_constrains) paulson@13812: paulson@13812: lemma PLam_transient: paulson@13812: "i \ I ==> paulson@13812: PLam I F \ transient A = (\i \ I. lift i (F i) \ transient A)" paulson@13812: by (simp add: JN_transient PLam_def) paulson@13786: paulson@13812: text{*This holds because the @{term "F j"} cannot change @{term "lift_set i"}*} paulson@13812: lemma PLam_ensures: wenzelm@61943: "[| i \ I; F i \ (A \ UNIV) ensures (B \ UNIV); paulson@13812: \j. F j \ preserves snd |] wenzelm@61943: ==> PLam I F \ lift_set i (A \ UNIV) ensures lift_set i (B \ UNIV)" paulson@13812: apply (simp add: ensures_def PLam_constrains PLam_transient paulson@13812: lift_set_Un_distrib [symmetric] lift_set_Diff_distrib [symmetric] paulson@13812: Times_Un_distrib1 [symmetric] Times_Diff_distrib1 [symmetric]) paulson@13812: apply (rule rev_bexI, assumption) paulson@13812: apply (simp add: lift_transient) paulson@13786: done paulson@13786: paulson@13812: lemma PLam_leadsTo_Basis: paulson@13812: "[| i \ I; wenzelm@61943: F i \ ((A \ UNIV) - (B \ UNIV)) co wenzelm@61943: ((A \ UNIV) \ (B \ UNIV)); wenzelm@61943: F i \ transient ((A \ UNIV) - (B \ UNIV)); paulson@13812: \j. F j \ preserves snd |] wenzelm@61943: ==> PLam I F \ lift_set i (A \ UNIV) leadsTo lift_set i (B \ UNIV)" paulson@13786: by (rule PLam_ensures [THEN leadsTo_Basis], rule_tac [2] ensuresI) paulson@13786: paulson@13786: paulson@13786: paulson@13786: (** invariant **) paulson@13786: paulson@13812: lemma invariant_imp_PLam_invariant: wenzelm@61943: "[| F i \ invariant (A \ UNIV); i \ I; paulson@13812: \j. F j \ preserves snd |] wenzelm@61943: ==> PLam I F \ invariant (lift_set i (A \ UNIV))" paulson@13786: by (auto simp add: PLam_stable invariant_def) paulson@13786: paulson@13786: paulson@13786: lemma PLam_preserves_fst [simp]: paulson@13812: "\j. F j \ preserves snd paulson@13812: ==> (PLam I F \ preserves (v o sub j o fst)) = paulson@13805: (if j \ I then F j \ preserves (v o fst) else True)" paulson@13812: by (simp add: PLam_def lift_preserves_sub) paulson@13786: paulson@13786: lemma PLam_preserves_snd [simp,intro]: paulson@13805: "\j. F j \ preserves snd ==> PLam I F \ preserves snd" paulson@13812: by (simp add: PLam_def lift_preserves_snd_I) paulson@13786: paulson@13786: paulson@13786: paulson@13786: (*** guarantees properties ***) paulson@13786: paulson@14150: text{*This rule looks unsatisfactory because it refers to @{term lift}. paulson@14150: One must use paulson@14150: @{text lift_guarantees_eq_lift_inv} to rewrite the first subgoal and paulson@14150: something like @{text lift_preserves_sub} to rewrite the third. However paulson@14150: there's no obvious alternative for the third premise.*} paulson@13812: lemma guarantees_PLam_I: paulson@13812: "[| lift i (F i): X guarantees Y; i \ I; paulson@13812: OK I (%i. lift i (F i)) |] paulson@13805: ==> (PLam I F) \ X guarantees Y" paulson@13786: apply (unfold PLam_def) paulson@13812: apply (simp add: guarantees_JN_I) paulson@13786: done paulson@13786: paulson@13786: lemma Allowed_PLam [simp]: paulson@13805: "Allowed (PLam I F) = (\i \ I. lift i ` Allowed(F i))" paulson@13812: by (simp add: PLam_def) paulson@13786: paulson@13786: paulson@13786: lemma PLam_preserves [simp]: paulson@13805: "(PLam I F) \ preserves v = (\i \ I. F i \ preserves (v o lift_map i))" paulson@13805: by (simp add: PLam_def lift_def rename_preserves) paulson@13786: paulson@13786: paulson@13786: (**UNUSED paulson@13786: (*The f0 premise ensures that the product is well-defined.*) paulson@13812: lemma PLam_invariant_imp_invariant: paulson@13812: "[| PLam I F \ invariant (lift_set i A); i \ I; paulson@13805: f0: Init (PLam I F) |] ==> F i \ invariant A" paulson@13786: apply (auto simp add: invariant_def) paulson@13786: apply (drule_tac c = "f0 (i:=x) " in subsetD) paulson@13786: apply auto paulson@13786: done paulson@13786: paulson@13812: lemma PLam_invariant: paulson@13812: "[| i \ I; f0: Init (PLam I F) |] paulson@13805: ==> (PLam I F \ invariant (lift_set i A)) = (F i \ invariant A)" paulson@13786: apply (blast intro: invariant_imp_PLam_invariant PLam_invariant_imp_invariant) paulson@13786: done paulson@13786: paulson@13786: (*The f0 premise isn't needed if F is a constant program because then paulson@13786: we get an initial state by replicating that of F*) paulson@13812: lemma reachable_PLam: paulson@13812: "i \ I paulson@13805: ==> ((plam x \ I. F) \ invariant (lift_set i A)) = (F \ invariant A)" paulson@13786: apply (auto simp add: invariant_def) paulson@13786: done paulson@13786: **) paulson@13786: paulson@13786: paulson@13786: (**UNUSED paulson@13786: (** Reachability **) paulson@13786: paulson@13805: Goal "[| f \ reachable (PLam I F); i \ I |] ==> f i \ reachable (F i)" paulson@13786: apply (erule reachable.induct) paulson@13786: apply (auto intro: reachable.intrs) paulson@13786: done paulson@13786: paulson@13786: (*Result to justify a re-organization of this file*) paulson@13805: lemma "{f. \i \ I. f i \ R i} = (\i \ I. lift_set i (R i))" paulson@13798: by auto paulson@13786: paulson@13812: lemma reachable_PLam_subset1: paulson@13805: "reachable (PLam I F) \ (\i \ I. lift_set i (reachable (F i)))" paulson@13786: apply (force dest!: reachable_PLam) paulson@13786: done paulson@13786: paulson@13786: (*simplify using reachable_lift??*) paulson@13798: lemma reachable_lift_Join_PLam [rule_format]: paulson@13812: "[| i \ I; A \ reachable (F i) |] paulson@13812: ==> \f. f \ reachable (PLam I F) wenzelm@60773: --> f(i:=A) \ reachable (lift i (F i) \ PLam I F)" paulson@13786: apply (erule reachable.induct) paulson@13786: apply (ALLGOALS Clarify_tac) paulson@13786: apply (erule reachable.induct) paulson@13786: (*Init, Init case*) paulson@13786: apply (force intro: reachable.intrs) paulson@13786: (*Init of F, action of PLam F case*) paulson@13786: apply (rule_tac act = act in reachable.Acts) paulson@13786: apply force paulson@13786: apply assumption paulson@13786: apply (force intro: ext) paulson@13786: (*induction over the 2nd "reachable" assumption*) paulson@13786: apply (erule_tac xa = f in reachable.induct) paulson@13786: (*Init of PLam F, action of F case*) paulson@13786: apply (rule_tac act = "lift_act i act" in reachable.Acts) paulson@13786: apply force paulson@13786: apply (force intro: reachable.Init) paulson@13786: apply (force intro: ext simp add: lift_act_def) paulson@13786: (*last case: an action of PLam I F*) paulson@13786: apply (rule_tac act = acta in reachable.Acts) paulson@13786: apply force paulson@13786: apply assumption paulson@13786: apply (force intro: ext) paulson@13786: done paulson@13786: paulson@13786: paulson@13786: (*The index set must be finite: otherwise infinitely many copies of F can paulson@13786: perform actions, and PLam can never catch up in finite time.*) paulson@13812: lemma reachable_PLam_subset2: paulson@13812: "finite I paulson@13805: ==> (\i \ I. lift_set i (reachable (F i))) \ reachable (PLam I F)" paulson@13786: apply (erule finite_induct) paulson@13786: apply (simp (no_asm)) paulson@13786: apply (force dest: reachable_lift_Join_PLam simp add: PLam_insert) paulson@13786: done paulson@13786: paulson@13812: lemma reachable_PLam_eq: paulson@13812: "finite I ==> paulson@13805: reachable (PLam I F) = (\i \ I. lift_set i (reachable (F i)))" paulson@13786: apply (REPEAT_FIRST (ares_tac [equalityI, reachable_PLam_subset1, reachable_PLam_subset2])) paulson@13786: done paulson@13786: paulson@13786: paulson@13786: (** Co **) paulson@13786: paulson@13812: lemma Constrains_imp_PLam_Constrains: paulson@13812: "[| F i \ A Co B; i \ I; finite I |] paulson@13805: ==> PLam I F \ (lift_set i A) Co (lift_set i B)" paulson@13786: apply (auto simp add: Constrains_def Collect_conj_eq [symmetric] reachable_PLam_eq) paulson@13786: apply (auto simp add: constrains_def PLam_def) paulson@13786: apply (REPEAT (blast intro: reachable.intrs)) paulson@13786: done paulson@13786: paulson@13786: paulson@13786: paulson@13812: lemma PLam_Constrains: paulson@13812: "[| i \ I; finite I; f0: Init (PLam I F) |] paulson@13812: ==> (PLam I F \ (lift_set i A) Co (lift_set i B)) = paulson@13805: (F i \ A Co B)" paulson@13786: apply (blast intro: Constrains_imp_PLam_Constrains PLam_Constrains_imp_Constrains) paulson@13786: done paulson@13786: paulson@13812: lemma PLam_Stable: paulson@13812: "[| i \ I; finite I; f0: Init (PLam I F) |] paulson@13805: ==> (PLam I F \ Stable (lift_set i A)) = (F i \ Stable A)" paulson@13812: apply (simp del: Init_PLam add: Stable_def PLam_Constrains) paulson@13786: done paulson@13786: paulson@13786: paulson@13786: (** const_PLam (no dependence on i) doesn't require the f0 premise **) paulson@13786: paulson@13812: lemma const_PLam_Constrains: paulson@13812: "[| i \ I; finite I |] paulson@13812: ==> ((plam x \ I. F) \ (lift_set i A) Co (lift_set i B)) = paulson@13805: (F \ A Co B)" paulson@13786: apply (blast intro: Constrains_imp_PLam_Constrains const_PLam_Constrains_imp_Constrains) paulson@13786: done paulson@13786: paulson@13812: lemma const_PLam_Stable: paulson@13812: "[| i \ I; finite I |] paulson@13805: ==> ((plam x \ I. F) \ Stable (lift_set i A)) = (F \ Stable A)" paulson@13812: apply (simp add: Stable_def const_PLam_Constrains) paulson@13786: done paulson@13786: paulson@13812: lemma const_PLam_Increasing: wenzelm@32960: "[| i \ I; finite I |] paulson@13805: ==> ((plam x \ I. F) \ Increasing (f o sub i)) = (F \ Increasing f)" paulson@13786: apply (unfold Increasing_def) paulson@13805: apply (subgoal_tac "\z. {s. z \ (f o sub i) s} = lift_set i {s. z \ f s}") paulson@13786: apply (asm_simp_tac (simpset () add: lift_set_sub) 2) paulson@13786: apply (simp add: finite_lessThan const_PLam_Stable) paulson@13786: done paulson@13786: **) paulson@13786: paulson@13786: paulson@5899: end