(* ========================================================================= *)
(* Simple WHILE-language with relational semantics.                          *)
(* ========================================================================= *)
prioritize_num();;
parse_as_infix("refined",(12,"right"));;
(* ------------------------------------------------------------------------- *)
(* Logical operations "lifted" to predicates, for readability.               *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("AND",(20,"right"));;
parse_as_infix("OR",(16,"right"));;
parse_as_infix("IMP",(13,"right"));;
parse_as_infix("IMPLIES",(12,"right"));;
let NOT = new_definition
  `NOT p = \x:S. ~(p x)`;;
let AND = new_definition
  `p AND q = \x:S. p x /\ q x`;;
let OR = new_definition
  `p OR q = \x:S. p x \/ q x`;;
let ANDS = new_definition
  `ANDS P = \x:S. !p. P p ==> p x`;;
let ORS = new_definition
  `ORS P = \x:S. ?p. P p /\ p x`;;
let IMP = new_definition
  `p IMP q = \x:S. p x ==> q x`;;
let DO = new_definition
  `DO c e = c Seq (While e c)`;;
let AWHILE = new_definition
  `AWHILE (i:S->bool) (v:S->S->bool) (e:S->bool) c = While e c`;;
let ADO = new_definition
  `ADO (i:S->bool) (v:S->S->bool) c (e:S->bool) = DO c e`;;
let SEM_ASSIGN = prove
 (`
sem(Assign f) s s' <=> (s' = f s)`,
  GEN_REWRITE_TAC LAND_CONV [
sem_CASES] THEN
  REWRITE_TAC[command_DISTINCT; command_INJECTIVE] THEN MESON_TAC[]);;
 
let SEM_SEQ = prove
 (`
sem(c1 Seq c2) s s' <=> ?s''. 
sem c1 s s'' /\ 
sem c2 s'' s'`,
  GEN_REWRITE_TAC LAND_CONV [
sem_CASES] THEN
  REWRITE_TAC[command_DISTINCT; command_INJECTIVE] THEN MESON_TAC[]);;
 
let SEM_ITE = prove
 (`
sem(Ite e c1 c2) s s' <=> e s /\ 
sem c1 s s' \/
                             ~(e s) /\ 
sem c2 s s'`,
  GEN_REWRITE_TAC LAND_CONV [
sem_CASES] THEN
  REWRITE_TAC[command_DISTINCT; command_INJECTIVE] THEN MESON_TAC[]);;
 
let DETERMINISM = prove
 (`!c:(S)command. deterministic(
sem c)`,
  REWRITE_TAC[deterministic] THEN SUBGOAL_THEN
   `!c s s1. 
sem c s s1 ==> !s2:S. 
sem c s s2 ==> (s1 = s2)`
   (fun th -> MESON_TAC[th]) THEN
  MATCH_MP_TAC 
sem_INDUCT THEN CONJ_TAC THENL
   [ALL_TAC; REPEAT CONJ_TAC THEN REPEAT GEN_TAC THEN DISCH_TAC] THEN
  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[
sem_CASES] THEN
  REWRITE_TAC[command_DISTINCT; command_INJECTIVE] THEN
  ASM_MESON_TAC[]);;
 
let CORRECT_SEQ = prove
 (`!p q r c1 c2.
        correct p c1 r /\ correct r c2 q ==> correct p (c1 Seq c2) q`,
 
let CORRECT_WHILE = prove
 (`! (<<) p c q e invariant.
       
WF(<<) /\
       p 
IMPLIES invariant /\
       (
NOT e) 
AND invariant 
IMPLIES q /\
       (!X:S. correct
              (invariant 
AND e 
AND (\s. X = s)) c (invariant 
AND (\s. s << X)))
       ==> correct p (While e c) q`,
  REWRITE_TAC[correct; 
IMPLIES; 
IN; 
AND; 
NOT] THEN REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `!s:S. invariant s ==> wp (While e c) q s` MP_TAC THENL
   [ALL_TAC; ASM_MESON_TAC[]] THEN
  FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[
WF_IND]) THEN
  X_GEN_TAC `s:S` THEN REPEAT DISCH_TAC THEN
  ONCE_REWRITE_TAC[GSYM 
WP_WHILE] THEN
  REWRITE_TAC[
WP_IF; 
WP_SEQ; 
AND; 
OR; 
NOT; 
o_THM] THEN
  ASM_CASES_TAC `(e:S->bool) s` THEN ASM_REWRITE_TAC[] THENL
   [ALL_TAC; ASM_MESON_TAC[]] THEN
  SUBGOAL_THEN `wp c (\x:S. invariant x /\ x << s) (s:S) :bool` MP_TAC THENL
   [FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
  SUBGOAL_THEN `(\x:S. invariant x /\ x << (s:S)) 
IMPLIES wp (While e c) q`
  MP_TAC THENL [REWRITE_TAC[
IMPLIES] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
  MESON_TAC[
WP_MONOTONIC; 
IMPLIES]);;
 
let CORRECT_DO = prove
 (`! (<<) p q c invariant.
        
WF(<<) /\
        (e 
AND invariant) 
IMPLIES p /\
        ((
NOT e) 
AND invariant) 
IMPLIES q /\
        (!X:S. correct
               (p 
AND (\s. X = s)) c (invariant 
AND (\s. s << X)))
        ==> correct p (
DO c e) q`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[
DO] THEN
  MATCH_MP_TAC 
CORRECT_SEQ THEN EXISTS_TAC `invariant:S->bool` THEN
  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
   [POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
    REWRITE_TAC[correct; GSYM 
WP_CONJUNCTIVE] THEN
    REWRITE_TAC[
AND; 
IMPLIES] THEN MESON_TAC[];
    MATCH_MP_TAC 
CORRECT_WHILE THEN
    MAP_EVERY EXISTS_TAC [`(<<) :S->S->bool`; `invariant:S->bool`] THEN
    ASM_REWRITE_TAC[
IMPLIES] THEN X_GEN_TAC `X:S` THEN
    MATCH_MP_TAC 
CORRECT_PRESTRENGTH THEN
    EXISTS_TAC `p 
AND (\s:S. X = s)` THEN ASM_REWRITE_TAC[] THEN
    UNDISCH_TAC `(e:S->bool) 
AND invariant 
IMPLIES p` THEN
    REWRITE_TAC[
AND; 
IMPLIES] THEN MESON_TAC[]]);;