Traffic light spin - semaphore

First I need to say Im very new on this and I have to do a semaphore with some conditions.
We will only model one traffic light per each direction (the second one just repeats the same behaviour). For instance, in the picture above, the vertical light is green and the horizontal one is red. Initially, both directions are red. When a car arrives, it is detected by a sensor and its corresponding light turns to green. However, this only happens if the other direction is still in red; otherwise, it will wait until the other direction is closed. Once any direction is in green, it will turn next to orange (there is a timer, but we will not model the delay) and then it will turn to red again.
Actually this is my code right now:
mtype = { red, yellow, green };
mtype light0 = red;
mtype light1 = red;
active proctype TL0() {
do
:: if
:: light0 == red -> Ered: atomic {
light1 == red; /* wait*/
light0 = green;
}
:: light0 == green -> EY: light0 = yellow
:: light0 == yellow -> EG: light0 =red
fi;
printf("The light0 is now %e\n", light0)
od
}
active proctype TL1() {
do
:: if
:: light1 == red -> Ered: atomic {
light0 == red; /* wait*/
light1 = green;
}
:: light1 == green -> EY: light1 = yellow
:: light1 == yellow -> EG: light1 =red
fi;
printf("The light1 is now %e\n", light1)
od
}
The problem is that when I use
spin -a -f '<>(!TL0#Ered && !TL1#Ered)' sem3.pml
for check the safety I get one erorr.
warning: never claim + accept labels requires -a flag to fully verify
warning: for p.o. reduction to be valid the never claim must be
stutter-invariant (never claims generated from LTL formulae are
stutter-invariant) pan:1: assertion violated !(( !((TL0._p==Ered))&&
!((TL1._p==Ered)))) (at depth 0) pan: wrote sem3.pml.trail
(Spin Version 6.4.8 -- 2 March 2018) Warning: Search not completed +
Partial Order Reduction
Full statespace search for: never claim + (never_0)
assertion violations + (if within scope of claim) acceptance
cycles - (not selected) invalid end states - (disabled by -E flag)
State-vector 36 byte, depth reached 0, errors: 1
1 states, stored
0 states, matched
1 transitions (= stored+matched)
0 atomic steps hash conflicts: 0 (resolved)
But actually I have no idea wheres the problem :(
Hope someone could help me
Thx!

The model is fine, but I would suggest you to manually generate the verifier.
First, add the following lines at the bottom of your file:
ltl p1 { <>(!TL0#Ered && !TL1#Ered) };
ltl p2 { [] !(TL0#EY && TL1#EY) }; // perhaps you wanted (something like) this?
Then, generate the verifier:
~$ spin -a file_name.pml
~$ gcc -o run pan.c
~$ ./run -a -N p1
...
~$ ./run -a -N p2
...

Related

Why an infinite loop doesn't result in an error in model checking with Promela and Spin?

If I write the following code in Promela and run it in Spin in verifier mode it ends with 0 errors. It does report that toogle and init had unreached states, but those seem to be only warnings.
byte x = 0; byte y = 0;
active proctype toggle() {
do
:: x == 1 -> x = 0
:: x == 0 -> x = 1
od
}
init {
(y == 1);
}
I was confused by this because I thought this would give me a 'invalid end state' error. If I change the body of the toogle proctype with a simple skip statement it does error out as I expected.
Why is this? Is there a way to force the simulator to report the infinite loop as an error?
Regarding the 'unreached in proctype' messages, adding an end label to the do loop doesn't seem to do anything.
I am running spin 6.5.0 and ran the following commands:
spin.exe -a test.pml
gcc -o pan pan.c
pan.exe
These are the outputs, for reference.
With do loop:
pan.exe
(Spin Version 6.5.0 -- 1 July 2019)
+ Partial Order Reduction
Full statespace search for:
never claim - (none specified)
assertion violations +
acceptance cycles - (not selected)
invalid end states +
State-vector 20 byte, depth reached 3, errors: 0
4 states, stored
1 states, matched
5 transitions (= stored+matched)
0 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.000 equivalent memory usage for states (stored*(State-vector + overhead))
0.292 actual memory usage for states
64.000 memory used for hash table (-w24)
0.343 memory used for DFS stack (-m10000)
64.539 total actual memory usage
unreached in proctype toggle
..\test2.pml:7, state 8, "-end-"
(1 of 8 states)
unreached in init
..\test2.pml:10, state 2, "-end-"
(1 of 2 states)
pan: elapsed time 0.013 seconds
pan: rate 307.69231 states/second
With skip:
pan.exe
pan:1: invalid end state (at depth 0)
pan: wrote ..\test2.pml.trail
(Spin Version 6.5.0 -- 1 July 2019)
Warning: Search not completed
+ Partial Order Reduction
Full statespace search for:
never claim - (none specified)
assertion violations +
acceptance cycles - (not selected)
invalid end states +
State-vector 20 byte, depth reached 1, errors: 1
2 states, stored
0 states, matched
2 transitions (= stored+matched)
0 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.000 equivalent memory usage for states (stored*(State-vector + overhead))
0.293 actual memory usage for states
64.000 memory used for hash table (-w24)
0.343 memory used for DFS stack (-m10000)
64.539 total actual memory usage
pan: elapsed time 0.015 seconds
pan: rate 133.33333 states/second
In this example
byte x = 0; byte y = 0;
active proctype toggle() {
do
:: x == 1 -> x = 0
:: x == 0 -> x = 1
od
}
init {
(y == 1);
}
the init process is blocked forever (because y == 1 is always false), but the toggle process can always execute something. Therefore, there is no invalid end state error.
Instead, in this example
byte x = 0; byte y = 0;
active proctype toggle() {
skip;
}
init {
(y == 1);
}
the init process is still blocked forever, but the toggle process can execute its only instruction skip; and then terminate. At this point, none of the remaining processes (i.e. only init) has any instruction it can execute, so Spin terminates with an invalid end state error.
~$ spin -a -search test.pml
pan:1: invalid end state (at depth 0)
pan: wrote test.pml.trail
(Spin Version 6.5.0 -- 17 July 2019)
...
State-vector 20 byte, depth reached 1, errors: 1
...
Is there a way to force the simulator to report the infinite loop as an error?
Yes. There are actually multiple ways.
The simplest approach is to use option -l of Spin:
~$ spin --help
...
-l: search for non-progress cycles
...
With this option, Spin reports any infinite-loop which does not contain any state with a progress label.
This is the output on your original problem:
~$ spin -search -l test.pml
pan:1: non-progress cycle (at depth 2)
pan: wrote test.pml.trail
(Spin Version 6.5.0 -- 17 July 2019)
...
State-vector 28 byte, depth reached 9, errors: 1
...
~$ spin -t test.pml
spin: couldn't find claim 2 (ignored)
<<<<<START OF CYCLE>>>>>
spin: trail ends after 10 steps
#processes: 2
x = 0
y = 0
10: proc 1 (:init::1) test.pml:10 (state 1)
10: proc 0 (toggle:1) test.pml:5 (state 4)
2 processes created
An alternative approach is to use LTL model checking. For instance, you may state that at some point the number of processes (see _nr_pr) that are in execution becomes equal to 0 (or more, if you admit some infinite loops), or check that a particular process terminates correctly using remote references.
Both cases are contained in the following example:
byte x = 0; byte y = 0;
active proctype toggle() {
do
:: x == 1 -> x = 0
:: x == 0 -> x = 1
od;
end:
}
init {
(y == 1);
}
// sooner or later, the process toggle
// with _pid == 0 will reach the end
// state
ltl p1 { <> toggle[0]#end };
// sooner or later, the number of processes
// that are currently running becomes 0,
// (hence, there can be no infinite loops)
ltl p2 { <> (_nr_pr == 0) };
Both the first
~$ spin -a -search -ltl p1 test.pml
~$ spin -t test.pml
ltl p1: <> ((toggle[0]#end))
ltl p2: <> ((_nr_pr==0))
<<<<<START OF CYCLE>>>>>
Never claim moves to line 4 [(!((toggle[0]._p==end)))]
spin: trail ends after 8 steps
#processes: 2
x = 0
y = 0
end = 0
8: proc 1 (:init::1) test.pml:10 (state 1)
8: proc 0 (toggle:1) test.pml:3 (state 5)
8: proc - (p1:1) _spin_nvr.tmp:3 (state 3)
2 processes created
and the second
~$ spin -a -search -ltl p2 test.pml
~$ spin -t test.pml
ltl p1: <> ((toggle[0]#end))
ltl p2: <> ((_nr_pr==0))
<<<<<START OF CYCLE>>>>>
Never claim moves to line 11 [(!((_nr_pr==0)))]
spin: trail ends after 8 steps
#processes: 2
x = 0
y = 0
end = 0
8: proc 1 (:init::1) test.pml:10 (state 1)
8: proc 0 (toggle:1) test.pml:3 (state 5)
8: proc - (p2:1) _spin_nvr.tmp:10 (state 3)
2 processes created
LTL properties are found to be false.
Regarding the 'unreached in proctype' messages, adding an end label to the do loop doesn't seem to do anything.
The end label(s) are used to remove the "invalid end state" error that would be otherwise be found.
For example, modifying your previous example as follows:
byte x = 0; byte y = 0;
active proctype toggle() {
skip;
}
init {
end:
(y == 1);
}
Makes the error go away:
~$ spin -a -search test.pml
(Spin Version 6.5.0 -- 17 July 2019)
...
State-vector 20 byte, depth reached 1, errors: 0
...
One should only ever use an end label when one is willing to guarantee that a process being stuck with no executable instruction is not a symptom of an undesired deadlock situation.

Undeclared variable error when using mtype with Jspin

I am new to Jspin and Promela. I tried to implement the following system:
A home alarm system can be activated and deactivated using a personal ID key or password, after  activation the system enters a waiting period of about 30 seconds, time that allows users to evacuate the  secured area after which the alarm is armed, also when an intrusion is detected the alarm has a built in waiting period or delay of 15 seconds to allow the intruder to enter the password or swipe the card key thus identifying himself, in case that the identification is not made within the allocated 15 seconds the alarm  will go off and will be on until an id card or password is used to deactivate it.
This is the code:
mtype = {sigact, sigdeact};
chan signal = [0] of {mtype};
/*chan syntax for declaring and initializing message passing channels*/
int count;
bool alarm_off = true; /*The initial state of the alarm is off*/
active proctype alarm()
{
off:
if
:: count >= 30 -> atomic {signal!sigdeact; count = 0;alarm_off = false; goto on;}
:: else -> atomic {count++; alarm_off = true; goto off;}
fi;
on:
if
:: count >=15 -> atomic { signal!sigact; count = 0;
alarm_off = false; goto off;}
:: else -> atomic {signal!sigact; alarm_off = true; goto off;}
fi;
pending:
if
:: count >= 30 -> atomic {count = 0; alarm_off = false; goto on;}
:: count < 30 -> atomic {count++; alarm_off = false; goto pending;}
fi;
}
When I run the code with Jspin I get this message:
Error: undeclared variable: sigact
But I declared this in the header.
How can I solve this?
According to the documentation of Promela, you are using mtype correctly.
In fact, I cannot reproduce your error with spin version 6.4.3, so I suspect this is a specific issue of Jspin not being correctly updated.
Unless you want to use spin instead of Jspin, you can try the following work-around, which should work even with Jspin:
#define sigact 0
#define sigdeact 1
chan signal = [0] of {short}; // or bool for only 2 values
...
Since no one ever reads from signal, I assume the system model is incomplete and that more processes will be added later on.
Be aware that, in the following instruction sequence:
atomic { signal!sigdeact; count = 0; alarm_off = false; goto on; }
the atomicity will be temporarily lost by alarm because signal is a synchronous channel (it has size 0) and so another process has to be immediately scheduled for reading the message being sent.
In off state, when count >= 30 you reset count back to 0, set alarm_off = false and then go to state on. In on state, you immediately set alarm_off back to true. Is this intended? It looks like some mistake, perhaps you meant to go to state pending.
By reading the description of your system, it looks like the alarm is missing some kind of input signal. I suspect you are using the signal channel differently from its intended purpose.
Shouldn't the model have some transition from state pending to off, in case the proper personal ID/password is used?

Promela SPIN unreached in proctype error

I'm pretty new to SPIN and Promela and I came across this error when I'm trying to verify the liveness property in my models.
Error code:
unreached in proctype P
(0 of 29 states)
unreached in proctype monitor
mutex_assert.pml:39, state 1, "assert(!((mutex>1)))"
mutex_assert.pml:42, state 2, "-end-"
(2 of 2 states)
unreached in init
(0 of 3 states)
unreached in claim ltl_0
_spin_nvr.tmp:10, state 13, "-end-"
(1 of 13 states)
pan: elapsed time 0 seconds
The code is basically an implementation of Peterson's algorithm and I checked for safety and it seems to be valid. But whenever I try to validate the liveness property using the ltl {[]((wait -> <> (cs)))}, it comes up with the above errors. I'm not sure what they mean so I don't know how to proceed...
My code is as follows:
#define N 3
#define wait (P[1]#WAIT)
#define cs (P[1]#CRITICAL)
int pos[N];
int step[N];
int enter;
byte mutex;
ltl {[]((wait -> <> (cs)))}
proctype P(int i) {
int t;
int k;
WAIT:
for (t : 1 .. (N-1)){
pos[i] = t
step[t] = i
k = 0;
do
:: atomic {(k != i && k < N && (pos[k] < t|| step[t] != i)) -> k++}
:: atomic {k == i -> k++}
:: atomic {k == N -> break}
od;
}
CRITICAL:
atomic {mutex++;
printf("MSC: P(%d) HAS ENTERED THE CRITICAL SECTION.\n", i);
mutex--;}
pos[i] = 0;
}
init {
atomic { run P(0); }
}
General Answer
This is a warning telling you that some states are unreachable due to transitions that are never taken.
In general, this is not an error, but it is a good practice to take a close look to the unreachable states for every routine that you modelled, and check that you expect none of them to be reachable. i.e. in the case the model is not correct wrt. the intended behaviour.
Note. You can use the label end: in front of a particular line of code to mark valid terminating states, so to get rid of those warnings, e.g. when your procedure does not terminate. More info here.
Specific Answer
I can not reproduce your output. In particular, by running
~$ spin -a file.pml
~$ gcc pan.c
~$ ./a.out -a
I get the following output, which is different from yours:
(Spin Version 6.4.3 -- 16 December 2014)
+ Partial Order Reduction
Full statespace search for:
never claim + (ltl_0)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 64 byte, depth reached 47, errors: 0
41 states, stored (58 visited)
18 states, matched
76 transitions (= visited+matched)
0 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.004 equivalent memory usage for states (stored*(State-vector + overhead))
0.288 actual memory usage for states
128.000 memory used for hash table (-w24)
0.534 memory used for DFS stack (-m10000)
128.730 total actual memory usage
unreached in proctype P
(0 of 29 states)
unreached in init
(0 of 3 states)
unreached in claim ltl_0
_spin_nvr.tmp:10, state 13, "-end-"
(1 of 13 states)
pan: elapsed time 0 seconds
In particular, I lack the warnings about the unreached states in the monitor process. As far as I am concerned, juding from the source code, none of the warnings I obtained is problematic.
Either you are using a different version of Spin than me, or you did not include the full source code in your question. In the latter case, could you edit your question and add the code? I'll update my answer afterwards.
EDIT: in the comments, you ask what does the following message mean: "unreached in claim ltl_0 _spin_nvr.tmp:10, state 13, "-end-"".
If you open the file _spin_nvr.tmp, you can see the following piece of Promela code, which corresponds to a Büchi automaton that accepts all and only the execution which violate your ltl property []((wait -> <> (cs))).
never ltl_0 { /* !([] ((! ((P[1]#WAIT))) || (<> ((P[1]#CRITICAL))))) */
T0_init:
do
:: (! ((! ((P[1]#WAIT)))) && ! (((P[1]#CRITICAL)))) -> goto accept_S4
:: (1) -> goto T0_init
od;
accept_S4:
do
:: (! (((P[1]#CRITICAL)))) -> goto accept_S4
od;
}
The message simply warns you that the execution of this code will never reach the last closing bracket } (state "-end-"), meaning that the procedure does never terminate.

Ask for multiple (or all) violation traces in Spin

Is it possible to get multiple (or all) violation traces for a property using Spin?
As an example, I created the Promela model below:
byte mutex = 0;
active proctype A() {
A1: mutex==0; /* Is free? */
A2: mutex++; /* Get mutex */
A3: /* A's critical section */
A4: mutex--; /* Release mutex */
}
active proctype B() {
B1: mutex==0; /* Is free? */
B2: mutex++; /* Get mutex */
B3: /* B's critical section */
B4: mutex--; /* Release mutex */
}
ltl {[] (mutex < 2)}
It has a naive mutex implementation. One could expect that processes A and B would not reach their critical section together and I wrote an LTL expression to check that.
Running
spin -run mutex_example.pml
shows that the property is not valid and running
spin -p -t mutex_example.pml
show the sequence of statements that violate the property.
Never claim moves to line 4 [(1)]
2: proc 1 (B:1) mutex_example.pml:11 (state 1) [((mutex==0))]
4: proc 0 (A:1) mutex_example.pml:4 (state 1) [((mutex==0))]
6: proc 1 (B:1) mutex_example.pml:12 (state 2) [mutex = (mutex+1)]
8: proc 0 (A:1) mutex_example.pml:5 (state 2) [mutex = (mutex+1)]
spin: _spin_nvr.tmp:3, Error: assertion violated
spin: text of failed assertion: assert(!(!((mutex<2))))
Never claim moves to line 3 [assert(!(!((mutex<2))))]
spin: trail ends after 9 steps
#processes: 2
mutex = 2
9: proc 1 (B:1) mutex_example.pml:14 (state 3)
9: proc 0 (A:1) mutex_example.pml:7 (state 3)
9: proc - (ltl_0:1) _spin_nvr.tmp:2 (state 6)
This shows that the sequence of statements (indicated by labels) 'B1' -> 'A1' -> 'B2' -> 'A2' violate the property but there are other interleaving options leading to that (e.g. 'A1' -> 'B1' -> 'B2' -> 'A2').
Can I ask Spin to give me multiple (or all) traces?
I doubt that you can get all violation traces in Spin.
For example, if we consider the following model, then there are infinitely many counter-examples.
byte mutex = 0;
active [2] proctype P() {
do
:: mutex == 0 ->
mutex++;
/* critical section */
mutex--;
od
}
ltl {[] (mutex <= 1)}
What you can do, is to use different search algorithms for your verifier, and this might yield some different counter-examples
-search (or -run) generate a verifier, and compile and run it
options before -search are interpreted by spin to parse the input
options following a -search are used to compile and run the verifier pan
valid options that can follow a -search argument include:
-bfs perform a breadth-first search
-bfspar perform a parallel breadth-first search
-bcs use the bounded-context-switching algorithm
-bitstate or -bit, use bitstate storage
-biterate use bitstate with iterative search refinement (-w18..-w35)
-swarmN,M like -biterate, but running all iterations in parallel
perform N parallel runs and increment -w every M runs
default value for N is 10, default for M is 1
-link file.c link executable pan to file.c
-collapse use collapse state compression
-hc use hash-compact storage
-noclaim ignore all ltl and never claims
-p_permute use process scheduling order permutation
-p_rotateN use process scheduling order rotation by N
-p_reverse use process scheduling order reversal
-ltl p verify the ltl property named p
-safety compile for safety properties only
-i use the dfs iterative shortening algorithm
-a search for acceptance cycles
-l search for non-progress cycles
similarly, a -D... parameter can be specified to modify the compilation
and any valid runtime pan argument can be specified for the verification

LTL model checking using Spin and Promela syntax

I'm trying to reproduce ALGOL 60 code written by Dijkstra in the paper titled "Cooperating sequential processes", the code is the first attempt to solve the mutex problem, here is the syntax:
begin integer turn; turn:= 1;
parbegin
process 1: begin Ll: if turn = 2 then goto Ll;
critical section 1;
turn:= 2;
remainder of cycle 1; goto L1
end;
process 2: begin L2: if turn = 1 then goto L2;
critical section 2;
turn:= 1;
remainder of cycle 2; goto L2
end
parend
end
So I tried to reproduce the above code in Promela and here is my code:
#define true 1
#define Aturn true
#define Bturn false
bool turn, status;
active proctype A()
{
L1: (turn == 1);
status = Aturn;
goto L1;
/* critical section */
turn = 1;
}
active proctype B()
{
L2: (turn == 2);
status = Bturn;
goto L2;
/* critical section */
turn = 2;
}
never{ /* ![]p */
if
:: (!status) -> skip
fi;
}
init
{ turn = 1;
run A(); run B();
}
What I'm trying to do is, verify that the fairness property will never hold because the label L1 is running infinitely.
The issue here is that my never claim block is not producing any error, the output I get simply says that my statement was never reached..
here is the actual output from iSpin
spin -a dekker.pml
gcc -DMEMLIM=1024 -O2 -DXUSAFE -DSAFETY -DNOCLAIM -w -o pan pan.c
./pan -m10000
Pid: 46025
(Spin Version 6.2.3 -- 24 October 2012)
+ Partial Order Reduction
Full statespace search for:
never claim - (not selected)
assertion violations +
cycle checks - (disabled by -DSAFETY)
invalid end states +
State-vector 44 byte, depth reached 8, errors: 0
11 states, stored
9 states, matched
20 transitions (= stored+matched)
0 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.001 equivalent memory usage for states (stored*(State-vector + overhead))
0.291 actual memory usage for states
128.000 memory used for hash table (-w24)
0.534 memory used for DFS stack (-m10000)
128.730 total actual memory usage
unreached in proctype A
dekker.pml:13, state 4, "turn = 1"
dekker.pml:15, state 5, "-end-"
(2 of 5 states)
unreached in proctype B
dekker.pml:20, state 2, "status = 0"
dekker.pml:23, state 4, "turn = 2"
dekker.pml:24, state 5, "-end-"
(3 of 5 states)
unreached in claim never_0
dekker.pml:30, state 5, "-end-"
(1 of 5 states)
unreached in init
(0 of 4 states)
pan: elapsed time 0 seconds
No errors found -- did you verify all claims?
I've read all the documentation of spin on the never{..} block but couldn't find my answer (here is the link), also I've tried using ltl{..} blocks as well (link) but that just gave me syntax error, even though its explicitly mentioned in the documentation that it can be outside the init and proctypes, can someone help me correct this code please?
Thank you
You've redefined 'true' which can't possibly be good. I axed that redefinition and the never claim fails. But, the failure is immaterial to your goal - that initial state of 'status' is 'false' and thus the never claim exits, which is a failure.
Also, it is slightly bad form to assign 1 or 0 to a bool; assign true or false instead - or use bit. Why not follow the Dijkstra code more closely - use an 'int' or 'byte'. It is not as if performance will be an issue in this problem.
You don't need 'active' if you are going to call 'run' - just one or the other.
My translation of 'process 1' would be:
proctype A ()
{
L1: turn !=2 ->
/* critical section */
status = Aturn;
turn = 2
/* remainder of cycle 1 */
goto L1;
}
but I could be wrong on that.

Resources