Model checking 如何在Spin中生成非初始化变量?

Model checking 如何在Spin中生成非初始化变量?,model-checking,spin,promela,Model Checking,Spin,Promela,Promela似乎初始化了每个变量(默认情况下,为0或声明中给定的值) 如何声明由未知值初始化的变量 文档建议if::p=0::p=1fi,但我不这么认为 它是有效的:Spin仍然证实了这一说法 bit p init { if :: p = 0 :: p = 1 fi } ltl { ! p } (和伪造p) 那么,init的语义到底是什么呢?还有一些 “初始前”状态?我如何才能解决这个问题,而不让我的学生感到困惑 这是一个有趣的问题 表示每个变量都初始化为0,除非模型另有规定 与

Promela似乎初始化了每个变量(默认情况下,为0或声明中给定的值)

如何声明由未知值初始化的变量

文档建议
if::p=0::p=1fi
,但我不这么认为 它是有效的:Spin仍然证实了这一说法

bit p 
init {   if ::  p = 0 :: p = 1 fi }
ltl {  ! p  }
(和伪造
p

那么,
init
的语义到底是什么呢?还有一些
“初始前”状态?我如何才能解决这个问题,而不让我的学生感到困惑

这是一个有趣的问题

表示每个变量都初始化为0,除非模型另有规定

与所有变量声明一样,显式初始化字段是可选的。所有变量的默认初始值为零。这适用于标量变量和数组变量,也适用于全局变量和局部变量

在您的模型中,声明变量时不初始化变量,因此随后会在初始状态下将其赋值给值0,该值位于赋值之前:

bit p

init {
  // THE INITIAL STATE IS HERE
  if
    :: p = 0
    :: p = 1
  fi
}

ltl {  ! p  }

一些实验。

为了避免这种限制,一个“幼稚”的想法是在调用
~$spin-A test.pml
时修改由spin生成的pan.c的c源代码,以便随机初始化变量

代替此初始化功能:

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

但是,一旦您使用
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
显然,假设由自旋验证的promela模型的初始状态是唯一的。毕竟,这是一个合理的假设,因为它会不必要地使事情复杂化:你总是可以用一个初始状态s.t.s替换N个不同的初始状态s_i。s允许通过ε转换到达每个s_i。在这种情况下,你得到的不是真正的ε转换,但在实践中,它几乎没有什么区别

编辑(来自评论): 原则上,可以通过进一步修改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语义。

Init仅保证是第一个生成的进程,并用于生成其他进程,例如,当其他例程将某些参数(例如,共享某些资源)作为输入时。更多信息

我认为这段文字有点误导:

初始化过程最常用于初始化全局变量, 以及通过使用run来实例化其他流程 操作员,在系统执行开始之前。任何过程,而不仅仅是 不过,init进程可以这样做


由于可以使用
原子{}
语句保证init进程在任何其他进程之前执行其所有代码,因此从编程的角度来看,可以说它可以用于在其他进程使用变量之前初始化变量。但这只是一个粗略的近似值,因为init进程并不对应于执行模型中的唯一状态,而是对应于根的状态树,根本身只由全局环境给出,就像任何进程开始之前一样。

是的,这种解决方法看起来是合理的。在我的应用程序中,我在主进程中有
do::p=0::p=1 od
(请参阅),因此我还可以在声明中放置
X
操作符。我仍然认为Promela应该有不确定的初始化(比如
位p=?
)。我不知道在哪里需要init确定性来进行模拟或验证。我同意你的观点,支持非确定性初始化不会有技术困难,尽管在处理可能值范围非常大的数据类型时会出现性能问题,除非也提供了限制范围的方法。但是我真的说不出他们为什么要这样设计语言,除了可能是为了简化一些事情。原则上,你可以修改pan.c,使它使用一个初始状态生成器而不是一个初始化器,并考虑到存在多个初始状态的可能性。除此之外,任何事情都不会改变,验证者将报告正确的结果。但在这一点上,最好是简单地修补spin以支持这种行为,即使它不是Promela规范语言的标准。