探索NuSMV来源中的国家空间

时间:2017-12-11 06:22:23

标签: model-checking nusmv

我正在进行一项计划修正/综合项目。我的任务是获取错误跟踪(反例),在完整的状态空间中找到它,并修复该位置的模型。我想将其实现为NuSMV扩展。

我一直在调试NuSMV以了解和探索它的源代码。到目前为止,我已经找到了创建BDD FSM的方法(compile.c第520行)。我试图找到一种遍历bdd的方法,以获得对状态空间的编程访问,从而对模型执行我的纠正工作。我还没有理解NuSMV用于通过bdd fsm验证属性的递归探索函数。

我想知道如何遍历bdd结构,以便我可以通过dot等工具对其进行可视化。我还想知道是否已经进行了这样或者微观的可视化(我已经搜索过但是空洞的)。其次,我想验证我所采用的方向是否正确,或者是否有更好的方法来获得给定模型的完整状态空间,并进行探索,特别是关于获得的反例通过NuSMV。

1 个答案:

答案 0 :(得分:0)

这是有关使用CUDD而不是通过NuSMV来处理二进制决策图(BDD)的方式的答案,因此请关注问题的第二部分。

关于研究状态空间的符号算法,Kesten,Pnueli和Raviv(ICALP '98,DOI:"Algorithmic verification of linear temporal logic specifications")发表的论文10.1007/BFb0055036是一个很好的介绍,涵盖了反例构造。 / p>

一种可视化BDD的可能性是在Python中使用Cython绑定到CUDD:

from dd import cudd


def dump_pdf_cudd():
    bdd = cudd.BDD()
    bdd.declare('x', 'y', 'z')
    u = bdd.add_expr('(x /\ y) \/ ~ z')
    bdd.dump('foo.pdf', [u])


if __name__ == '__main__':
    dump_pdf_cudd()

此方法使用dd,可以使用pippip install dd进行安装。可以找到文档here。查看(内部)模块dd._abc可能也很有帮助(这是一种规范;名称“ abc”暗示Python中的abstract base classes)。 (纯Python可以解决较小的问题,而CUDD可以解决较大的问题)。

enter image description here

与该问题有关的遍历有两种:

  1. BDD图的遍历
  2. 以状态为节点,步为边缘的图的遍历。

这些将在下面分别讨论。

遍历BDD图

使用BDD时,深度优先遍历比呼吸优先遍历更为普遍。 对于dd.cudddd.autoref的接口,遍历为:

from dd import autoref as _bdd


def demo_bdd_traversal():
    bdd = _bdd.BDD()
    bdd.declare('x', 'y')
    u = bdd.add_expr('x /\ y')
    print_bdd_nodes(u)


def print_bdd_nodes(u):
    visited = set()
    _print_bdd_nodes(u, visited)


def _print_bdd_nodes(u, visited):
    # terminal ?
    if u.var is None:
        print('terminal reached')
        return
    # non-terminal
    # already visited ?
    if u in visited:
        return
    # recurse
    v = u.low
    w = u.high
    # DFS pre-order
    print('found node {u}'.format(u=u))
    _print_bdd_nodes(v, visited)
    # DFS in-order
    print('back to node {u}'.format(u=u))
    _print_bdd_nodes(w, visited)
    # DFS post-order
    print('leaving node {u}'.format(u=u))
    # memoize
    visited.add(u)


if __name__ == '__main__':
    demo_bdd_traversal()
在使用BDD(使用CUDD或类似的库)时,还需要考虑

Complemented edges。属性u.negated提供了此信息。

函数dd.bdd.copy_bdd是遍历BDD的纯Python示例。此功能直接通过dd.autoref包装的“低级”界面来操作BDD,使其看起来与dd.cudd相同。

状态图的遍历

脚本dd/examples/reachability.py显示了如何以有限的步骤计算从哪些状态可以达到给定状态集。

dd相比,软件包omega更方便开发基于BDD的与系统行为相关的算法。脚本omega/examples/reachability_solver演示了使用omega的可达性计算。

使用omega == 0.3.1进行转发可达性的基本示例如下:

from omega.symbolic import temporal as trl
from omega.symbolic import prime as prm


def reachability_example():
    """How to find what states are reachable."""
    aut = trl.Automaton()
    vrs = dict(
        x=(0, 10),
        y=(3, 50))
    aut.declare_variables(**vrs)
    aut.varlist = dict(
        sys=['x', 'y'])
    aut.prime_varlists()
    s = r'''
        Init ==
            /\ x = 0
            /\ y = 45

        Next ==
            /\ (x' = IF x < 10 THEN x + 1 ELSE 0)
            /\ (y' = IF y > 5 THEN y - 1 ELSE 45)
        '''
    aut.define(s)
    init = aut.add_expr('Init', with_ops=True)
    action = aut.add_expr('Next', with_ops=True)
    reachable = reachable_states(init, action, vrs, aut)
    n = aut.count(reachable, care_vars=['x', 'y'])
    print('{n} states are reachable'.format(n=n))


def reachable_states(init, action, vrs, aut):
    """States reachable by `action` steps, starting from `init`."""
    operator = lambda y: image(y, action, vrs, aut)
    r = least_fixpoint(operator, init)
    assert prm.is_state_predicate(r)
    return r


def image(source, action, vrs, aut):
    """States reachable from `source` in one step that satisfies `action`."""
    u = source & action
    u = aut.exist(vrs, u)
    return aut.replace_with_unprimed(vrs, u)


def least_fixpoint(operator, target):
    """Least fixpoint of `operator`, starting from `target`."""
    y = target
    yold = None
    while y != yold:
        yold = y
        y |= operator(y)
    return y


if __name__ == '__main__':
    reachability_example()

omegadd进行比较:

  • omega支持变量和常量,以及它们的整数值(相关模块为omega.symbolic.temporal)。变量表示状态更改,例如xx'。常量通过系统行为保持不变。

  • dd仅支持布尔值变量(omega使用布尔值变量代表整数值变量,因此通过dd将谓词表示为BDD; bitblasting在模块omega.logic.bitvector中完成)。

omega.symbolic.fixpoint中实现了几个定点运算符。这些运算符可用于模型检查或temporal synthesis。模块omega.logic.past包含与符号模型检查(也称为temporal testers)相关的时间运算符的翻译。

可以找到hereomega文档。

更多评论

我在上面使用了术语“步骤”来表示一对连续状态,这些状态代表规范允许的状态变化。 Leslie Lamport的书Specifying Systems中介绍了TLA +语言和步骤,灵活灵活的变量和其他有用的概念。

https://github.com/johnyf/tool_lists/列出了一组正式的验证软件。

以我的经验,在Python级别上工作,仅在C级别上使用BDD管理器是一种有效的方法,可以使代码更可读,算法更清晰。