gpt4 book ai didi

sorting - Dafny 中的选择排序

转载 作者:行者123 更新时间:2023-12-02 14:35:20 27 4
gpt4 key购买 nike

我正在尝试在 Dafny 中实现选择排序。

我的 sortedFindMin 函数确实有效,但 selectionsort 本身包含 Dafny 无法证明的断言,即使它们是正确的。

这是我的程序:

predicate sorted(a:array<int>,i:int)
requires a != null;
requires 0 <= i <= a.Length;
reads a;
{
forall k :: 0 < k < i ==> a[k-1] < a[k]
}
method FindMin(a:array<int>,i:int) returns(m:int)
requires a != null;
requires 0 <= i < a.Length;
ensures i <= m < a.Length;
ensures forall k :: i <= k < a.Length ==> a[k] >= a[m];
{
var j := i;
m := i;
while(j < a.Length)
decreases a.Length - j;
invariant i <= j <= a.Length;
invariant i <= m < a.Length;
invariant forall k :: i <= k < j ==> a[k] >= a[m];
{
if(a[j] < a[m]){m := j;}
j := j + 1;
}
}
method selectionsort(a:array<int>) returns(s:array<int>)
requires a != null;
modifies a;
ensures s != null;
ensures sorted(s,s.Length);
{
var c,m := 0,0;
var t;
s := a;
assert s != null;
assert s.Length == a.Length;
while(c<s.Length)
decreases s.Length-c;
invariant 0 <= c <= s.Length;
invariant c-1 <= m <= s.Length;
invariant sorted(s,c);
{
m := FindMin(s,c);
assert forall k :: c <= k < s.Length ==> s[k] >= s[m];
assert forall k :: 0 <= k < c ==> s[k] <= s[m];
assert s[c] >= s[m];
t := s[c];
s[m] := t;
s[c] := s[m];
assert s[m] >= s[c];
assert forall k :: c <= k < s.Length ==> s[k] >= s[c];
c := c+1;
assert c+1 < s.Length ==> s[c-1] <= s[c];
}
}

为什么这是错误的? “后置条件可能不成立”是什么意思? Dafny 能举个反例吗?

最佳答案

您似乎了解循环不变量背后的基本思想,这是使用 Dafny 验证程序所必需的。

你的程序不正确。发现这一点的一种方法是使用 Visual Studio 中 Dafny IDE 内的验证调试器。单击报告的最后一个错误( c 增量之前的行上的断言),您将看到数组的上半部分包含一个比 s[c] 都小的元素。和s[m] 。然后选择 3 语句交换操作周围的程序点,您会发现您的交换实际上并未交换。

要修复交换,请交换 3 语句交换的第二个和第三个语句。更好的是,利用 Dafny 的多重赋值语句,这使得代码更容易正确:

s[c], s[m] := s[m], s[c];

还有另外两个问题。一是循环内的第二个断言未验证:

assert forall k :: 0 <= k < c ==> s[k] <= s[m];

同时s[m]是数组上部的最小元素,循环不变式需要证明数组下部的元素不大于上部的元素——这是选择排序算法的基本属性。下面的循环不变量就可以解决这个问题:

invariant forall k, l :: 0 <= k < c <= l < a.Length ==> s[k] <= s[l];

最后是关于属性(property)的投诉sorted(s,c)不被循环维护是因为您定义了 sorted 严格递增,除非数组的元素最初都是不同的,否则交换永远不会实现。因此,达夫尼指出了您必须对排序例程做出的设计决策。您可以决定您的selectionsort方法将仅适用于没有重复元素的数组,您可以通过添加来实现

forall k, l :: 0 <= k < l < a.Length ==> a[k] != a[l];

作为 selectionsort 的前提条件(并且循环不变) 。或者,更传统的是,您可以修复 sorted 的定义。替换a[k] > a[m]a[k] >= a[m] .

要稍微清理一下代码,您现在可以删除所有断言语句和 t 的声明。自 m仅在循环内部使用,您可以移动 m 的声明到调用 FindMin 的语句,这也表明循环不变式 c-1 <= m <= s.Length不需要。两个decreases子句可以省略;对于您的程序,Dafny 将自动提供这些。最后,您的selectionsort方法就地修改给定的数组,因此没有真正的理由返回引用 a在输出参数 s ;相反,您可以省略输出参数并替换 s通过a无处不在。

关于sorting - Dafny 中的选择排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24591668/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com