This file is indexed.

/usr/share/hol88-2.02.19940316/contrib/rule-induction/opsem.ml is in hol88-contrib-source 2.02.19940316-19.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
% ===================================================================== %
% FILE		: opsem.ml						%
% DESCRIPTION   : Creates a theory of the syntax and operational 	%
% 		  semantics of a very simple imperative programming 	%
% 		  language.  Illustrates the inductive definitions 	%
% 		  package with proofs that the evaluation relation for	%
%		  the given semantics is deterministic and that the 	%
%		  Hoare-logic rule for while loops follows from a 	%
%		  suitable definition of partial correctness.		%
%									%
% AUTHORS	: Tom Melham and Juanito Camilleri			%
% DATE		: 91.10.09						%
% ===================================================================== %

% --------------------------------------------------------------------- %
% Open a new theory and load the required libraries.			%
% --------------------------------------------------------------------- %

new_theory `opsem`;;

load_library `string`;;

load_library `ind_defs`;;

% ===================================================================== %
% Syntax of the programming language.					%
% ===================================================================== %

% --------------------------------------------------------------------- %
% Program variables will be represented by strings, and states will be  %
% modelled by functions from program variables to natural numbers.	%
% --------------------------------------------------------------------- %

new_type_abbrev (`state`, ":string->num");;

% --------------------------------------------------------------------- %
% Natural number expressions and boolean expressions will just be 	%
% modelled by total functions from states to numbers and booleans       %
% respectively.  This simplification allows us to concentrate in this   %
% example on defining the semantics of commands.			%
% --------------------------------------------------------------------- %

new_type_abbrev(`nexp`, ":state->num");;
new_type_abbrev(`bexp`, ":state->bool");;

% --------------------------------------------------------------------- %
% We can now use the recursive types package to define the syntax of    %
% commands (or `programs').  We have the following types of commands:   %
%									%
%    C ::=   skip                     (does nothing)			%
%          | V := E                   (assignment)          		%
%          | C1 ; C2                  (sequencing)           		%
%          | if B then C1 else C2     (conditional)			%
%          | while B do C             (repetition)			%
%                                                                       %
% where V ranges over program varibles, E ranges over natural number	%
% expressions, B ranges over boolean expressions, and C, C1 and C2      %
% range over commands.  						%
%									%
% In the logic, we represent this abstract syntax with a set of prefix  %
% type constructors. So we have:					%
%						                        %
%    V := E                  represented by "assign V E"		%
%    C1 ; C2                 represented by "seq C1 C2"			%
%    if B then C1 else C2    represented by "if B C1 C2"		%
%    while B do C            represented by "while B C"			%
%									%
% For notational clarity, we later introduce two constants := and ; as 	%
% infix abbreviations for assign and seq.  This can't be done here just %
% because define_type doesn't suppport infix constructors.  		%
% --------------------------------------------------------------------- %

let comm = 
    define_type `comm`
    `comm =   skip
            | assign string nexp
	    | seq comm comm        
            | if bexp comm comm    
	    | while bexp comm`;;


% --------------------------------------------------------------------- %
% Define an infix function `:=' for assignment.				%
% --------------------------------------------------------------------- %

let assign_def = 
    new_infix_definition 
    (`assign_def`,"$:= V E = assign V E");;


% --------------------------------------------------------------------- %
% Define infix function `;' for sequencing.				%
% --------------------------------------------------------------------- %

let seq_def = 
    new_infix_definition 
    (`seq_def`,"$; C1 C2 = seq C1 C2");;


% --------------------------------------------------------------------- %
% Replace seq and assign by the infixes := and ;.			%
% --------------------------------------------------------------------- %

let comm = 
     save_thm
      (`comm_thm`,
        PURE_ONCE_REWRITE_RULE
	  [SYM (SPEC_ALL assign_def);SYM (SPEC_ALL seq_def)]
          comm);;

% ===================================================================== %
% Standard syntactic theory, derived by the recursive types package.	%
% ===================================================================== %

% --------------------------------------------------------------------- %
% Structural induction theorem for commands.				%
% --------------------------------------------------------------------- %

let induct = 
    save_thm (`induct`,prove_induction_thm comm);;

% --------------------------------------------------------------------- %
% Exhaustive case analysis theorem for commands.			%
% --------------------------------------------------------------------- %

let cases = 
    save_thm (`cases`, prove_cases_thm induct);;

% --------------------------------------------------------------------- %
% Prove that the abstract syntax constructors are one-to-one.		%
% --------------------------------------------------------------------- %

let const11 = 
    let [assign11;seq11;if11;while11] =
        (CONJUNCTS (prove_constructors_one_one comm)) in
        map save_thm
        [(`assign11`,assign11);
         (`seq11`,seq11);
         (`if11`,if11);
         (`while11`,while11)];;


% --------------------------------------------------------------------- %
% Prove that the constructors yield syntactically distinct values. Note %
% that one typically needs symmetric forms of the inequalities, so 	%
% these	are constructed here and grouped togther into one theorem.	%
% --------------------------------------------------------------------- %

let distinct =
    let ths = CONJUNCTS (prove_constructors_distinct comm) in
    let rths = map (GEN_ALL o NOT_EQ_SYM o SPEC_ALL) ths in
        save_thm(`distinct`, LIST_CONJ (ths @ rths));;

% ===================================================================== %
% Definition of the operational semantics.				%
% ===================================================================== %

% --------------------------------------------------------------------- %
% The semantics of commands will be given by an evaluation relation	%
%									%
%       EVAL : comm -> state -> state -> bool     			%
%									%
% defined inductively such that 					%
%									%
%       EVAL C s1 s2							%
%									%
% holds exactly when executing the command C in the initial state s1 	%
% terminates in the final state s2. The evaluation relation is defined  %
% inductively by the set of rules shown below.  			%
% --------------------------------------------------------------------- %

let rules,ind = 
    let EVAL = "EVAL : comm -> state -> state -> bool" in
    new_inductive_definition false `trans` 

    ("^EVAL C s1 s2", []) 
    
     [ [
       % ------------------------------------------------- % ],
                         "^EVAL skip s s"                  ;  

       [              
       % ------------------------------------------------- % ],
            "^EVAL (V := E) s (\v. (v=V) => E s | s v)"   ;


       [    "^EVAL C1 s1 s2";        "^EVAL C2 s2 s3"     
       % ------------------------------------------------- % ],
                      "^EVAL (C1;C2) s1 s3"               ;


       [               "^EVAL C1 s1 s2"                   ;
       % ------------------------------------------------- % "(B:bexp) s1"],
                   "^EVAL (if B C1 C2) s1 s2"             ;


       [                 "^EVAL C2 s1 s2"                 ;
       % ------------------------------------------------- % "~((B:bexp) s1)"],
                    "^EVAL (if B C1 C2) s1 s2"            ;

       [                                                  
       % ------------------------------------------------- % "~((B:bexp) s)"],
                     "^EVAL (while B C) s s"              ;


       [   "^EVAL C s1 s2";    "^EVAL (while B C) s2 s3"   ;
       % ------------------------------------------------- %  "(B:bexp) s1"],
                     "^EVAL (while B C) s1 s3"             ];;

% --------------------------------------------------------------------- %
% Stronger form of rule induction.					%
% --------------------------------------------------------------------- %

let sind = derive_strong_induction(rules,ind);;

% --------------------------------------------------------------------- %
% Construct the standard rule induction tactic for EVAL.  This uses	%
% the `weaker' form of the rule induction theorem, and both premisses	%
% and side conditions are simply assumed (in stripped form).  This 	%
% served for many proofs, but when a more elaborate treatment of	%
% premisses or side conditions is needed, or when the stronger form of	%
% induction is required, a specialized  rule induction tactic is	%
% constructed on the fly.						%
% --------------------------------------------------------------------- %

let RULE_INDUCT_TAC =
    RULE_INDUCT_THEN ind STRIP_ASSUME_TAC STRIP_ASSUME_TAC;;

% --------------------------------------------------------------------- %
% Prove the case analysis theorem for the evaluation rules.		%
% --------------------------------------------------------------------- %

let ecases = derive_cases_thm (rules,ind);;

% ===================================================================== %
% Derivation of backwards case analysis theorems for each rule.         %
%									%
% These theorems are consequences of the general case analysis theorem  %
% proved above.  They are used to justify formal reasoning in which the %
% rules are driven `backwards', inferring premisses from conclusions.   %
% One infers from the assertion that:					%
%									%
%    1: EVAL C s1 s2 							%
%									%
% for a specific command C (e.g. for C = "skip") that the corresponding %
% instance of the premisses of the rule(s) for C must also hold, since  %
% (1) can hold only by virtue of being derivable by the rule for C.     %
% This kind of reasoning occurs frequently in proofs about operational  %
% semantics.  Formally, one must use the fact that the logical 		%
% representations of syntactically different commands are distinct, a   %
% fact automatically proved by the recursive types package.		%
% ===================================================================== %

% --------------------------------------------------------------------- %
% The following rule is used to simplify special cases of the general   %
% exhaustive case analysis theorem, which looks something like:		%
%									%
%      |- !C s1 s2.							%
%          EVAL C s1 s2 =						%
%             (C = skip) ... \/						%
%             (?V E. (C = V := E) ...) \/				%
%             (?C1 C2 s2'. (C = C1 ; C2) ...) \/			%
%             (?C1 B C2. (C = if B C1 C2) /\ B s1 ...) \/		%
%             (?C2 B C1. (C = if B C1 C2) /\ ~B s1 ...) \/		%
%             (?B C'. (C = while B C') /\ ~B s1 ... ) \/		%
%             (?C' B s2'. (C = while B C') /\ B s1 ...)			%
%  									%
% If C is specialized to some particular syntactic form, for example    %
% to "C1;C2", then most of the disjuncts in the conclusion become 	%
% just false because of the syntactic inequality of different commands. %
% These false can be simplified away by rewriting with the theorem	%
% distinct.  The disjuncts that match the command to which C is 	%
% specialized can also be simplified by rewriting with const11.  This   %
% changes equalities between similar commands, for example:		%
%									%
%    (C1 ; C2) = (C1' ; C2')						%
%									%
% to equalities between their coresponding constitutents:		%
%									%
%    C1 = C1'  /\  C2 = C2'						%
%									%
% These can then generally be used for substitution.			%
% --------------------------------------------------------------------- %

let SIMPLIFY = REWRITE_RULE (distinct . const11);;

% --------------------------------------------------------------------- %
% CASE_TAC : this is applicable to goals of the form:			%
%									%
%      TRANS C s1 s2 ==> P						%
%									%
% When applied to such a goal, the antecedant is matched to the general %
% case analysis theorem and a corresponding instance of its conclusion  %
% is obtained.  This is simplified using the SIMPLIFY rule described    %
% above and the result is assumed in stripped form.  Given this tactic, %
% the sequence of theorems given below are simple to prove.  The proofs %
% are fairly uniform; with a careful analysis of the regularities, one  %
% should be able to devise an automatic proof procedure for deriving    %
% sets of theorems of this type.					%
% --------------------------------------------------------------------- %

let CASE_TAC = DISCH_THEN 
               (STRIP_ASSUME_TAC o SIMPLIFY o ONCE_REWRITE_RULE[ecases]);;

% --------------------------------------------------------------------- %
% SKIP_THM : EVAL skip s1 s2 is provable only by the skip rule, which   %
% requires that s1 and s2 be the same state.				%
% --------------------------------------------------------------------- %

let SKIP_THM =
    prove_thm
    (`SKIP_THM`,
     "!s1 s2. EVAL skip s1 s2 = (s1 = s2)",
     REPEAT GEN_TAC THEN EQ_TAC THENL
     [CASE_TAC THEN ASM_REWRITE_TAC [];
      DISCH_THEN SUBST1_TAC THEN MAP_FIRST RULE_TAC rules]);;


% --------------------------------------------------------------------- %
% ASSIGN_THM : EVAL (V := E) s1 s2 is provable only by the assignment	%
% rule, which requires that s2 be the state s1 with V updated to E.	%
% --------------------------------------------------------------------- %

let ASSIGN_THM =
    prove_thm
    (`ASSIGN_THM`,
     "!s1 s2 V E. EVAL (V := E) s1 s2 = ((\v. ((v=V) => E s1 | s1 v)) = s2)",
     REPEAT GEN_TAC THEN EQ_TAC THENL
     [CASE_TAC THEN ASM_REWRITE_TAC [];
      DISCH_THEN (SUBST1_TAC o SYM) THEN MAP_FIRST RULE_TAC rules]);;


% --------------------------------------------------------------------- %
% SEQ_THM : EVAL (C1;C2) s1 s2 is provable only by the sequencing rule, %
% which requires that some intermediate state s3 exists such that C1    %
% in state s1 terminates in s3 and C3 in s3 terminates in s2.		%
% --------------------------------------------------------------------- %

let SEQ_THM =
    prove_thm
    (`SEQ_THM`,
     "!s1 s2 C1 C2.EVAL (C1;C2) s1 s2 = (?s3. EVAL C1 s1 s3 /\ EVAL C2 s3 s2)",
     REPEAT GEN_TAC THEN EQ_TAC THENL
     [CASE_TAC THEN EXISTS_TAC "s2':state" THEN ASM_REWRITE_TAC [];
      DISCH_THEN \th. MAP_FIRST RULE_TAC rules THEN MATCH_ACCEPT_TAC th]);;


% --------------------------------------------------------------------- %
% IF_T_THM : if B(s1) is true, then EVAL (if B C2 C2) s1 s2 is provable %
% only by the first conditional rule, which requires that C1 when	%
% evaluated in s1 terminates in s2.					%
% --------------------------------------------------------------------- %

let IF_T_THM =
    prove_thm
    (`IF_T_THM`,
     "!s1 s2 B C1 C2. B s1 ==> (EVAL (if B C1 C2) s1 s2 = EVAL C1 s1 s2)",
     REPEAT STRIP_TAC THEN EQ_TAC THENL
     [CASE_TAC THEN EVERY_ASSUM (TRY o SUBST_ALL_TAC) THENL
      [FIRST_ASSUM ACCEPT_TAC; RES_TAC];
      DISCH_TAC THEN MAP_FIRST RULE_TAC rules THEN FIRST_ASSUM ACCEPT_TAC]);;


% --------------------------------------------------------------------- %
% IF_F_THM : if B(s1) is false, then EVAL (if B C1 C2) s1 s2 is 	%
% provable only by the second conditional rule, which requires that C2	%
% when evaluated in s1 terminates in s2.				%
% --------------------------------------------------------------------- %

let IF_F_THM =
    prove_thm
    (`IF_F_THM`,
     "!s1 s2 B C1 C2. ~B s1 ==> (EVAL (if B C1 C2) s1 s2 = EVAL C2 s1 s2)",
     REPEAT STRIP_TAC THEN EQ_TAC THENL
     [CASE_TAC THEN EVERY_ASSUM (TRY o SUBST_ALL_TAC) THENL
      [RES_TAC; FIRST_ASSUM ACCEPT_TAC];
      DISCH_TAC THEN MAP_FIRST RULE_TAC (rev rules) THEN
      FIRST_ASSUM ACCEPT_TAC]);;


% --------------------------------------------------------------------- %
% WHILE_T_THM : if B(s1) is true, then EVAL (while B C) s1 s2 is 	%
% provable only by the corresponding while rule, which requires that 	%
% there is an intermediate state s3 such that C in state s1 terminates  %
% in s3, and while B do C in state s3 terminates in s2.			%
% --------------------------------------------------------------------- %

let WHILE_T_THM =
    prove_thm
    (`WHILE_T_THM`,
     "!s1 s2 B C.
      B s1 ==> (EVAL (while B C) s1 s2 =
                (?s3. EVAL C s1 s3 /\ EVAL (while B C) s3 s2))",
     REPEAT STRIP_TAC THEN EQ_TAC THENL
     [CASE_TAC THEN EVERY_ASSUM (TRY o SUBST_ALL_TAC) THENL
      [RES_TAC;
       EXISTS_TAC "s2':state" THEN CONJ_TAC THEN FIRST_ASSUM ACCEPT_TAC];
      STRIP_TAC THEN MAP_FIRST RULE_TAC (rev rules) THEN
      EXISTS_TAC "s3:state" THEN
      REPEAT CONJ_TAC THEN FIRST_ASSUM ACCEPT_TAC]);;


% --------------------------------------------------------------------- %
% WHILE_F_THM : if B(s1) is false, then EVAL (while B C) s1 s2 is	%
% provable only by the corresponding while rule, which requires that 	%
% s2 equals the original state s1					%
% --------------------------------------------------------------------- %

let WHILE_F_THM =
    prove_thm
    (`WHILE_F_THM`,
     "!s1 s2 B C. ~B s1 ==> (EVAL (while B C) s1 s2 = (s1 = s2))",
     REPEAT STRIP_TAC THEN EQ_TAC THENL
     [CASE_TAC THENL
      [CONV_TAC SYM_CONV THEN FIRST_ASSUM ACCEPT_TAC;
       EVERY_ASSUM (TRY o SUBST_ALL_TAC) THEN RES_TAC];
      DISCH_THEN (SUBST1_TAC o SYM) THEN MAP_FIRST RULE_TAC rules THEN
      FIRST_ASSUM ACCEPT_TAC]);;


% ===================================================================== %
% THEOREM: the operational semantics is deterministic.			%
%									%
% Given the suite of theorems proved above, this proof is relatively    %
% strightforward.  The standard proof is by structural induction on C,  %
% but the proof by rule induction given below gives rise to a slightly  %
% easier analysis in each case of the induction.  There are, however,   %
% more cases---one per rule, rather than one per constructor.		%
% ===================================================================== %

let DETERMINISTIC =
    prove_thm
    (`DETERMINISTIC`,
     "!C st1 st2. EVAL C st1 st2 ==> !st3. EVAL C st1 st3 ==> (st2 = st3)",
     RULE_INDUCT_TAC THEN REPEAT GEN_TAC THENL
     [REWRITE_TAC [SKIP_THM];
      REWRITE_TAC [ASSIGN_THM];
      PURE_ONCE_REWRITE_TAC [SEQ_THM] THEN STRIP_TAC THEN
      FIRST_ASSUM MATCH_MP_TAC THEN RES_TAC THEN ASM_REWRITE_TAC [];
      IMP_RES_TAC IF_T_THM THEN ASM_REWRITE_TAC [];
      IMP_RES_TAC IF_F_THM THEN ASM_REWRITE_TAC [];
      IMP_RES_TAC WHILE_F_THM THEN ASM_REWRITE_TAC [];
      IMP_RES_THEN (\th. PURE_ONCE_REWRITE_TAC [th]) WHILE_T_THM THEN
      STRIP_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
      RES_TAC THEN ASM_REWRITE_TAC []]);;


% ===================================================================== %
% Definition of partial correctness and derivation of proof rules.	%
% ===================================================================== %

let SPEC_DEF =
    new_definition
    (`SPEC_DEF`,
     "SPEC P C Q = !s1 s2. (P s1 /\ EVAL C s1 s2) ==> Q s2");;

% --------------------------------------------------------------------- %
% Proof of the while rule in Hoare logic.				%
% --------------------------------------------------------------------- %

% --------------------------------------------------------------------- %
% In the following proofs, theorems of the form:			%
%									%
%     |- !y1...yn. (C x1 ... xn = C y1 ... yn) ==> tm[y1,...,yn]	%
%									%
% frequently arise, where C is one of the constructors of the data type %
% of commands.  The following theorem-tactic simplifies such theorems   %
% by specializing yi to xi and then removing the resulting trivially    %
% true antecedent.  The result is:					%
%									%
%     |- tm[x1,...,xn/y1,...,yn]					%
%									%
% which is passed to the theorem continuation function. The tactic just	%
% discards theorems not of the form shown above.   For the while proof  %
% given below, this has the effect of thinning out useless induction	%
% hypotheses of the form:						%
%									%
%     |- !B' C'. (C = while B' C') ==> tm[B',C']			%
% 									%
% These are just discarded.						%
% --------------------------------------------------------------------- %

let REFL_MP_THEN ttac th =
    (let tm = lhs(fst(dest_imp(snd(strip_forall(concl th))))) in 
     ttac (MATCH_MP th (REFL tm))) ? ALL_TAC;;

% --------------------------------------------------------------------- %
% The following lemma states that the condition B in while B C must be  %
% false upon termination of a while loop.  The proof is by a rule 	%
% induction specialized to the while rule cases.  We show that the set	%
% 									%
%    {(while B C,s1,s2) | ~(B s2)} U {(C,s1,s2) | ~(C = while B' C')}   %
%									%
% is closed under the rules for the evaluation relation. Note that this %
% formulation illustrates a general way of proving a property of some   %
% specific class of commands by rule induction.  One takes the union of %
% the set containing triples with the desired property and the set of   %
% all other triples whose command component is NOT an element of the    %
% class of commands of interest.					%
%									%
% The proof is trivial for all but the two while rules, since this set	%
% contains all triples (C,s1,s2) for which C is not a while command.  	%
% The subgoals corresponding to these cases are vacuously true, since 	%
% they are implications with antecedents of the form (C = while B' C'), %
% where C is a command syntactically distinct from any while command.	%
%									%
% Showing that the above set is closed under the two while rules is     %
% likewise trivial.  For the while axiom, we get ~(B s2) immediately 	%
% from the side condition. For the other while rule, the statement to	%
% prove is just one of the induction hypotheses; since RULE_INDUCT_TAC  %
% uses STRIP_ASSUME_TAC on this hypothesis, this subgoal is solved	%
% immediately.								%
% --------------------------------------------------------------------- %


let WHILE_LEMMA1 =
    TAC_PROOF
    (([], "!C s1 s2. EVAL C s1 s2 ==> !B' C'. (C = while B' C') ==> ~(B' s2)"),
     RULE_INDUCT_TAC THEN REWRITE_TAC (distinct . const11) THEN
     REPEAT GEN_TAC THEN DISCH_THEN (STRIP_THM_THEN SUBST_ALL_TAC) THEN
     FIRST_ASSUM ACCEPT_TAC);;

% --------------------------------------------------------------------- %
% The second lemma deals with the invariant part of the Hoare proof 	%
% rule for while commands.  We show that if P is an invariant of C, 	%
% then it is also an invariant of while B C.  The proof is essentially  %
% an induction on the number of applications of the evaluation rule for %
% while commands.  This is expressed as a rule induction, which 	%
% establishes that the set:						%
%									%
%    {(while B C,s1,s2) | P invariant of C ==> (P s1 ==> P s2)}		%
%									%
% is closed under the transition rules.  As in lemma 1, the rules for   %
% other kinds of commands are dealt with by taking the union of this 	%
% set with 								%
% 									%
%    {(C,s1,s2) | ~(C = while B' C')}					%
%									%
% Closure under evaluation rules other than the two rules for while is  %
% therefore trivial, as outlined in the comments to lemma 1 above. 	%
%									%
% The proof in fact proceeds by strong rule induction.  With ordinary   %
% rule induction, one obtains hypotheses that are too weak to imply the %
% desired conclusion in the step case of the while rule.  To see why, 	%
% try replacing strong by weak induction in the tactic proof below.	%
%									%
% Note that REFL_MP_THEN is used to simplify the induction hypotheses   %
% before adding them to the assumption list.  This avoids having the 	%
% assumptions in an awkward form (try using ASSUME_TAC instead). Note	%
% also that in the case of the while axiom, the states s1 and s2 are	%
% identical, so the corresponding subgoal is trivial and is solved by	%
% the rewriting step.							%
% --------------------------------------------------------------------- %

let WHILE_LEMMA2 =
    TAC_PROOF
    (([], "!C s1 s2. EVAL C s1 s2 
             ==>
           !B' C'. (C = while B' C') ==>
                   (!s1 s2. P s1 /\ B' s1 /\ EVAL C' s1 s2 ==> P s2) ==>
                   (P s1 ==> P s2)"),
     RULE_INDUCT_THEN sind (REFL_MP_THEN ASSUME_TAC) ASSUME_TAC THEN 
     REWRITE_TAC (distinct . const11) THEN REPEAT GEN_TAC THEN
     DISCH_THEN (STRIP_THM_THEN SUBST_ALL_TAC) THEN
     REPEAT STRIP_TAC THEN RES_TAC);;

% --------------------------------------------------------------------- %
% The proof rule for while commands in Hoare logic is:			%
%									%
%         |- {P /\ B} C {P}						%
%      ----------------------						%
%        |- {P} C {P /\ ~B}						%
% 									%
% Given the two lemmas proved above, it is trivial to prove this rule.  %
% The antecedent of the rule is just the assumption of invariance of P  %
% for C which occurs in lemma 2.  Note that REFL_MP_THEN is used to     %
% simplify the conclusions of the lemmas after one resolution step.	%
% --------------------------------------------------------------------- %

let WHILE =
    prove_thm
    (`WHILE`,
     "!P C. SPEC (\s. P s /\ (B s)) C P ==>
            SPEC P (while B C) (\s. P s /\ ~B s)",
     PURE_ONCE_REWRITE_TAC [SPEC_DEF] THEN
     CONV_TAC (ONCE_DEPTH_CONV BETA_CONV) THEN
     PURE_ONCE_REWRITE_TAC [SYM(SPEC_ALL CONJ_ASSOC)] THEN
     REPEAT STRIP_TAC THENL
     [IMP_RES_THEN (REFL_MP_THEN IMP_RES_TAC) WHILE_LEMMA2;
      IMP_RES_THEN (REFL_MP_THEN IMP_RES_TAC) WHILE_LEMMA1]);;

% --------------------------------------------------------------------- %
% End of example.							%
% --------------------------------------------------------------------- %

close_theory();;
quit();;