Add 2 benchmarks directories.

Add an algorithm to split an automaton in several automata.

* bench/scc-stats: New directory.  Contains input files and test
program for computing statistics.
* bench/split-product: New directory.  Contains test program for
synchronised product on splitted automata.
* bench/split-product/models: New directory.  Contains Promela
files and LTL formulae that should be verified by the models.
* src/tgba/tgbafromfile.cc, src/tgba/tgbafromfile.hh:
New files.  Small class to avoid long initializations with numerous
constants when translating to TGBA many LTL formulae from a
given file.
* src/tgbaalgos/cutscc.cc, src/tgbaalgos/cutscc.hh:
New file.  From a single automaton, create, at most,
X sub automata.
* src/tgbaalgos/scc.cc, src/tgbaalgos/scc.hh:
Adjust to compute self-loops count.
This commit is contained in:
Flix Abecassis 2009-07-06 17:27:16 +02:00
parent a160b3504b
commit 414956c51e
35 changed files with 2989 additions and 5 deletions

View file

@ -0,0 +1,43 @@
#define w1 client[0]@wait
#define s1 client[0]@served
#define C 3
#define S 1
chan clserv = [C] of { int };
chan servcl = [S] of { int };
active [C] proctype client() {
/* the _pid's are: 0 .. C-1 */
served:
if
:: (1) -> goto request;
fi;
request:
if
:: (1) -> clserv!_pid; goto wait;
fi;
wait:
if
:: servcl?eval(_pid); goto served;
fi;
}
active [S] proctype server() {
/* the _pid's are: 0 .. S-1 */
byte id;
wait:
if
:: clserv?id -> goto work;
fi;
work:
if
:: (1) -> goto reply;
fi;
reply:
if
:: (1) -> servcl!id; goto wait;
fi;
}

View file

@ -0,0 +1,43 @@
#define w1 client[0]@wait
#define s1 client[0]@served
#define C 3
#define S 3
chan clserv = [C] of { int };
chan servcl = [S] of { int };
active [C] proctype client() {
/* the _pid's are: 0 .. C-1 */
served:
if
:: (1) -> goto request;
fi;
request:
if
:: (1) -> clserv!_pid; goto wait;
fi;
wait:
if
:: servcl?eval(_pid); goto served;
fi;
}
active [S] proctype server() {
/* the _pid's are: 0 .. S-1 */
byte id;
wait:
if
:: clserv?id -> goto work;
fi;
work:
if
:: (1) -> goto reply;
fi;
reply:
if
:: (1) -> servcl!id; goto wait;
fi;
}

View file

@ -0,0 +1 @@
!([] (w1 -> <> s1))

View file

@ -0,0 +1,9 @@
!(<>[](noLeader U zeroLeads))
!(<>[](noLeader U threeLeads))
!(<>zeroLeads)
!([]<>zeroLeads)
!(<>threeLeads)
!([](noLeader -> <>zeroLeads))
!([](noLeader || zeroLeads))
!((<>[](noLeader || zeroLeads || oneLeads || twoLeads)) && (<>[]((zeroLeads -> (zeroLeads U (noLeader U oneLeads))))) && (<>[]((oneLeads -> (oneLeads U (noLeader U twoLeads))))) && (<>[]((twoLeads -> (twoLeads U (noLeader U zeroLeads))))))
!((<>[](noLeader || zeroLeads || oneLeads || twoLeads)) && (<>[]((zeroLeads -> (zeroLeads U (noLeader U twoLeads))))) && (<>[]((oneLeads -> (oneLeads U (noLeader U zeroLeads))))) && (<>[]((twoLeads -> (twoLeads U (noLeader U oneLeads))))))

View file

@ -0,0 +1,116 @@
/* Echo Election Algorithm with Extinction in an Arbitrary Network. */
/* Variation 1: Node 0 wins every time. */
#define L 10 /* size of buffer */
#define udef 3
#define noLeader (nr_leaders == 0)
#define zeroLeads (nr_leaders == 1 && leader == 0)
#define oneLeads (nr_leaders == 1 && leader == 1)
#define twoLeads (nr_leaders == 1 && leader == 2)
#define threeLeads (nr_leaders == 1 && leader == 3)
mtype = { tok, ldr };
chan zero_one = [L] of { mtype, byte};
chan zero_two = [L] of { mtype, byte};
chan one_zero = [L] of { mtype, byte};
chan one_two = [L] of { mtype, byte};
chan two_zero = [L] of { mtype, byte};
chan two_one = [L] of { mtype, byte};
chan nr0 = [0] of {mtype};
chan nr1 = [0] of {mtype};
chan nr2 = [0] of {mtype};
byte nr_leaders, done, leader;
inline recvldr ()
{
if
:: lrec == 0 && r != myid ->
out1!ldr(r);
out2!ldr(r);
:: else -> skip;
fi;
lrec++;
win = r;
}
inline recvtok (q,c)
{
if
:: r < caw ->
caw = r;
rec = 0;
father = q;
c!tok(r);
:: else -> skip;
fi;
if
:: r == caw ->
rec++;
if
:: rec == 2 && caw == myid
-> out1!ldr(myid); out2!ldr(myid);
:: rec == 2 && caw != myid && father == neigh1
-> out1!tok(caw)
:: rec == 2 && caw != myid && father == neigh2
-> out2!tok(caw)
:: else -> skip;
fi;
:: else -> skip;
fi;
}
proctype node (chan nr; byte neigh1; chan out1, in1;
byte neigh2; chan out2, in2)
{ byte myid = 3 - neigh1 - neigh2;
byte caw, rec, father, lrec, win, r;
xr in1; xr in2;
xs out1; xs out2;
restart:
nr?tok;
caw = myid; rec = 0; lrec = 0;
father = udef; win = udef; r = udef;
out1!tok(myid);
out2!tok(myid);
do
:: lrec == 2 -> break;
:: in1?ldr(r) -> recvldr();
:: in2?ldr(r) -> recvldr();
:: in1?tok(r) -> recvtok(neigh1,out2);
:: in2?tok(r) -> recvtok(neigh2,out1);
od;
if
:: win == myid ->
leader = myid;
nr_leaders++;
assert(nr_leaders == 1);
:: else ->
skip;
fi;
done++;
goto restart;
}
init {
atomic {
run node (nr0,1,zero_one,one_zero,2,zero_two,two_zero);
run node (nr1,0,one_zero,zero_one,2,one_two,two_one);
run node (nr2,0,two_zero,zero_two,1,two_one,one_two);
}
do
:: true ->
done = 0;
nr_leaders = 0;
leader = udef;
nr0!tok; nr1!tok; nr2!tok;
done == 3;
od;
}

View file

@ -0,0 +1,118 @@
/* Echo Election Algorithm with Extinction in an Arbitrary Network. */
/* Variation 1: Node 0 wins every time. */
#define L 10 /* size of buffer */
#define udef 3
#define noLeader (nr_leaders == 0)
#define zeroLeads (nr_leaders == 1 && leader == 0)
#define oneLeads (nr_leaders == 1 && leader == 1)
#define twoLeads (nr_leaders == 1 && leader == 2)
#define threeLeads (nr_leaders == 1 && leader == 3)
mtype = { tok, ldr };
chan zero_one = [L] of { mtype, byte};
chan zero_two = [L] of { mtype, byte};
chan one_zero = [L] of { mtype, byte};
chan one_two = [L] of { mtype, byte};
chan two_zero = [L] of { mtype, byte};
chan two_one = [L] of { mtype, byte};
chan nr0 = [0] of {mtype, byte};
chan nr1 = [0] of {mtype, byte};
chan nr2 = [0] of {mtype, byte};
byte nr_leaders, done, leader;
inline recvldr ()
{
if
:: lrec == 0 && r != myid ->
out1!ldr(r);
out2!ldr(r);
:: else -> skip;
fi;
lrec++;
win = r;
}
inline recvtok (q,c)
{
if
:: (r+turn)%3 < (caw+turn)%3 ->
caw = r;
rec = 0;
father = q;
c!tok(r);
:: else -> skip;
fi;
if
:: r == caw ->
rec++;
if
:: rec == 2 && caw == myid
-> out1!ldr(myid); out2!ldr(myid);
:: rec == 2 && caw != myid && father == neigh1
-> out1!tok(caw)
:: rec == 2 && caw != myid && father == neigh2
-> out2!tok(caw)
:: else -> skip;
fi;
:: else -> skip;
fi;
}
proctype node (chan nr; byte neigh1; chan out1, in1;
byte neigh2; chan out2, in2)
{ byte myid = 3 - neigh1 - neigh2;
byte caw, rec, father, lrec, win, r, turn;
xr in1; xr in2;
xs out1; xs out2;
restart:
nr?tok(turn);
caw = myid; rec = 0; lrec = 0;
father = udef; win = udef; r = udef;
out1!tok(myid);
out2!tok(myid);
do
:: lrec == 2 -> break;
:: in1?ldr(r) -> recvldr();
:: in2?ldr(r) -> recvldr();
:: in1?tok(r) -> recvtok(neigh1,out2);
:: in2?tok(r) -> recvtok(neigh2,out1);
od;
if
:: win == myid ->
leader = myid;
nr_leaders++;
assert(nr_leaders == 1);
:: else ->
skip;
fi;
done++;
goto restart;
}
init {
byte turn = 0;
atomic {
run node (nr0,1,zero_one,one_zero,2,zero_two,two_zero);
run node (nr1,0,one_zero,zero_one,2,one_two,two_one);
run node (nr2,0,two_zero,zero_two,1,two_one,one_two);
}
do
:: true ->
done = 0;
nr_leaders = 0;
leader = udef;
nr0!tok(turn); nr1!tok(turn); nr2!tok(turn);
done == 3;
turn = (turn+1)%3;
od;
}

View file

@ -0,0 +1,55 @@
[](!p0)
<>p1 -> (!p0 U p1)
[](p2 -> [](!p0))
[]((p2 & !p1 & <>p1) -> (!p0 U p1))
[](p2 & !p1 -> (!p0 U (p1 | []!p0)))
<>(p0)
!p1 U ((p0 & !p1) | []!p1)
[](!p2) | <>(p2 & <>p0)
[](p2 & !p1 -> (!p1 U ((p0 & !p1) | []!p1)))
[](p2 & !p1 -> (!p1 U (p0 & !p1)))
<>p1 -> ((!p0 & !p1) U (p1 | ((p0 & !p1) U (p1 | ((!p0 & !p1) U (p1 | ((p0 & !p1) U (p1 | (!p0 U p1)))))))))
[]((p2 & <>p1) -> ((!p0 & !p1) U (p1 | ((p0 & !p1) U (p1 | ((!p0 & !p1) U (p1 | ((p0 & !p1) U (p1 | (!p0 U p1))))))))))
[](p2 -> ((!p0 & !p1) U (p1 | ((p0 & !p1) U (p1 | ((!p0 & !p1) U (p1 | ((p0 & !p1) U (p1 | (!p0 U (p1 | []!p0)) | []p0)))))))))
[](p0)
<>p1 -> (p0 U p1)
[](p2 -> [](p0))
[]((p2 & !p1 & <>p1) -> (p0 U p1))
[](p2 & !p1 -> (p0 U (p1 | [] p0)))
!p0 U (p3 | []!p0)
<>p1 -> (!p0 U (p3 | p1))
[]!p2 | <>(p2 & (!p0 U (p3 | []!p0)))
[]((p2 & !p1 & <>p1) -> (!p0 U (p3 | p1)))
[](p2 & !p1 -> (!p0 U ((p3 | p1) | []!p0)))
[](p0 -> <>p3)
<>p1 -> (p0 -> (!p1 U (p3 & !p1))) U p1
[](p2 -> [](p0 -> <>p3))
[]((p2 & !p1 & <>p1) -> (p0 -> (!p1 U (p3 & !p1))) U p1)
[](p2 & !p1 -> ((p0 -> (!p1 U (p3 & !p1))) U (p1 | [](p0 -> (!p1 U (p3 & !p1))))))
<>p0 -> (!p0 U (p3 & !p0 & X(!p0 U p4)))
<>p1 -> (!p0 U (p1 | (p3 & !p0 & X(!p0 U p4))))
([]!p2) | (!p2 U (p2 & <>p0 -> (!p0 U (p3 & !p0 & X(!p0 U p4)))))
[]((p2 & <>p1) -> (!p0 U (p1 | (p3 & !p0 & X(!p0 U p4)))))
[](p2 -> (<>p0 -> (!p0 U (p1 | (p3 & !p0 & X(!p0 U p4))))))
(<>(p3 & X<>p4)) -> ((!p3) U p0)
<>p1 -> ((!(p3 & (!p1) & X(!p1 U (p4 & !p1)))) U (p1 | p0))
([]!p2) | ((!p2) U (p2 & ((<>(p3 & X<>p4)) -> ((!p3) U p0))))
[]((p2 & <>p1) -> ((!(p3 & (!p1) & X(!p1 U (p4 & !p1)))) U (p1 | p0)))
[](p2 -> (!(p3 & (!p1) & X(!p1 U (p4 & !p1))) U (p1 | p0) | [](!(p3 & X<>p4))))
[] (p3 & X<> p4 -> X(<>(p4 & <> p0)))
<>p1 -> (p3 & X(!p1 U p4) -> X(!p1 U (p4 & <> p0))) U p1
[] (p2 -> [] (p3 & X<> p4 -> X(!p4 U (p4 & <> p0))))
[] ((p2 & <>p1) -> (p3 & X(!p1 U p4) -> X(!p1 U (p4 & <> p0))) U p1)
[] (p2 -> (p3 & X(!p1 U p4) -> X(!p1 U (p4 & <> p0))) U (p1 | [] (p3 & X(!p1 U p4) -> X(!p1 U (p4 & <> p0)))))
[] (p0 -> <>(p3 & X<>p4))
<>p1 -> (p0 -> (!p1 U (p3 & !p1 & X(!p1 U p4)))) U p1
[] (p2 -> [] (p0 -> (p3 & X<> p4)))
[] ((p2 & <>p1) -> (p0 -> (!p1 U (p3 & !p1 & X(!p1 U p4)))) U p1)
[] (p2 -> (p0 -> (!p1 U (p3 & !p1 & X(!p1 U p4)))) U (p1 | [] (p0 -> (p3 & X<> p4))))
[] (p0 -> <>(p3 & !p5 & X(!p5 U p4)))
<>p1 -> (p0 -> (!p1 U (p3 & !p1 & !p5 & X((!p1 & !p5) U p4)))) U p1
[] (p2 -> [] (p0 -> (p3 & !p5 & X(!p5 U p4))))
[] ((p2 & <>p1) -> (p0 -> (!p1 U (p3 & !p1 & !p5 & X((!p1 & !p5) U p4)))) U p1)
[] (p2 -> (p0 -> (!p1 U (p3 & !p1 & !p5 & X((!p1 & !p5) U p4)))) U (p1 | [] (p0 -> (p3 & !p5 & X(!p5 U p4)))))
!p0 U ((p0 U ((!p0 U ((p0 U ([]!p0 | []p0)) | []!p0)) | []!p0)) | []!p0)
<>p2 -> (!p2 U (p2 & (!p0 U ((p0 U ((!p0 U ((p0 U ([]!p0 | []p0)) | []!p0)) | []!p0)) | []!p0))))

View file

@ -0,0 +1 @@
!(<>[]oneLeader)

View file

@ -0,0 +1,89 @@
/* Dolev, Klawe & Rodeh for leader election in unidirectional ring
* `An O(n log n) unidirectional distributed algorithm for extrema
* finding in a circle,' J. of Algs, Vol 3. (1982), pp. 245-260
*/
#define elected (nr_leaders > 0)
#define noLeader (nr_leaders == 0)
#define oneLeader (nr_leaders == 1)
#define N 5 /* nr of processes (use 5 for demos) */
#define I 3 /* node given the smallest number */
#define L 10 /* size of buffer (>= 2*N) */
mtype = { one, two, winner };
chan q[N] = [L] of { mtype, byte};
byte nr_leaders = 0;
proctype node (chan in, out; byte mynumber)
{ bit Active = 1, know_winner = 0;
byte nr, maximum = mynumber, neighbourR;
xr in;
xs out;
printf("MSC: %d\n", mynumber);
out!one(mynumber);
end: do
:: in?one(nr) ->
if
:: Active ->
if
:: nr != maximum ->
out!two(nr);
neighbourR = nr
:: else ->
/* Raynal p.39: max is greatest number */
assert(nr == N);
know_winner = 1;
out!winner,nr;
fi
:: else ->
out!one(nr)
fi
:: in?two(nr) ->
if
:: Active ->
if
:: neighbourR > nr && neighbourR > maximum ->
maximum = neighbourR;
out!one(neighbourR)
:: else ->
Active = 0
fi
:: else ->
out!two(nr)
fi
:: in?winner,nr ->
if
:: nr != mynumber ->
printf("MSC: LOST\n");
:: else ->
printf("MSC: LEADER\n");
nr_leaders++;
assert(nr_leaders == 1)
fi;
if
:: know_winner
:: else -> out!winner,nr
fi;
break
od
}
init {
byte proc;
atomic {
proc = 1;
do
:: proc <= N ->
run node (q[proc-1], q[proc%N], (N+I-proc)%N+1);
proc++
:: proc > N ->
break
od
}
}

View file

@ -0,0 +1,2 @@
!((![]<>(r)) -> [](<>p -> <>q))

View file

@ -0,0 +1,155 @@
/*
* Model of cell-phone handoff strategy in a mobile network.
* A translation from the pi-calculus description of this
* model presented in:
* Fredrik Orava and Joachim Parrow, 'An algebraic verification
* of a mobile network,' Formal aspects of computing, 4:497-543 (1992).
* For more information on this model, email: joachim@it.kth.se
*
* See also the simplified version of this model in mobile2
*
* The ltl property definition for this version is in mobile1.ltl
*
* to perform the verification with xspin, simply use the ltl property
* manager, which will load the above .ltl file by default.
* to perform the verificaion from a Unix command line, type:
* $ spin -a -N mobile1.ltl mobile1
* $ cc -o pan pan.c
* $ pan -a
*/
#define p in?[red]
#define q out?[red]
#define r (BS[a_id]@progress || BS[p_id]@progress)
mtype = { data, ho_cmd, ho_com, ho_acc, ho_fail, ch_rel, white, red, blue };
chan in = [1] of { mtype };
chan out = [1] of { mtype };
byte a_id, p_id; /* ids of processes refered to in the property */
proctype CC(chan fa, fp, l) /* communication controller */
{ chan m_old, m_new, x;
mtype v;
do
:: in?v ->
printf("MSC: DATA\n");
fa!data; fa!v
:: l?m_new ->
fa!ho_cmd; fa!m_new;
printf("MSC: HAND-OFF\n");
if
:: fp?ho_com ->
printf("MSC: CH_REL\n");
fa!ch_rel; fa?m_old;
l!m_old;
x = fa; fa = fp; fp = x
:: fa?ho_fail ->
printf("MSC: FAIL\n");
l!m_new
fi
od
}
proctype HC(chan l, m) /* handover controller */
{
do
:: l!m; l?m
od
}
proctype MSC(chan fa, fp, m) /* mobile switching center */
{ chan l = [0] of { chan };
atomic {
run HC(l, m);
run CC(fa, fp, l)
}
}
proctype BS(chan f, m; bit how) /* base station */
{ chan v;
if
:: how -> goto Active
:: else -> goto Passive
fi;
Active:
printf("MSC: ACTIVE\n");
do
:: f?data -> f?v; m!data; m!v
:: f?ho_cmd -> /* handover command */
progress: f?v; m!ho_cmd; m!v;
if
:: f?ch_rel ->
f!m;
goto Passive
:: m?ho_fail ->
printf("MSC: FAILURE\n");
f!ho_fail
fi
od;
Passive:
printf("MSC: PASSIVE\n");
m?ho_acc -> f!ho_com;
goto Active
}
proctype MS(chan m) /* mobile station */
{ chan m_new;
mtype v;
do
:: m?data -> m?v; out!v
:: m?ho_cmd; m?m_new;
if
:: m_new!ho_acc; m = m_new
:: m!ho_fail
fi
od
}
proctype P(chan fa, fp)
{ chan m = [0] of { mtype };
atomic {
run MSC(fa, fp, m);
p_id = run BS(fp, m, 0) /* passive base station */
}
}
proctype Q(chan fa)
{ chan m = [0] of { mtype }; /* mixed use as mtype/chan */
atomic {
a_id = run BS(fa, m, 1); /* active base station */
run MS(m)
}
}
active proctype System()
{ chan fa = [0] of { mtype }; /* mixed use as mtype/chan */
chan fp = [0] of { mtype }; /* mixed use as mtype/chan */
atomic {
run P(fa, fp);
run Q(fa)
}
}
active proctype top()
{
do
:: in!red; in!white; in!blue
od
}
active proctype bot()
{
do /* deadlock on loss or duplication */
:: out?red; out?white; out?blue
od
}

View file

@ -0,0 +1 @@
!((![]<>(r)) -> [](<>p -> <>q))

View file

@ -0,0 +1,136 @@
/*
* Simplified model of cell-phone handoff strategy in a mobile network.
* A translation from the pi-calculus description of this
* model presented in:
* Fredrik Orava and Joachim Parrow, 'An algebraic verification
* of a mobile network,' Formal aspects of computing, 4:497-543 (1992).
* For more information on this model, email: joachim@it.kth.se
*
* This version exploits some Promela features to reduce the number
* of processes -- which looks better in simulations, and reduces
* complexity (by about 60%) in verification.
*
* See also the more literal version of this model in mobile1.
*
* The ltl property definition for this version is in mobile2.ltl
*
* to perform the verification with xspin, simply use the ltl property
* manager, which will load the above .ltl file by default.
* to perform the verificaion from a Unix command line, type:
* $ spin -a -N mobile2.ltl mobile2
* $ cc -o pan pan.c
* $ pan -a
*/
#define p in?[red]
#define q out?[red]
#define r (BS[a_id]@progress || BS[p_id]@progress)
mtype = { data, ho_cmd, ho_com, ho_acc, ho_fail, ch_rel, white, red, blue };
chan in = [1] of { mtype };
chan out = [1] of { mtype };
chan fa = [0] of { chan };
chan fp = [0] of { chan };
chan m1 = [0] of { chan };
chan m2 = [0] of { chan };
chan l = [0] of { chan };
byte a_id, p_id; /* ids of processes refered to in the property */
proctype CC() /* communication controller */
{ chan m_old, m_new, x;
mtype v;
do
:: in?v ->
printf("MSC: DATA\n");
fa!data; fa!v
:: l?m_new ->
fa!ho_cmd; fa!m_new;
printf("MSC: HAND-OFF\n");
if
:: fp?ho_com ->
printf("MSC: CH_REL\n");
fa!ch_rel; fa?m_old;
l!m_old;
x = fa; fa = fp; fp = x
:: fa?ho_fail ->
printf("MSC: FAIL\n");
l!m_new
fi
od
}
proctype HC(chan m) /* handover controller */
{
do
:: l!m; l?m
od
}
proctype BS(chan f, m; bit how) /* base station */
{ chan v;
if
:: how -> goto Active
:: else -> goto Passive
fi;
Active:
printf("MSC: ACTIVE\n");
do
:: f?data -> f?v; m!data; m!v
:: f?ho_cmd -> /* handover command */
progress: f?v; m!ho_cmd; m!v;
if
:: f?ch_rel ->
f!m;
goto Passive
:: m?ho_fail ->
printf("MSC: FAILURE\n");
f!ho_fail
fi
od;
Passive:
printf("MSC: PASSIVE\n");
m?ho_acc -> f!ho_com;
goto Active
}
proctype MS(chan m) /* mobile station */
{ chan m_new;
mtype v;
do
:: m?data -> m?v; out!v
:: m?ho_cmd; m?m_new;
if
:: m_new!ho_acc; m = m_new
:: m!ho_fail
fi
od
}
active proctype System()
{
atomic {
run HC(m1);
run CC();
p_id = run BS(fp, m1, 0); /* passive base station */
a_id = run BS(fa, m2, 1); /* active base station */
run MS(m2)
}
end: do
:: in!red; in!white; in!blue
od
}
active proctype Out()
{
end: do /* deadlocks if order is disturbed */
:: out?red; out?white; out?blue
od
}

View file

@ -0,0 +1 @@
![] (zune_at_S -> <> zune_at_E)

View file

@ -0,0 +1,70 @@
/*
* input: days elapsed since Jan 1, 1980
* intended output: year and daynr in current year
*
* a bug caused all Zune-30 players to freeze on Dec 31, 2008
* http://www.zuneboards.com/forums/zune-news/38143-cause-zune-30-leapyear-problem-isolated.html
*
* Wikepedia:
* The bug was in the firmware clock-driver, which was written by Freescale
* for their MC13783 PMIC processor. The same bug froze up Toshiba Gigabeat S
* media players that share the same hardware and driver.
*/
#define IsLeapYear(y) (((y%4 == 0) && (y%100 != 0)) || (y%400 == 0))
chan q = [0] of { short };
active proctype zune()
{ short year = 1980;
short days;
end: do
:: q?days ->
S: do
:: days > 365 ->
if
:: IsLeapYear(year) ->
if
:: days > 366 ->
days = days - 366;
year++
:: else
#ifdef FIX
-> break
#endif
fi
:: else ->
days = days - 365;
year++
fi
:: else ->
break
od;
E: printf("Year: %d, Day %d\n", year, days)
od;
/* check that the date is in a valid range */
assert(days >= 1 && days <= 366);
assert(days < 366 || IsLeapYear(year))
}
init {
/* jan 1, 2008 */
short days = (2008 - 1980) * 365 + (2008-1980)/4;
if
:: q!days + 365
:: q!days + 366
:: q!days + 367
fi
}
#define zune_at_S zune@S
#define zune_at_E zune@E
/* sample analysis:
spin -a zune.pml
cc -o pan pan.c
./pan -a # find matches of formula
spin -t -p -l zune.pml # replay error sequence
*/