Dafny无法在while循环中验证多个迭代器

时间:2019-08-06 19:14:03

标签: dafny

我想要一个分配两个迭代器的函数,然后进入一个循环,只要MoveNext()返回true,该循环便会在迭代器上重复调用MoveNext()。但是,在迭代器上调用MoveNext()会违反(或阻止Dafny验证)另一个迭代器所需的不变式:

iterator Iter1()
{ yield; }

iterator Iter2()
{ yield; }

method main()
    decreases *
{
    var iter1 := new Iter1();
    var iter2 := new Iter2();
    var iter1More := true;
    var iter2More := true;

    while (iter1More || iter2More)
        invariant iter1More ==> iter1.Valid() && fresh(iter1._new)
        // The following invariant is not verified
        invariant iter2More ==> iter2.Valid() && fresh(iter2._new)
        decreases *
    {
        if (iter1More) {
            iter1More := iter1.MoveNext();
        }
    }
}

Dafny无法验证iter2More ==> iter2.Valid() && fresh(iter2._new),即使Iter1的修改子句为空。我需要添加一个循环不变式吗?

1 个答案:

答案 0 :(得分:1)

好的,这个很有趣:)

这是您需要验证的其他不变式

invariant {iter1} + iter1._new !! {iter2} + iter2._new

这个不变量也足以证明调用两个迭代器的更复杂的循环,如下所示:

    if (iterMore1) {
        iterMore1 := iter1.MoveNext();
    }
    if (iterMore2) {
        iterMore2 := iter2.MoveNext();
    }

我发现这个问题的方式是,达夫妮抱怨iter2.Valid()在调用iter1.MoveNext()之后可能不成立。任何时候在调用之前为真的谓词可能在调用之后都不为真时,您就会知道问题是Dafny无法证明该函数的reads子句与该方法的Modifys子句不重叠。不幸的是,没有记录迭代器的Valid()谓词的reads子句,也没有记录迭代器的MoveNext()方法的Modifys子句。我深入研究了Dafny的Boogie输出,并能够如下对它们进行反向工程

predicate Valid()
  reads this, this._reads, this._new

method MoveNext()
  modifies this, this._modifies, old(this._new)

我还可以看到Dafny可以证明Iter1Iter2都具有空的_reads_modifies集。因此,实际上只是引用本身及其_new集。这解释了不变性。