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

Dafny can't verify multiple iterators in while loop

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

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 有一个空的修改子句。我需要添加循环不变量吗?

好的,这个很有趣 :)

这是您需要验证的额外不变量

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

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

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

我发现这个问题的方式是 Dafny 抱怨 iter2.Valid() 在调用 iter1.MoveNext() 后可能无法保持。任何时候在调用之前为真的谓词在调用之后可能不为真,你知道问题是 Dafny 无法证明函数的读取子句没有与方法的修改子句重叠。不幸的是,迭代器的 Valid() 谓词的 reads 子句和迭代器的 MoveNext() 方法的修改子句都没有记录。我深入研究了 Dafny 的 Boogie 输出,并能够按如下方式对它们进行逆向工程

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

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

我还看到 Dafny 可以证明 Iter1Iter2 都有空的 _reads_modifies 集合。所以实际上它只是引用本身,以及它们的 _new 集。这解释了不变量。