【发布时间】:2018-03-27 04:52:21
【问题描述】:
我的任务是初始化一个 8x8 矩阵并确保矩阵内的所有元素都设置为零。我还需要使用 while 循环和循环不变量来实现。我的实现如下所示:
method initMatrix(a: array2<int>)
modifies a
// require an 8 x 8 matrix
requires a.Length0 == 8 && a.Length1 == 8
// Ensures that all rows in the matrix are zeroes
ensures forall row, col :: 0 <= row < a.Length0 && 0 <= col < a.Length1 ==> a[row, col] == 0
{
var row : nat := 0;
while(row < a.Length0)
invariant 0 <= row <= a.Length0
invariant forall i,j :: 0 <= i < row && 0 <= j < a.Length1 ==> a[i,j] == 0
{
var col : nat := 0;
while(col < a.Length1)
invariant 0 <= row <= a.Length0
invariant 0 <= col <= a.Length1
invariant forall i,j :: i == row && 0 <= j < col ==> a[i,j] == 0
{
a[row, col] := 0;
col := col + 1;
}
row := row + 1;
}
}
从逻辑上讲,我认为我所有的量词都是正确的。但是,Dafny 认为我的循环在外部 while 循环中是不变的
invariant forall i,j :: 0 <= i < row && 0 <= j < a.Length1 ==> a[i,j] == 0
没有被循环维护。
我首先怀疑我的实现中存在问题。所以我首先在没有任何前置条件和后置条件的情况下运行该方法并打印数组中的所有元素;输出是一个充满零的矩阵。
为了更加确定它正在替换所有元素,而不仅仅是使用矩阵实例化时的零,我将矩阵中的所有元素初始化为 1 并打印出其中的所有值。结果是一样的——矩阵中的所有元素都是 1。
从这个实验中,我可以得出结论,问题不存在于我的实现中,而是我定义规范的方式。
我手动浏览了我的算法,发现它在逻辑上应该可以工作,但是,我认为我对量词如何在 Dafny 中的循环不变量中工作的理解可能存在偏差。
当条件0 <= i < row && 0 <= j < a.Length1 为假时,究竟发生了什么?在第一次迭代中,变量row 等于0,不满足条件0 <= i < row。它是遍历第一行并检查该行中的所有元素是否为零还是跳过它?
现在,当它在初始迭代中到达语句 row := row + 1; 时会发生什么?循环不变量invariant forall i,j :: 0 <= i < row && 0 <= j < a.Length1 ==> a[i,j] == 0 在进入时使用row 的值(为零)还是使用row (1) 的递增值?
【问题讨论】: