# Bill,
#   This is just a 2-process bounded buffer problem, with wrap-around.
# The main challenge is that the bufer bound is not concretized, but is
# simply specified as "n", and remains static.
#   The combined system can easily be specified with a single program pt,
# and with 4 self-looping relations.  Two of the invariants we may wish
# to prove are below.
#   Neither transitive closure, nor widening seemed to work.  
# Closure just attempts to enumerate all reaching relations, 
# and since n isn't a constant, the process never stops.
#   Pls note that there is a "key invarant" which can summerize the 
# relationship between all the variables.  If one wished to formulate
# it, and then prove it on each transition using the omega test,
# this would work.  But this requires too much human interaction,
# and would defeat the whole pt of using tool.  Also, in more complicated
# problems, formulating a set key invariants isn't trivial.
# rich
# 
# 
# int n > 1;
# 
# int Pptr = 0,  // Producer's position in the buffer, domain [0,n-1] 
#     Cptr = 0,  // Consumer's position in the buffer, domain [0,n-1] 
#     pct = 0,   // Number of items produced so far, domain >= 0 
#     cct = 0;   // Number of items consumed so far, domain >= 0 
#     
# Producer:
#    enabled :: (Pptr == n-1 and Cptr != 0) or 
#               (Pptr < n-1 and Pptr != Cptr - 1) 
#    action :: if (Pptr == n-1) then
#                 Pptr := 0
#              else 
#                 Pptr := Ptr + 1 
#              pct := pct + 1
# 
# Consumer:
#    enabled :: Cptr != Pptr
#    action :: if (Cptr == n-1) then
#                  Cptr := 0
#              else
#                  Cptr := Cptr + 1 
#              cct := cct + 1
#              
# Requirements
#    Invariant ( cct <= pct)
#    Invariant ( pct - cct <= n )
# 
symbolic n;
I := {[Pptr,Cptr,pct,cct] : 0 <= Pptr,Cptr <= n-1 && pct,cct >= 0 && n > 1};
R1 := (I*I) intersection {[n-1,Cptr,pct,cct] -> [0,Cptr,pct+1,cct] : Cptr > 0};
R2 := (I*I) intersection {[Pptr,Cptr,pct,cct] -> [Pptr+1,Cptr,pct+1,cct] : Pptr+1 < Cptr};
R3 := (I*I) intersection {[Pptr,Cptr,pct,cct] -> [Pptr+1,Cptr,pct+1,cct] : Pptr+1 > Cptr};
R4 := (I*I) intersection {[Pptr,n-1,pct,cct] -> [Pptr,0,pct,cct+1] : Pptr < n-1};
R5 := (I*I) intersection {[Pptr,Cptr,pct,cct] -> [Pptr,Cptr+1,pct,cct+1] : Pptr < Cptr};
R6 := (I*I) intersection {[Pptr,Cptr,pct,cct] -> [Pptr,Cptr+1,pct,cct+1] : Pptr > Cptr};

Init := {[0,0,0,0]};

R1c := R1+;
R2c := R2+;
R3c := R3+;
R4c := R4+;
R5c := R5+;
R6c := R6+;
R1c;
R2c;
R3c;
R4c;
R5c;
R6c;

Rp := (R1c union R2c union R3c union R4c union R5c union R6c);

Venn domain Rp;

S1 := Init;
S1;
S2 := R3c(S1);
S2;
S3 := R6c(S2);
S3;
S4 := R1c(S3);
S4;
S5 := R2c(S4);
S5;
S1a := R4c(S4);
S1a;
S1 := Hull(S1 union S1a);
S1;
S2a := R4c(S5) union R3c(S1);
S2a;
S2 := Hull(S2 union S2a);
S2;
S3a := R6c(S2);


R1c := Init;
T1 := Rp( Init );
# Uses just R1+
T1;
T2 := Rp(T1) - T1;
# Uses just R1+
T2;
T3 := Rp(T2) - T2 - T1;
T3;
T4 := Rp(T3) - T3 - T2 - T1;
T4;
T5 := Rp(T4) - T4 - T3 - T2 - T1;
T5;
T6 := Rp(T5) - T5 - T4 - T3 - T2 - T1;
T6;
T7 := Rp(T6) - T6 - T5 - T4 - T3 - T2 - T1;
T7;
