似乎Promela初始化每个变量(默认情况下,为0,或者声明中给出的值)。
如何声明由未知值初始化的变量?
文档提示if :: p = 0 :: p = 1 fi
,但我不这么认为
它的工作原理:Spin仍在验证此声明
bit p
init { if :: p = 0 :: p = 1 fi }
ltl { ! p }
(并伪造p
)
那么init
的语义到底是什么?还有一些
"预初始"州?我该如何解决这个问题 - 而不是混淆我的学生?
答案 0 :(得分:3)
这是一个有趣的问题。
documentation表示每个变量都初始化为0,除非模型另有说明。
与所有变量声明一样,显式初始化字段是可选的。所有变量的默认初始值均为零。这适用于标量变量和数组变量,它适用于全局变量和局部变量。
在您的模型中,在声明变量时不要初始化变量,因此随后将其分配给初始状态中的值0,该状态位于分配之前:
bit p
init {
// THE INITIAL STATE IS HERE
if
:: p = 0
:: p = 1
fi
}
ltl { ! p }
一些实验。
避免此限制的"天真" 想法是修改 pan.c 的 c源代码当你调用~$ spin -a test.pml
时由spin生成的,这样变量就会随机初始化。
而不是这个初始化函数:
void
iniglobals(int calling_pid)
{
now.p = 0;
#ifdef VAR_RANGES
logval("p", now.p);
#endif
}
可以尝试写这个:
void
iniglobals(int calling_pid)
{
srand(time(NULL));
now.p = rand() % 2;
#ifdef VAR_RANGES
logval("p", now.p);
#endif
}
并在标题部分添加#include <time.h>
。
但是,一旦将其编译为具有gcc pan.c
的验证程序,并且您尝试运行它,您将获得非确定性行为,具体取决于变量的初始化值p 强>
它可以确定该属性是否被违反:
~$ ./a.out -a
pan:1: assertion violated !( !( !(p))) (at depth 0)
pan: wrote test.pml.trail
(Spin Version 6.4.3 -- 16 December 2014)
Warning: Search not completed
+ 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 28 byte, depth reached 0, errors: 1
1 states, stored
0 states, matched
1 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.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
pan: elapsed time 0 seconds
或打印该物业满意:
~$ ./a.out -a
(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 28 byte, depth reached 0, errors: 0
1 states, stored
0 states, matched
1 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.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 init
test.pml:8, state 5, "-end-"
(1 of 5 states)
unreached in claim ltl_0
_spin_nvr.tmp:8, state 8, "-end-"
(1 of 8 states)
pan: elapsed time 0 seconds
显然, spin 验证的 promela模型的初始状态被认为是唯一的。 Afterall,这是一个合理的假设,因为它会不必要地使事情变得复杂:你总是可以用初始状态S s.t替换N个不同的初始状态S_i。 S允许通过epsilon转换到达每个S_i。在这种情况下,你得到的并不是真正的epsilon过渡,但在实践中它没什么区别。
编辑 (来自评论): 原则上,通过稍微修改 pan.c 可以使这项工作成为可能:
话虽如此,这可能不值得麻烦,除非通过修补 Spin 的源代码来完成。
解决方法。强>
如果你想在初始状态中说明某些事情是真的,或者从初始状态开始,并考虑到某些非确定性行为,那么你应该写下如下内容:
bit p
bool init_state = false
init {
if
:: p = 0
:: p = 1
fi
init_state = true // TARGET STATE
init_state = false
}
ltl { init_state & ! p }
你得到:
~$ ./a.out -a
pan:1: assertion violated !( !((initialised& !(p)))) (at depth 0)
pan: wrote 2.pml.trail
(Spin Version 6.4.3 -- 16 December 2014)
Warning: Search not completed
+ 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 28 byte, depth reached 0, errors: 1
1 states, stored
0 states, matched
1 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.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
pan: elapsed time 0 seconds
Init Semantics。
初始只是保证第一个产生过程,并且意味着用于产生其他过程例如,其他例程将输入一些参数,例如一些资源是共享的。更多信息here。
我认为documentation的这个片段有点误导:
init进程最常用于初始化全局变量, 并通过使用run来实例化其他进程 运算符,在系统执行开始之前。任何过程,而不仅仅是 init进程,可以这样做,但
由于可以保证init进程在使用atomic { }
语句的任何其他进程之前执行其所有代码,因此可以说它可以用于在之前初始化变量从编程的角度来看,它们被其他进程使用。但这只是一个粗略近似,因为init进程不对应于执行模型中的唯一状态,而是对应于根和状态树的状态。 root本身仅由全局环境给出,就像任何进程开始之前一样。