In general, that's not possible. An LTL formula expresses a property that must hold over an execution path, whereas by definition of minimum, you want to express a property over multiple execution paths. In fact N is considered minimum only if there is no other execution trace in which it has a smaller value.
Work-around. You can, however, find the minimum value of N
by running Spin
multiple times over an LTL
formula with an increasing value for N
, and examine the output to determine the correct answer.
Consider this example:
byte N = 0;
short cend = 0;
active [2] proctype P(){
byte temp, i;
i = 1;
do
:: i < 10 ->
temp = N;
temp++;
N = temp;
i++;
:: else ->
break;
od
cend++;
}
ltl p0 { [] ((cend == 2) -> 2 <= N) };
ltl p1 { [] ((cend == 2) -> 3 <= N) };
We have two properties:
p0
states that it is globally true that when both processes terminate the value of N
is at least 2
. This formula is verified:
~$ spin -a -search -bfs -ltl p0 m.pml
...
Full statespace search for:
never claim + (p0)
assertion violations + (if within scope of claim)
cycle checks - (disabled by -DSAFETY)
invalid end states - (disabled by never claim)
State-vector 36 byte, depth reached 98, errors: 0
...
p1
states that it is globally true that when both processes terminate the value of N
is at least 3
. This formula is not verified:
~$ spin -a -search -bfs -ltl p1 m.pml
...
Full statespace search for:
never claim + (p1)
assertion violations + (if within scope of claim)
cycle checks - (disabled by -DSAFETY)
invalid end states - (disabled by never claim)
State-vector 36 byte, depth reached 95, errors: 1
...
So we know that the minimum value of N
is equal to 2
.
Let's see the counter-example:
~$ spin -l -g -p -t m.pml
ltl p0: [] ((! ((cend==2))) || ((2<=N)))
ltl p1: [] ((! ((cend==2))) || ((3<=N)))
starting claim 2
using statement merging
1: proc 1 (P:1) m.pml:7 (state 1) [i = 1]
P(1):i = 1
2: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
3: proc 0 (P:1) m.pml:7 (state 1) [i = 1]
P(0):i = 1
4: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
5: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 0
6: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 1
7: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 0
8: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 1
9: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 1
10: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 2
11: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
12: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 1
13: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 2
14: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 2
15: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 3
16: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
17: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 2
18: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 3
19: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 3
20: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 4
21: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
22: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 3
23: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 4
24: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 4
25: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 5
26: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
27: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 4
28: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 5
29: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 5
30: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 6
31: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
32: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 5
33: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 6
34: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 6
35: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 7
36: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
37: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 6
38: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 7
39: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 7
40: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 8
41: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
42: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 7
43: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 8
44: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 8
45: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 9
46: proc 1 (P:1) m.pml:9 (state 2) [((i<10))]
47: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 1
48: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 2
49: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
50: proc 1 (P:1) m.pml:10 (state 3) [temp = N]
P(1):temp = 1
51: proc 1 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(1):temp = 2
52: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 1
53: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 2
54: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 2
55: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 3
56: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
57: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 2
58: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 3
59: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 3
60: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 4
61: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
62: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 3
63: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 4
64: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 4
65: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 5
66: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
67: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 4
68: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 5
69: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 5
70: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 6
71: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
72: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 5
73: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 6
74: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 6
75: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 7
76: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
77: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 6
78: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 7
79: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 7
80: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 8
81: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
82: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 7
83: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 8
84: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 8
85: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 9
86: proc 0 (P:1) m.pml:9 (state 2) [((i<10))]
87: proc 0 (P:1) m.pml:10 (state 3) [temp = N]
P(0):temp = 8
88: proc 0 (P:1) m.pml:11 (state 4) [temp = (temp+1)]
P(0):temp = 9
89: proc 0 (P:1) m.pml:12 (state 5) [N = temp]
N = 9
90: proc 0 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(0):i = 10
91: proc 0 (P:1) m.pml:14 (state 7) [else]
92: proc 1 (P:1) m.pml:12 (state 5) [N = temp]
N = 2
93: proc 1 (P:1) m.pml:13 (state 6) [i = (i+1)]
P(1):i = 10
94: proc 1 (P:1) m.pml:14 (state 7) [else]
95: proc 0 (P:1) m.pml:17 (state 12) [cend = (cend+1)]
cend = 1
96: proc 1 (P:1) m.pml:17 (state 12) [cend = (cend+1)]
cend = 2
spin: trail ends after 96 steps
#processes: 2
N = 2
cend = 2
96: proc 1 (P:1) m.pml:18 (state 13) <valid end state>
96: proc 0 (P:1) m.pml:18 (state 13) <valid end state>
96: proc - (p1:1) _spin_nvr.tmp:11 (state 6)
2 processes created
As you can see, the counter-example corresponds to an execution in which:
proc0
stores the value N = 0
into temp
and then stops executing any instruction
proc1
increments the value of N
for 8
times
proc0
resets the value of N
back to 1
proc1
copies N = 1
in temp
and then stops executing any instruction
proc0
increments N
up to 9
and then terminates
proc1
resets the value of N
back to 2
and then terminates