【问题标题】:Why does this Dafny assertion involving arrays fail?为什么这个涉及数组的 Dafny 断言会失败?
【发布时间】:2015-07-25 18:21:09
【问题描述】:

我正在研究经过验证的高斯消除实现,但在验证这种将数组 b 的内容添加到数组 a 的内容的超级简单方法时遇到问题。这是代码。

method addAssign(a: array<real>, b: array<real>)
   requires a != null && b != null && a.Length == b.Length;
   modifies a
   ensures forall k:: 0 <= k < a.Length ==> a[k] == old(a[k]) + b[k];
{
   var i := 0;
   assert a == old(a);
   while(i < a.Length)
      invariant 0 <= i <= a.Length
      invariant forall k:: i <= k < a.Length ==> a[k] == old(a[k])
      invariant forall k:: 0 <= k < i ==> a[k] == old(a[k]) + b[k];
   {
      assert a[i] == old(a[i]); // dafny verifies this
      a[i] := a[i] + b[i];
      assert a[i] == old(a[i]) + b[i]; // dafny says this is an assertion violation
      i := i + 1;
   }
}

【问题讨论】:

    标签: arrays verification dafny


    【解决方案1】:

    (我删除了我的第一个答案,因为它不起作用)。

    问题似乎在于 Dafny 检测到了潜在的混叠问题。作为一个实验,我首先修改了你的代码以获得一个更简单的函数来验证:

    method addOne(a: array<real>)
       requires a != null;
       modifies a;
       ensures forall k:: 0 <= k < a.Length ==> a[k] == old(a[k]) + 1.0;
    {
       var i := 0;
       assert a == old(a);
       while(i < a.Length)
          invariant 0 <= i <= a.Length
          invariant forall k:: i <= k < a.Length ==> a[k] == old(a[k])
          invariant forall k:: 0 <= k < i ==> a[k] == old(a[k]) + 1.0;
       {
          assert a[i] == old(a[i]); // dafny verifies this
          a[i] := a[i] + 1.0;
          assert a[i] == old(a[i]) + 1.0; // dafny *doesn't* say this is an assertion violation
          i := i + 1;
       }
    }
    

    唯一的区别是我使用的是文字实数 (1.0) 而不是从b 提取的实数。为什么会有所作为?

    假设您使用看起来像

    的调用来调用您的方法
    addAssign(a,a)
    

    那么在函数体中ba 都引用同一个数组。例如,假设a[0] 是 1.0。然后在第一次循环中执行a[0] := a[0] + b[0]

    这会将 a[0] 设置为 2.0。但是——它b[0] 设置为2.0。

    但在这种情况下assert a[0] == old(a[0]) + b[0]相当于

    assert 2.0 == 1.0 + 2.0 -- 应该失败。

    顺便说一句——以下确实验证:

    method addAssign(a: array<real>, b: array<real>)
       requires a != null && b != null && a.Length == b.Length;
       modifies a;
       ensures forall k:: 0 <= k < a.Length ==> a[k] == old(a[k]) + old(b[k]);
    {
       var i := 0;
       assert a == old(a);
       while(i < a.Length)
          invariant 0 <= i <= a.Length
          invariant forall k:: i <= k < a.Length ==> a[k] == old(a[k])
          invariant forall k:: 0 <= k < i ==> a[k] == old(a[k]) + old(b[k]);
       {
          assert a[i] == old(a[i]); // dafny verifies this
          a[i] := a[i] + b[i];
          assert a[i] == old(a[i]) + old(b[i]); // and also this!
          i := i + 1;
       }
    }
    

    【讨论】:

    • 我认为情况并非如此。我尝试在代码中将 替换为 ,但我仍然在同一个地方遇到断言违规。不过,感谢您抽出宝贵时间回答。
    • 这很奇怪——但请注意,即使使用整数,您也不能肯定地断言 x + y 是 x 和 y 的总和,因为可能会溢出。如果你放弃数组而只添加几个变量会发生什么?我很好奇对此进行了研究,甚至可以下载 Dafny。如果我发现任何确定的内容,我会重新发布。
    • 感谢您的洞察力,这帮助很大。
    • @MatthewGarlock 感谢您让我了解 Dafny。尽管符号不同,但它的方法强烈地让我想起了大卫·格里斯 (David Gries) 的《编程科学》一书,我在读研究生时曾看过这本书。毫无疑问,这本书不再是最先进的,但仍然值得一读。
    猜你喜欢
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 2019-01-19
    • 2023-02-09
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多