src/HOL/TLA/Action.ML
author paulson
Wed, 24 Dec 1997 10:02:30 +0100
changeset 4477 b3e5857d8d99
parent 4089 96fba19bcbe2
child 6255 db63752140c7
permissions -rw-r--r--
New Auto_tac (by Oheimb), and new syntax (without parens), and expandshort

(* 
    File:	 Action.ML
    Author:      Stephan Merz
    Copyright:   1997 University of Munich

Lemmas and tactics for TLA actions.
*)

val act_rews = [pairSF_def RS eq_reflection,unl_before,unl_after,unchanged_def,
                pr_con,pr_before,pr_lift,pr_lift2,pr_lift3,pr_all,pr_ex];

val action_rews = act_rews @ intensional_rews;

qed_goal "actionI" Action.thy "(!!s t. ([[s,t]] |= A)) ==> A"
  (fn [prem] => [REPEAT (resolve_tac [prem,intI,state2_ext] 1)]);

qed_goal "actionD" Action.thy "A ==> ([[s,t]] |= A)"
  (fn [prem] => [REPEAT (resolve_tac [prem,intD] 1)]);



(* ================ Functions to "unlift" action theorems into HOL rules ================ *)

(* Basic unlifting introduces a world parameter and applies basic rewrites, e.g.
   A .= B    gets   ([[s,t]] |= A) = ([[s,t]] |= B)
   A .-> B   gets   ([[s,t]] |= A) --> ([[s,t]] |= B)
*)
fun action_unlift th = rewrite_rule action_rews (th RS actionD);

(* A .-> B   becomes   A [[s,t]] ==> B [[s,t]] *)
fun action_mp th = zero_var_indexes ((action_unlift th) RS mp);

(* A .-> B   becomes   [| A[[s,t]]; B[[s,t]] ==> R |] ==> R 
   so that it can be used as an elimination rule
*)
fun action_impE th = zero_var_indexes ((action_unlift th) RS impE);

(* A .& B .-> C  becomes  [| A[[s,t]]; B[[s,t]] |] ==> C[[s,t]] *)
fun action_conjmp th = zero_var_indexes (conjI RS (action_mp th));

(* A .& B .-> C  becomes  [| A[[s,t]]; B[[s,t]]; (C[[s,t]] ==> R) |] ==> R *)
fun action_conjimpE th = zero_var_indexes (conjI RS (action_impE th));

(* Turn  A .= B  into meta-level rewrite rule  A == B *)
fun action_rewrite th = (rewrite_rule action_rews (th RS inteq_reflection));

(* ===================== Update simpset and classical prover ============================= *)

(* Make the simplifier use action_unlift rather than int_unlift 
   when action simplifications are added.
*)
fun maybe_unlift th =
    (case concl_of th of
         Const("Intensional.TrueInt",_) $ p 
           => (action_unlift th
                  handle _ => int_unlift th)
       | _ => th);

simpset_ref() := simpset() setmksimps ((mksimps mksimps_pairs) o maybe_unlift);

(* make act_rews be always active -- intensional_rews has been added before *)
Addsimps act_rews;

use "cladata.ML";        (* local version! *)

(* ================================ action_simp_tac ================================== *)

(* A dumb simplification tactic with just a little first-order logic:
   should plug in only "very safe" rules that can be applied blindly.
   Note that it applies whatever simplifications are currently active.
*)
fun action_simp_tac ss intros elims i =
    (asm_full_simp_tac 
         (ss setloop ((resolve_tac (intros @ [refl,impI,conjI,actionI,allI]))
		      ORELSE' (eresolve_tac (elims @ [conjE,disjE,exE_prop]))))
         i);
(* default version without additional plug-in rules *)
fun Action_simp_tac i = (action_simp_tac (simpset()) [] [] i);


(* ==================== Simplification of abstractions ==================== *)

(* Somewhat obscure simplifications, rarely necessary to get rid
   of abstractions that may be introduced by higher-order unification.
*)

qed_goal "pr_con_abs" Action.thy "(%w. c)` .= #c"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac (con_abs::action_rews),
            rtac refl 1
           ]);

qed_goal "pr_lift_abs" Action.thy "(%w. f(x w))` .= f[x`]"
  (fn _ => [rtac actionI 1,
              (* give all rewrites to the engine and it loops! *)
            rewrite_goals_tac intensional_rews,
            rewtac lift_abs,
            rewtac pr_lift,
            rewtac unl_lift,
            rtac refl 1
           ]);

qed_goal "pr_lift2_abs" Action.thy "(%w. f(x w) (y w))` .= f[x`,y`]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift2_abs,
            rewtac pr_lift2,
            rewtac unl_lift2,
            rtac refl 1
           ]);

qed_goal "pr_lift2_abs_con1" Action.thy "(%w. f x (y w))` .= f[#x, y`]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift2_abs_con1,
            rewtac pr_lift2,
            rewtac unl_lift2,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift2_abs_con2" Action.thy "(%w. f (x w) y)` .= f[x`, #y]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift2_abs_con2,
            rewtac pr_lift2,
            rewtac unl_lift2,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs" Action.thy "(%w. f(x w) (y w) (z w))` .= f[x`,y`,z`]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs_con1" Action.thy "(%w. f x (y w) (z w))` .= f[#x, y`, z`]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs_con1,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs_con2" Action.thy "(%w. f (x w) y (z w))` .= f[x`, #y, z`]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs_con2,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs_con3" Action.thy "(%w. f (x w) (y w) z)` .= f[x`, y`, #z]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs_con3,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs_con12" Action.thy "(%w. f x y (z w))` .= f[#x, #y, z`]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs_con12,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs_con13" Action.thy "(%w. f x (y w) z)` .= f[#x, y`, #z]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs_con13,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

qed_goal "pr_lift3_abs_con23" Action.thy "(%w. f (x w) y z)` .= f[x`, #y, #z]"
  (fn _ => [rtac actionI 1,
            rewrite_goals_tac intensional_rews,
            rewtac lift3_abs_con23,
            rewtac pr_lift3,
            rewtac unl_lift3,
            rewtac pr_con,
            rewtac unl_con,
            rtac refl 1
           ]);

(* We don't add these as default rewrite rules, because they are
   rarely needed and may slow down automatic proofs.
*)
val pr_abs_rews = map (fn th => th RS inteq_reflection) 
                      [pr_con_abs,
                       pr_lift_abs,pr_lift2_abs,pr_lift2_abs_con1,pr_lift2_abs_con2,
                       pr_lift3_abs,pr_lift3_abs_con1,pr_lift3_abs_con2,pr_lift3_abs_con3,
                       pr_lift3_abs_con12,pr_lift3_abs_con13,pr_lift3_abs_con23];

(* =========================== square / angle brackets =========================== *)

qed_goalw "idle_squareI" Action.thy [square_def]
   "!!s t. ([[s,t]] |= unchanged v) ==> ([[s,t]] |= [A]_v)"
   (fn _ => [ Auto_tac ]);

qed_goalw "busy_squareI" Action.thy [square_def]
   "!!s t. ([[s,t]] |= A) ==> ([[s,t]] |= [A]_v)"
   (fn _ => [ Auto_tac ]);

qed_goalw "square_simulation" Action.thy [square_def]
   "[| unchanged f .& .~B .-> unchanged g;   \
\      A .& .~unchanged g .-> B              \
\   |] ==> [A]_f .-> [B]_g"
   (fn [p1,p2] => [Auto_tac,
                   etac (action_conjimpE p2) 1,
                   etac swap 3, etac (action_conjimpE p1) 3,
                   ALLGOALS atac
                  ]);
                   
qed_goalw "not_square" Action.thy [square_def,angle_def]
   "(.~ [A]_v) .= <.~A>_v"
   (fn _ => [ Auto_tac ]);

qed_goalw "not_angle" Action.thy [square_def,angle_def]
   "(.~ <A>_v) .= [.~A]_v"
   (fn _ => [ Auto_tac ]);

(* ============================== Facts about ENABLED ============================== *)

qed_goalw "enabledI" Action.thy [enabled_def]
  "A [[s,t]] ==> (Enabled A) s"
  (fn prems => [ REPEAT (resolve_tac (exI::prems) 1) ]);

qed_goalw "enabledE" Action.thy [enabled_def]
  "[| (Enabled A) s; !!u. A[[s,u]] ==> PROP R |] ==> PROP R"
  (fn prems => [cut_facts_tac prems 1,
                etac exE_prop 1,
                resolve_tac prems 1, atac 1
               ]);

qed_goal "notEnabledD" Action.thy
  "!!G. ~ (Enabled G s) ==> ~ G [[s,t]]"
  (fn _ => [ auto_tac (action_css addsimps2 [enabled_def]) ]);

(* Monotonicity *)
qed_goal "enabled_mono" Action.thy
  "[| (Enabled F) s; F .-> G |] ==> (Enabled G) s"
  (fn [min,maj] => [rtac (min RS enabledE) 1,
                    rtac enabledI 1,
                    etac (action_mp maj) 1
                   ]);

(* stronger variant *)
qed_goal "enabled_mono2" Action.thy
   "[| (Enabled F) s; !!t. (F [[s,t]] ==> G[[s,t]] ) |] ==> (Enabled G) s"
   (fn [min,maj] => [rtac (min RS enabledE) 1,
		     rtac enabledI 1,
		     etac maj 1
		    ]);

qed_goal "enabled_disj1" Action.thy
  "!!s. (Enabled F) s ==> (Enabled (F .| G)) s"
  (fn _ => [etac enabled_mono 1, Auto_tac
	   ]);

qed_goal "enabled_disj2" Action.thy
  "!!s. (Enabled G) s ==> (Enabled (F .| G)) s"
  (fn _ => [etac enabled_mono 1, Auto_tac
	   ]);

qed_goal "enabled_conj1" Action.thy
  "!!s. (Enabled (F .& G)) s ==> (Enabled F) s"
  (fn _ => [etac enabled_mono 1, Auto_tac
           ]);

qed_goal "enabled_conj2" Action.thy
  "!!s. (Enabled (F .& G)) s ==> (Enabled G) s"
  (fn _ => [etac enabled_mono 1, Auto_tac
           ]);

qed_goal "enabled_conjE" Action.thy
  "[| (Enabled (F .& G)) s; [| (Enabled F) s; (Enabled G) s |] ==> PROP R |] ==> PROP R"
  (fn prems => [cut_facts_tac prems 1, resolve_tac prems 1,
                etac enabled_conj1 1, etac enabled_conj2 1]);

qed_goal "enabled_disjD" Action.thy
  "!!s. (Enabled (F .| G)) s ==> ((Enabled F) s) | ((Enabled G) s)"
  (fn _ => [etac enabledE 1,
            auto_tac (action_css addSDs2 [notEnabledD] addSEs2 [enabledI])
           ]);

qed_goal "enabled_disj" Action.thy
  "(Enabled (F .| G)) s = ( (Enabled F) s | (Enabled G) s )"
  (fn _ => [rtac iffI 1,
            etac enabled_disjD 1,
            REPEAT (eresolve_tac [disjE,enabled_disj1,enabled_disj2] 1)
           ]);

qed_goal "enabled_ex" Action.thy
  "(Enabled (REX x. F x)) s = (EX x. (Enabled (F x)) s)"
  (fn _ => [ auto_tac (action_css addsimps2 [enabled_def]) ]);
	    

(* A rule that combines enabledI and baseE, but generates fewer possible instantiations *)
qed_goal "base_enabled" Action.thy
  "[| base_var(v); !!u. v u = c s ==> A [[s,u]] |] ==> Enabled A s"
  (fn prems => [cut_facts_tac prems 1,
		etac baseE 1, rtac enabledI 1,
		REPEAT (ares_tac prems 1)]);


(* ---------------- enabled_tac: tactic to prove (Enabled A) -------------------- *)
(* "Enabled A" can be proven as follows:
   - Assume that we know which state variables are "base variables";
     this should be expressed by a theorem of the form "base_var <x,y,z,...>".
   - Resolve this theorem with baseE to introduce a constant for the value of the
     variables in the successor state, and resolve the goal with the result.
   - E-resolve with PairVarE so that we have one constant per variable.
   - Resolve with enabledI and do some rewriting.
   - Solve for the unknowns using standard HOL reasoning.
   The following tactic combines these steps except the final one.
*)

fun enabled_tac base_vars i =
    EVERY [(* apply actionI (plus rewriting) if the goal is of the form $(Enabled A),
	      do nothing if it is of the form (Enabled A) s *)
	   TRY ((rtac actionI i) THEN (SELECT_GOAL (rewrite_goals_tac action_rews) i)),
	   rtac (base_vars RS base_enabled) i,
	   REPEAT_DETERM (etac PairVarE i),
	   (SELECT_GOAL (rewrite_goals_tac action_rews) i)
	  ];

(* Example of use:

val [prem] = goal Action.thy "base_var <x,y,z> ==> $x .-> $Enabled ($x .& (y$ .= #False))";
by (REPEAT ((CHANGED (Action_simp_tac 1)) ORELSE (enabled_tac prem 1)));

*)