如何构造和证明循环不变性,从而证明其部分正确性

时间:2018-12-11 22:19:48

标签: algorithm correctness loop-invariant

我需要根据给定的规范构造并证明循环不变性:

{n > 0} P {q = | {j: a[j]=x and 0 <= j < n} |}

其中 | A | 是集合A的元素数量。这意味着 q 等于数组 a 等于 x

代码 P 指定为:

{
int i = 0, q = 0;
while (i != n){
    if (a[i] == x)
        q = q + 1;
    i = i + 1;
}

我知道循环不变性必须为真:

  • 循环开始之前
  • 在每次循环之前
  • 循环终止后

但是我不知道如何找到正确的循环不变式,这将使我随后显示P的部分正确性。我已经尝试查看循环的每个迭代以及随机 n x a [0 ... n-1] 以查看在循环运行时组合的哪些值是恒定的,但没有帮助。

1 个答案:

答案 0 :(得分:1)

仔细查看您的代码。刚开始时,q为0,并且仅在找到== x的新元素时才会增长。所以

q = | {j: a[j]=x and 0 <= j < i} |

是您不变式的一部分。请注意,在您的规范中,您使用的是< n而不是< i。还请注意,在循环终止时,i == n。因此,一开始它也是有效的。两者之间的任何时候也都是如此:到目前为止,很好。还有其他东西吗?是的,我们也应该声明

0 <= i <= n -因为它描述了i的值的范围(否则i可以自由地在数组之外冒险)。

这就是全部吗?是的-没有其他循环状态可以描述。因此,您的完整不变式看起来像

q = | {j: a[j]=x and 0 <= j < i} | and 0 <= i <= n

解决这些练习时,您可以尝试以下两个步骤:

  • 尝试以纯文本形式描述算法中发生的情况:“我将i从0扫描到n-1,在n处停止,每时每刻,我将q保持在{我在数组中找到的x中的“”。必须提及循环中涉及的所有变量!。
  • 将纯文本翻译成数学,同时还要确保您的后置条件反映在不变式上,通常用循环计数器(在这种情况下为n)来代替i li>

作为思想实验,请尝试使用等效循环(但从末尾开始重复)来编写不变量:

{
int i = n-1, q = 0;
while (i >= 0){
    if (a[i] == x)
        q = q + 1;
    i = i - 1;
}

将鼠标悬停以寻找答案(但请先找出答案)。

  

q = | {j: a[j]=x and i < j < n} | and -1 <= i < n  注意不同的限制,反映出i的扫描范围不同;  但整体结构相同