| 
1465
 | 
     1  | 
(*  Title:      HOL/Hoare/Hoare.ML
  | 
| 
1335
 | 
     2  | 
    ID:         $Id$
  | 
| 
1465
 | 
     3  | 
    Author:     Norbert Galm & Tobias Nipkow
  | 
| 
1335
 | 
     4  | 
    Copyright   1995 TUM
  | 
| 
 | 
     5  | 
  | 
| 
 | 
     6  | 
The verification condition generation tactics.
  | 
| 
 | 
     7  | 
*)
  | 
| 
 | 
     8  | 
  | 
| 
 | 
     9  | 
open Hoare;
  | 
| 
 | 
    10  | 
  | 
| 
 | 
    11  | 
(*** Hoare rules ***)
  | 
| 
 | 
    12  | 
  | 
| 
1558
 | 
    13  | 
val SkipRule = prove_goalw thy [Spec_def,Skip_def]
  | 
| 
3842
 | 
    14  | 
  "(!!s. p(s) ==> q(s)) ==> Spec p Skip q"
  | 
| 
1875
 | 
    15  | 
  (fn prems => [fast_tac (!claset addIs prems) 1]);
  | 
| 
1335
 | 
    16  | 
  | 
| 
1558
 | 
    17  | 
val AssignRule = prove_goalw thy [Spec_def,Assign_def]
  | 
| 
3842
 | 
    18  | 
  "(!!s. p s ==> q(%x. if x=v then e s else s x)) ==> Spec p (Assign v e) q"
  | 
| 
1875
 | 
    19  | 
  (fn prems => [fast_tac (!claset addIs prems) 1]);
  | 
| 
1335
 | 
    20  | 
  | 
| 
1558
 | 
    21  | 
val SeqRule = prove_goalw thy [Spec_def,Seq_def]
  | 
| 
3842
 | 
    22  | 
  "[| Spec p c (%s. q s); Spec (%s. q s) c' r |] ==> Spec p (Seq c c') r"
  | 
| 
1875
 | 
    23  | 
  (fn prems => [cut_facts_tac prems 1, Fast_tac 1]);
  | 
| 
1335
 | 
    24  | 
  | 
| 
1558
 | 
    25  | 
val IfRule = prove_goalw thy [Spec_def,Cond_def]
  | 
| 
1335
 | 
    26  | 
  "[| !!s. p s ==> (b s --> q s) & (~b s --> q' s); \
  | 
| 
3842
 | 
    27  | 
\     Spec (%s. q s) c r; Spec (%s. q' s) c' r |] \
  | 
| 
1335
 | 
    28  | 
\  ==> Spec p (Cond b c c') r"
  | 
| 
 | 
    29  | 
  (fn [prem1,prem2,prem3] =>
  | 
| 
 | 
    30  | 
     [REPEAT (rtac allI 1),
  | 
| 
 | 
    31  | 
      REPEAT (rtac impI 1),
  | 
| 
1465
 | 
    32  | 
      dtac prem1 1,
  | 
| 
1335
 | 
    33  | 
      cut_facts_tac [prem2,prem3] 1,
  | 
| 
1875
 | 
    34  | 
      fast_tac (!claset addIs [prem1]) 1]);
  | 
| 
1335
 | 
    35  | 
  | 
| 
1558
 | 
    36  | 
val strenthen_pre = prove_goalw thy [Spec_def]
  | 
| 
1335
 | 
    37  | 
  "[| !!s. p s ==> p' s; Spec p' c q |] ==> Spec p c q"
  | 
| 
 | 
    38  | 
  (fn [prem1,prem2] =>[cut_facts_tac [prem2] 1,
  | 
| 
1875
 | 
    39  | 
                       fast_tac (!claset addIs [prem1]) 1]);
  | 
| 
1335
 | 
    40  | 
  | 
| 
1558
 | 
    41  | 
val lemma = prove_goalw thy [Spec_def,While_def]
  | 
| 
3842
 | 
    42  | 
  "[| Spec (%s. I s & b s) c I; !!s. [| I s; ~b s |] ==> q s |] \
  | 
| 
2901
 | 
    43  | 
\  ==> Spec I (While b I c) q"
  | 
| 
1335
 | 
    44  | 
  (fn [prem1,prem2] =>
  | 
| 
 | 
    45  | 
     [REPEAT(rtac allI 1), rtac impI 1, etac exE 1, rtac mp 1, atac 2,
  | 
| 
 | 
    46  | 
      etac thin_rl 1, res_inst_tac[("x","s")]spec 1,
 | 
| 
 | 
    47  | 
      res_inst_tac[("x","s'")]spec 1, nat_ind_tac "n" 1,
 | 
| 
2901
 | 
    48  | 
      Simp_tac 1,
  | 
| 
1875
 | 
    49  | 
      fast_tac (!claset addIs [prem2]) 1,
  | 
| 
2901
 | 
    50  | 
      simp_tac (!simpset addsimps [Seq_def]) 1,
  | 
| 
1875
 | 
    51  | 
      cut_facts_tac [prem1] 1, fast_tac (!claset addIs [prem2]) 1]);
  | 
| 
1335
 | 
    52  | 
  | 
| 
 | 
    53  | 
val WhileRule = lemma RSN (2,strenthen_pre);
  | 
| 
 | 
    54  | 
  | 
| 
 | 
    55  | 
  | 
| 
 | 
    56  | 
(*** meta_spec used in StateElimTac ***)
  | 
| 
 | 
    57  | 
  | 
| 
 | 
    58  | 
val meta_spec = prove_goal HOL.thy
  | 
| 
 | 
    59  | 
  "(!!s x. PROP P s x) ==> (!!s. PROP P s (x s))"
  | 
| 
 | 
    60  | 
  (fn prems => [resolve_tac prems 1]);
  | 
| 
 | 
    61  | 
  | 
| 
 | 
    62  | 
  | 
| 
 | 
    63  | 
(**************************************************************************************************)
  | 
| 
 | 
    64  | 
(*** Funktion zum Generieren eines Theorems durch Umbennenen von Namen von Lambda-Abstraktionen ***)
  | 
| 
 | 
    65  | 
(*** in einem bestehenden Theorem. Bsp.: "!a.?P(a) ==> ?P(?x)" aus "!x.?P(x) ==> ?P(?x)"        ***)
  | 
| 
 | 
    66  | 
(**************************************************************************************************)
  | 
| 
 | 
    67  | 
  | 
| 
 | 
    68  | 
(* rename_abs:term (von:string,nach:string,trm:term) benennt in trm alle Lambda-Abstraktionen
  | 
| 
 | 
    69  | 
   mit Namen von in nach um *)
  | 
| 
 | 
    70  | 
  | 
| 
3537
 | 
    71  | 
fun rename_abs (von,nach,Abs (s,t,trm)) =
  | 
| 
 | 
    72  | 
    if von=s
  | 
| 
 | 
    73  | 
	then Abs (nach,t,rename_abs (von,nach,trm))
  | 
| 
 | 
    74  | 
        else Abs (s,t,rename_abs (von,nach,trm))
  | 
| 
1465
 | 
    75  | 
  | rename_abs (von,nach,trm1 $ trm2)   =rename_abs (von,nach,trm1) $ rename_abs (von,nach,trm2)
  | 
| 
 | 
    76  | 
  | rename_abs (_,_,trm)                =trm;
  | 
| 
1335
 | 
    77  | 
  | 
| 
 | 
    78  | 
(* ren_abs_thm:thm (von:string,nach:string,theorem:thm) benennt in theorem alle Lambda-Abstraktionen
  | 
| 
 | 
    79  | 
   mit Namen von in nach um. Vorgehen:
  | 
| 
1465
 | 
    80  | 
        - Term t zu thoerem bestimmen
  | 
| 
 | 
    81  | 
        - Term t' zu t durch Umbenennen der Namen generieren
  | 
| 
 | 
    82  | 
        - Certified Term ct' zu t' erstellen
  | 
| 
 | 
    83  | 
        - Thoerem ct'==ct' anlegen
  | 
| 
 | 
    84  | 
        - Nach der Regel "[|P==Q; P|] ==> Q" wird aus "ct'==ct'" und theorem das Theorem zu ct'
  | 
| 
 | 
    85  | 
          abgeleitet (ist moeglich, da t' mit t unifiziert werden kann, da nur Umnbenennungen) *)
  | 
| 
1335
 | 
    86  | 
  | 
| 
1465
 | 
    87  | 
fun ren_abs_thm (von,nach,theorem)      =
  | 
| 
 | 
    88  | 
        equal_elim
  | 
| 
3537
 | 
    89  | 
                (reflexive (cterm_of (#sign (rep_thm theorem))
  | 
| 
 | 
    90  | 
			    (rename_abs (von,nach,#prop (rep_thm theorem)))))
  | 
| 
1465
 | 
    91  | 
                theorem;
  | 
| 
1335
 | 
    92  | 
  | 
| 
 | 
    93  | 
  | 
| 
3537
 | 
    94  | 
(****************************************************************************)
  | 
| 
 | 
    95  | 
(*** Taktik zum Anwenden eines Theorems theorem auf ein Subgoal i durch   ***)
  | 
| 
 | 
    96  | 
(***  - Umbenennen von Lambda-Abstraktionen im Theorem                    ***)
  | 
| 
 | 
    97  | 
(***  - Instanziieren von freien Variablen im Theorem                     ***)
  | 
| 
 | 
    98  | 
(***  - Composing des Subgoals mit dem Theorem                            ***)
  | 
| 
 | 
    99  | 
(****************************************************************************)
  | 
| 
1335
 | 
   100  | 
  | 
| 
 | 
   101  | 
(* - rens:(string*string) list, d.h. es koennen verschiedene Lambda-Abstraktionen umbenannt werden
  | 
| 
 | 
   102  | 
   - insts:(cterm*cterm) list, d.h. es koennen verschiedene Variablen instanziiert werden *)
  | 
| 
 | 
   103  | 
  | 
| 
1465
 | 
   104  | 
fun comp_inst_ren_tac rens insts theorem i      =
  | 
| 
3537
 | 
   105  | 
        let fun compose_inst_ren_tac [] insts theorem i                     =
  | 
| 
 | 
   106  | 
	      compose_tac (false,
  | 
| 
 | 
   107  | 
			   cterm_instantiate insts theorem,nprems_of theorem) i
  | 
| 
 | 
   108  | 
	      | compose_inst_ren_tac ((von,nach)::rl) insts theorem i       =
  | 
| 
 | 
   109  | 
                        compose_inst_ren_tac rl insts 
  | 
| 
 | 
   110  | 
			  (ren_abs_thm (von,nach,theorem)) i
  | 
| 
 | 
   111  | 
        in  compose_inst_ren_tac rens insts theorem i  end;
  | 
| 
1335
 | 
   112  | 
  | 
| 
 | 
   113  | 
  | 
| 
3537
 | 
   114  | 
(***************************************************************    *********)
  | 
| 
1335
 | 
   115  | 
(*** Taktik zum Eliminieren des Zustandes waehrend Hoare-Beweisen                               ***)
  | 
| 
 | 
   116  | 
(***    Bsp.: "!!s. s(Suc(0))=0 --> s(Suc(0))+1=1" wird zu "!!s b. b=0 --> b+1=1"               ***)
  | 
| 
3537
 | 
   117  | 
(****************************************************************************)
  | 
| 
1335
 | 
   118  | 
  | 
| 
 | 
   119  | 
(* pvars_of_term:term list (name:string,trm:term) gibt die Liste aller Programm-Variablen
  | 
| 
 | 
   120  | 
   aus trm zurueck. name gibt dabei den Namen der Zustandsvariablen an.
  | 
| 
1465
 | 
   121  | 
        Bsp.: bei name="s" und dem Term "s(Suc(Suc(0)))=s(0)" (entspricht "c=a")
  | 
| 
 | 
   122  | 
              wird [0,Suc(Suc(0))] geliefert (Liste ist i.A. unsortiert) *)
  | 
| 
1335
 | 
   123  | 
  | 
| 
1465
 | 
   124  | 
fun pvars_of_term (name,trm)    =
  | 
| 
3537
 | 
   125  | 
  let fun add_vars (name,Free (s,t) $ trm,vl) =
  | 
| 
 | 
   126  | 
            if name=s then if trm mem vl then vl else trm::vl
  | 
| 
 | 
   127  | 
                      else add_vars (name,trm,vl)
  | 
| 
 | 
   128  | 
	| add_vars (name,Abs (s,t,trm),vl)    =add_vars (name,trm,vl)
  | 
| 
 | 
   129  | 
	| add_vars (name,trm1 $ trm2,vl)      =add_vars (name,trm2,add_vars (name,trm1,vl))
  | 
| 
 | 
   130  | 
	| add_vars (_,_,vl)                   =vl
  | 
| 
 | 
   131  | 
  in add_vars (name,trm,[]) end;
  | 
| 
 | 
   132  | 
  | 
| 
1335
 | 
   133  | 
  | 
| 
 | 
   134  | 
(* VarsElimTac: Taktik zum Eliminieren von bestimmten Programmvariablen aus dem Subgoal i
  | 
| 
3537
 | 
   135  | 
 - v::vl:(term) list  Liste der zu eliminierenden Programmvariablen
  | 
| 
 | 
   136  | 
 - meta_spec:thm      Theorem, welches zur Entfernung der Variablen benutzt wird
  | 
| 
3842
 | 
   137  | 
		      z.B.: "(!!s x. PROP P(s,x)) ==> (!!s. PROP P(s,x(s)))"
  | 
| 
3537
 | 
   138  | 
 - namexAll:string    Name von    ^                                  (hier "x")
  | 
| 
 | 
   139  | 
 - varx:term          Term zu                                      ^ (hier Var(("x",0),...))
 | 
| 
 | 
   140  | 
 - varP:term          Term zu                                  ^     (hier Var(("P",0),...))
 | 
| 
 | 
   141  | 
 - type_pvar:typ      Typ der Programmvariablen (d.h. 'a bei 'a prog, z.B.: nat, bool, ...)
  | 
| 
1335
 | 
   142  | 
  | 
| 
3537
 | 
   143  | 
 Vorgehen:
  | 
| 
 | 
   144  | 
      - eliminiere jede pvar durch Anwendung von comp_inst_ren_tac. Dazu:
  | 
| 
 | 
   145  | 
      - Unbenennung in meta_spec: namexAll wird in den Namen der Prog.-Var. umbenannt
  | 
| 
 | 
   146  | 
	z.B.: fuer die Prog.-Var. mit Namen "a" ergibt sich
  | 
| 
3842
 | 
   147  | 
	      meta_spec zu "(!! s a. PROP P(s,a)) ==> (!! s. PROP P(s,x(s)))"
  | 
| 
3537
 | 
   148  | 
      - Instanziierungen in meta_spec:
  | 
| 
3842
 | 
   149  | 
	      varx wird mit "%s:(type_pvar) state. s(pvar)" instanziiert
  | 
| 
3537
 | 
   150  | 
	      varP wird entsprechend instanziiert. Beispiel fuer Prog.-Var. "a":
  | 
| 
3842
 | 
   151  | 
	 - zu Subgoal "!!s. s(Suc(0)) = s(0) ==> s(0) = 1" bestimme Term ohne "!!s.":
  | 
| 
3537
 | 
   152  | 
		trm0 = "s(Suc(0)) = s(0) ==> s(0) = 1" (s ist hier freie Variable)
  | 
| 
 | 
   153  | 
	 - substituiere alle Vorkommen von s(pvar) durch eine freie Var. xs:
  | 
| 
 | 
   154  | 
		trm1 = "s(Suc(0)) = xs ==> xs = 1"
  | 
| 
 | 
   155  | 
	 - abstrahiere ueber xs:
  | 
| 
3842
 | 
   156  | 
		trm2 = "%xs. s(Suc(0)) = xs ==> xs = 1"
  | 
| 
3537
 | 
   157  | 
	 - abstrahiere ueber restliche Vorkommen von s:
  | 
| 
3842
 | 
   158  | 
		trm3 = "%s xs. s(Suc(0)) = xs ==> xs = 1"
  | 
| 
3537
 | 
   159  | 
	 - instanziiere varP mit trm3
  | 
| 
1335
 | 
   160  | 
*)
  | 
| 
 | 
   161  | 
  | 
| 
3537
 | 
   162  | 
(* StateElimTac: tactic to eliminate all program variable from subgoal i
  | 
| 
3842
 | 
   163  | 
    - applies to subgoals of the form "!!s:('a) state. P(s)",
 | 
| 
3537
 | 
   164  | 
        i.e. the term  Const("all",_) $ Abs ("s",pvar --> 'a,_)
 | 
| 
3842
 | 
   165  | 
    -   meta_spec has the form "(!!s x. PROP P(s,x)) ==> (!!s. PROP P(s,x(s)))"
  | 
| 
1335
 | 
   166  | 
*)
  | 
| 
 | 
   167  | 
  | 
| 
3537
 | 
   168  | 
val StateElimTac = SUBGOAL (fn (Bi,i) =>
  | 
| 
 | 
   169  | 
  let val Const _ $ Abs (_,Type ("fun",[_,type_pvar]),trm) = Bi
 | 
| 
 | 
   170  | 
      val _ $ (_ $ Abs (_,_,_ $ Abs (namexAll,_,_))) $
  | 
| 
 | 
   171  | 
			    (_ $ Abs (_,_,varP $ _ $ (varx $ _))) = 
  | 
| 
 | 
   172  | 
			    #prop (rep_thm meta_spec)
  | 
| 
 | 
   173  | 
      fun vtac v i st = st |>
  | 
| 
 | 
   174  | 
	  let val cterm = cterm_of (#sign (rep_thm st))
  | 
| 
 | 
   175  | 
	      val (_,_,_ $ Abs (_,_,trm),_) = dest_state (st,i);
  | 
| 
 | 
   176  | 
	      val (sname,trm0) = variant_abs ("s",dummyT,trm);
 | 
| 
 | 
   177  | 
	      val xsname = variant_name ("xs",trm0);
 | 
| 
 | 
   178  | 
	      val trm1 = subst_term (Free (sname,dummyT) $ v,
  | 
| 
 | 
   179  | 
				     Syntax.free xsname,trm0)
  | 
| 
 | 
   180  | 
	      val trm2 = Abs ("xs", type_pvar,
 | 
| 
 | 
   181  | 
			      abstract_over (Syntax.free xsname,trm1))
  | 
| 
 | 
   182  | 
	  in
  | 
| 
 | 
   183  | 
	      comp_inst_ren_tac
  | 
| 
 | 
   184  | 
		[(namexAll,pvar2pvarID v)]
  | 
| 
 | 
   185  | 
		[(cterm varx,
  | 
| 
 | 
   186  | 
		  cterm (Abs  ("s",Type ("nat",[]) --> type_pvar,
 | 
| 
 | 
   187  | 
			       Bound 0 $ v))),
  | 
| 
 | 
   188  | 
		 (cterm varP,
  | 
| 
 | 
   189  | 
		  cterm (Abs ("s", Type ("nat",[]) --> type_pvar,
 | 
| 
 | 
   190  | 
			      abstract_over (Free (sname,dummyT),trm2))))]
  | 
| 
 | 
   191  | 
		meta_spec i
  | 
| 
 | 
   192  | 
	  end
  | 
| 
 | 
   193  | 
      fun vars_tac [] i      = all_tac
  | 
| 
 | 
   194  | 
	| vars_tac (v::vl) i = vtac v i THEN vars_tac vl i
  | 
| 
 | 
   195  | 
  in
  | 
| 
 | 
   196  | 
      vars_tac (pvars_of_term (variant_abs ("s",dummyT,trm))) i
 | 
| 
 | 
   197  | 
  end);
  | 
| 
1335
 | 
   198  | 
  | 
| 
 | 
   199  | 
  | 
| 
 | 
   200  | 
(*** tactics for verification condition generation ***)
  | 
| 
 | 
   201  | 
  | 
| 
 | 
   202  | 
(* pre_cond:bool gibt an, ob das Subgoal von der Form Spec(?Q,c,p) ist oder nicht. Im Fall
  | 
| 
 | 
   203  | 
   von pre_cond=false besteht die Vorbedingung nur nur aus einer scheme-Variable. Die dann
  | 
| 
 | 
   204  | 
   generierte Verifikationsbedingung hat die Form "!!s.?Q --> ...". "?Q" kann deshalb zu gegebenen
  | 
| 
 | 
   205  | 
   Zeitpunkt mittels "rtac impI" und "atac" gebunden werden, die Bedingung loest sich dadurch auf. *)
  | 
| 
 | 
   206  | 
  | 
| 
 | 
   207  | 
fun WlpTac i = (rtac SeqRule i) THEN (HoareRuleTac (i+1) false)
  | 
| 
3537
 | 
   208  | 
and HoareRuleTac i pre_cond st = st |>  
  | 
| 
 | 
   209  | 
	(*abstraction over st prevents looping*)
  | 
| 
 | 
   210  | 
    ( (WlpTac i THEN HoareRuleTac i pre_cond)
  | 
| 
 | 
   211  | 
      ORELSE
  | 
| 
 | 
   212  | 
      (FIRST[rtac SkipRule i,
  | 
| 
 | 
   213  | 
	     rtac AssignRule i,
  | 
| 
 | 
   214  | 
	     EVERY[rtac IfRule i,
  | 
| 
 | 
   215  | 
		   HoareRuleTac (i+2) false,
  | 
| 
 | 
   216  | 
		   HoareRuleTac (i+1) false],
  | 
| 
 | 
   217  | 
	     EVERY[rtac WhileRule i,
  | 
| 
 | 
   218  | 
		   Asm_full_simp_tac (i+2),
  | 
| 
 | 
   219  | 
		   HoareRuleTac (i+1) true]]
  | 
| 
 | 
   220  | 
       THEN
  | 
| 
 | 
   221  | 
       (if pre_cond then (Asm_full_simp_tac i) else (atac i))) );
  | 
| 
1335
 | 
   222  | 
  | 
| 
3537
 | 
   223  | 
val hoare_tac = 
  | 
| 
 | 
   224  | 
  SELECT_GOAL
  | 
| 
 | 
   225  | 
    (EVERY[HoareRuleTac 1 true, ALLGOALS StateElimTac, prune_params_tac]);
  | 
| 
1335
 | 
   226  | 
  |