%
  2-process Bakery, infinite-state case in PVS

bakery: THEORY
BEGIN

phase : TYPE = {idle, trying, critical}

state: TYPE = [# pc1, pc2: phase, t1, t2: nat #]

s, pre, post: VAR state

P1_transition(pre, post): boolean = 
    IF pre`pc1 = idle
      THEN post = pre WITH [`t1 := pre`t2 + 1, `pc1 := trying]
    ELSIF pre`pc1 = trying AND (pre`t2 = 0 OR pre`t1 < pre`t2)
      THEN post = pre WITH [`pc1 := critical]
    ELSIF pre`pc1 = critical
      THEN post = pre WITH [`t1 := 0, `pc1 := idle]
    ELSE post = pre
    ENDIF

% Could also be written as
%
%   CASES pre`pc1 OF
%      idle:     post = pre WITH [`t1 := pre`t2 + 1, `pc1 := trying],
%      trying:   IF  (pre`t2 = 0 OR pre`t1 < pre`t2)
%                 THEN post = pre WITH [`pc1 := critical]
%                ELSE post = pre ENDIF,
%      critical: post = pre WITH [`t1 := 0, `pc1 := idle]
%    ENDCASES
%


P2_transition(pre, post): boolean =  
    IF pre`pc2 = idle
      THEN post = pre WITH [`t2 := pre`t1 + 1, `pc2 := trying]
    ELSIF pre`pc2 = trying AND (pre`t1 = 0 OR pre`t1 > pre`t2)
      THEN post = pre WITH [`pc2 := critical]
    ELSIF pre`pc2 = critical
      THEN post = pre WITH [`t2 := 0, `pc2 := idle]
    ELSE post = pre
    ENDIF

transitions(pre, post): bool = 
   P1_transition(pre, post) OR P2_transition(pre, post)

init(s): boolean = s`pc1 = idle AND s`pc2 = idle AND s`t1 = 0 AND s`t2 = 0

safe(s): boolean = NOT (s`pc1 = critical AND s`pc2 = critical)

IMPORTING transitions[state, init, transitions]

% Intentionally not proved
first_try: LEMMA indinv(safe)

strong_safe(s): bool = safe(s) 
  AND (s`t1 = 0 => s`pc1 = idle)
  AND (s`t2 = 0 => s`pc2 = idle)

% Intentionally not proved
second_try: LEMMA indinv(strong_safe)

inductive_safe(s): bool = strong_safe(s)
  AND ((s`pc1 = critical AND s`pc2 = trying) => s`t1 < s`t2)
  AND ((s`pc2 = critical AND s`pc1 = trying) => s`t1 > s`t2)

third_try: LEMMA indinv(inductive_safe)

abstract_state: TYPE = 
  [# pc1, pc2: phase, t1_is_0, t2_is_0, t1_lt_t2: bool #]

a_s, a_pre, a_post: VAR abstract_state

abst(s): abstract_state =
  (# pc1 := s`pc1, 
     pc2 := s`pc2,
     t1_is_0 := s`t1 = 0, 
     t2_is_0 := s`t2 = 0,
     t1_lt_t2 := s`t1 < s`t2 #)

a_init(a_s): bool = 
   a_s`pc1 = idle AND a_s`pc2 = idle AND a_s`t1_is_0 AND a_s`t2_is_0

a_P1_transition(a_pre, a_post): bool = 
%   a_pre = a_post OR
   IF a_pre`pc1 = idle
     THEN a_post = a_pre WITH [`t1_is_0 := false,
                               `t1_lt_t2 := false,
                               `pc1 := trying]
   ELSIF a_pre`pc1 = trying AND (a_pre`t2_is_0 OR a_pre`t1_lt_t2)
     THEN a_post = a_pre WITH [`pc1 := critical]
   ELSIF a_pre`pc1 = critical
     THEN a_post = a_pre WITH [`t1_is_0 := true,
                               `t1_lt_t2 := NOT a_pre`t2_is_0,
                               `pc1 := idle]
   ELSE a_post = a_pre
   ENDIF

a_P2_transition(a_pre, a_post): bool =  
%   a_pre = a_post OR
   IF a_pre`pc2 = idle
     THEN a_post = a_pre WITH [`t2_is_0 := false,
                               `t1_lt_t2 := true,
                               `pc2 := trying]
   ELSIF a_pre`pc2 = trying AND (a_pre`t1_is_0 OR NOT a_pre`t1_lt_t2)
     THEN a_post = a_pre WITH [`pc2 := critical]
   ELSIF a_pre`pc2 = critical
     THEN a_post = a_pre WITH [`t2_is_0 := true,
                               `t1_lt_t2 := false,
                               `pc2 := idle]
   ELSE a_post = a_pre
   ENDIF

a_trans(a_pre, a_post): bool = a_P1_transition(a_pre, a_post)
                               OR a_P2_transition(a_pre, a_post)

a_safe(a_s): boolean = NOT (a_s`pc1 = critical AND a_s`pc2 = critical)

init_simulation: THEOREM
   init(s) IMPLIES a_init(abst(s))

% Intentionally not proved
trans_simulation: THEOREM
   transitions(pre, post) IMPLIES a_trans(abst(pre), abst(post))

safety_preserved: THEOREM a_safe(abst(s)) IMPLIES safe(s)

abs_invariant_ctl: THEOREM
   a_init(a_s) IMPLIES AG(a_trans, a_safe)(a_s)

not_eq(s): bool = s`t1 = s`t2 => s`t1=0

extra: LEMMA indinv(not_eq)

strong_trans_simulation: THEOREM
   indinv(not_eq) 
    AND not_eq(pre)
    AND not_eq(post)
    AND transitions(pre, post) 
     IMPLIES a_trans(abst(pre), abst(post))

auto_abstract: THEOREM init(s) IMPLIES AG(transitions, safe)(s)

END bakery