Iterative algorithm and functional code (Dafny) = 迭代算法和功能性代码(Dafny)

huangapple go评论84阅读模式
英文:

Iterative algorithm and functional code (Dafny)

问题

Here's the translation of the code portions you provided:

我有这个简单的算法+函数:
method DifferenceMinMax(a: array<int>) returns (diff: int)
    requires a.Length > 0
    ensures diff == (Max(a[..]) - Min(a[..]))
{
    var minVal := a[0];
    var maxVal := a[0];

    for i := 1 to a.Length
        invariant 1 <= i <= a.Length
        invariant minVal <= maxVal
        invariant forall k :: 0 <= k < i ==> minVal <= a[k] && a[k] <= maxVal
    {
        if a[i] < minVal {
            minVal := a[i];
        } else if a[i] > maxVal {
            maxVal := a[i];
        }
    }

    diff := maxVal - minVal;
}

function Min(a: seq<int>) : int
    requires |a| > 0
{
    if |a| == 1 then a[0]
    else if a[0] <= Min(a[1..]) then a[0] else Min(a[1..])
}

function Max(a: seq<int>) : int
    requires |a| > 0
{
    if |a| == 1 then a[0]
    else if a[0] >= Max(a[1..]) then a[0] else Max(a[1..])
}
这不验证。

我知道我可以像这样重写方法:
method DifferenceMinMax(a: array<int>) returns (diff: int)
    requires a.Length > 0
    ensures diff == (Max(a[..]) - Min(a[..]))
{
    var minVal := Min(a[..]);
    var maxVal := Max(a[..]);

    diff := maxVal - minVal;
}
这个验证。但这会两次遍历数组,而第一个迭代解决方案只会遍历一次。假设我真的想要第一个迭代算法。如何定义 Max 和 Min 以确保返回的 diff 真的是最大值和最小值之间的差异?

我已经尝试过这个,希望在循环不变式中以某种方式使用它,但它不会验证:
function Min(a: seq<int>) : (m: int)
    requires |a| > 0
    ensures forall n :: n in a ==> m in a && m <= n
{
    if |a| == 1 then a[0]
    else if a[0] <= Min(a[1..]) then a[0] else Min(a[1..])
}
我是否需要完全摒弃这些函数?谢谢。

I've provided the requested translations of the code portions. If you have any specific questions or need further assistance with this code, please feel free to ask.

英文:

I have this simple algorithm + functions:

method DifferenceMinMax(a: array<int>) returns (diff: int)
    requires a.Length > 0
    ensures diff == (Max(a[..]) - Min(a[..]))
{
    var minVal := a[0];
    var maxVal := a[0];

    for i := 1 to a.Length
        invariant 1 <= i <= a.Length
        invariant minVal <= maxVal
        invariant forall k :: 0 <= k < i ==> minVal <= a[k] && a[k] <= maxVal
    {
        if a[i] < minVal {
            minVal := a[i];
        } else if a[i] > maxVal {
            maxVal := a[i];
        }
    }

    diff := maxVal - minVal;
}

function Min(a: seq<int>) : int
    requires |a| > 0
{
    if |a| == 1 then a[0]
    else if a[0] <= Min(a[1..]) then a[0] else Min(a[1..])
}

function Max(a: seq<int>) : int
    requires |a| > 0
{
    if |a| == 1 then a[0]
    else if a[0] >= Max(a[1..]) then a[0] else Max(a[1..])
}

This doesn't verify.

I know I can rewrite the method like this:

method DifferenceMinMax(a: array<int>) returns (diff: int)
    requires a.Length > 0
    ensures diff == (Max(a[..]) - Min(a[..]))
{
    var minVal := Min(a[..]);
    var maxVal := Max(a[..]);

    diff := maxVal - minVal;
}

This verifies. But this traverses the array twice, while the first iterative solution does it only once. Assume I really want the first iterative algorithm. How do I define Max and Min so that the returned diff is really the difference between the max and the min?

I already tried this, which I was hoping to use in the loop invariant somehow, but it doesn't verify:

function Min(a: seq<int>) : (m: int)
    requires |a| > 0
    ensures forall n :: n in a ==> m in a && m <= n
{
    if |a| == 1 then a[0]
    else if a[0] <= Min(a[1..]) then a[0] else Min(a[1..])
}

Do I need to get rid of the functions entirely?
Thanks.

答案1

得分: 2

以下是翻译好的部分:

建议

  • 在你的循环中,你有效地计算了min(min(min(a[0], a[1]), a[2]), a[3])。看着这个,最佳实践是确保你的最小值的规定与这个计算相匹配。你当前的规定计算了min(a[0], min(a[1], min(a[2]....))),因此你将会很难证明这两者是相同的,或者需要一个引理来证明它们是相同的,或者后置条件(我还没有尝试过)
  • 如果一个for循环无法验证(即某些不变量),最好将其临时转换为while循环,并明确指定循环变量的赋值
  • 将不变量编写为应在for循环结束时成立的断言
  • 应用最弱前置条件演算法来查看开始时应该成立的内容
  • 在你的min和max函数中,你两次计算相同的函数,你可以将它分配给一个变量
  • 你需要有一个关于MinVal(a)和MaxVal(a)的不变量,它在最后产生了一些内容。

给出了上述建议,这是解决方案。

解决方案

method DifferenceMinMax(a: array<int>) returns (diff: int)
    requires a.Length > 0
    ensures diff == (Max(a[..]) - Min(a[..]))
{
    var minVal := a[0];
    var maxVal := a[0];
    for i := 1 to a.Length
        invariant 1 <= i <= a.Length
        invariant minVal <= maxVal
        invariant forall k :: 0 <= k < i ==> minVal <= a[k] && a[k] <= maxVal
        invariant minVal == Min(a[..i])
        invariant maxVal == Max(a[..i])
    {
        if a[i] < minVal {
            minVal := a[i];
        } else if a[i] > maxVal {
            maxVal := a[i];
        }
        assert a[..i+1][..i] == a[..i];
    }
    assert a[..a.Length] == a[..];
    diff := maxVal - minVal;
}

function Min(a: seq<int>) : (m: int)
    requires |a| > 0
{
    if |a| == 1 then a[0]
    else
      var minPrefix := Min(a[..|a|-1]);
      if a[|a|-1] <= minPrefix then a[|a|-1] else minPrefix
}

function Max(a: seq<int>) : (m: int)
    requires |a| > 0
{
    if |a| == 1 then a[0]
    else
      var maxPrefix := Max(a[..|a|-1]);
      if a[|a|-1] >= maxPrefix then a[|a|-1] else maxPrefix
}

请注意,由于原始文本中包含了HTML编码(例如&lt;&gt;),这些编码在翻译中被保留了下来。如果需要,您可以将其还原为正常的HTML符号。

英文:

Great question.

Here is some advice on how to solve such an issue, and below is the solution

Advice

  • In your loop, you effectively compute min(min(min(a[0], a[1]), a[2]), a[3]). Looking at that, it is best practice to ensure your specification of the minimum matches this computation. Your current spec computes min(a[0], min(a[1], min(a[2]....))) so you'll have a hard time (meaning, needing a lemma) to prove that the two are the same, or postconditions (I haven't tried that)
  • If a for loop is failing to verify (i.e. some invariants), it's better to convert it temporarily to a while loop and explicit the assignments of the loop variable
  • Write the invariant as an assertion that should hold at the end of the for loop
  • Apply the weakest precondition calculus to see what should hold at the beginning
  • In your min and max function, you compute the same function twice, you can assign it to a variable
  • You need to have an invariant that produces something about MinVal(a) and MaxVal(a) at the end.

That advice given, here is the solution.

*** Solution ***

method DifferenceMinMax(a: array&lt;int&gt;) returns (diff: int)
    requires a.Length &gt; 0
    ensures diff == (Max(a[..]) - Min(a[..]))
{
    var minVal := a[0];
    var maxVal := a[0];
    for i := 1 to a.Length
        invariant 1 &lt;= i &lt;= a.Length
        invariant minVal &lt;= maxVal
        invariant forall k :: 0 &lt;= k &lt; i ==&gt; minVal &lt;= a[k] &amp;&amp; a[k] &lt;= maxVal
        invariant minVal == Min(a[..i])
        invariant maxVal == Max(a[..i])
    {
        if a[i] &lt; minVal {
            minVal := a[i];
        } else if a[i] &gt; maxVal {
            maxVal := a[i];
        }
        assert a[..i+1][..i] == a[..i];
    }
    assert a[..a.Length] == a[..];
    diff := maxVal - minVal;
}

function Min(a: seq&lt;int&gt;) : (m: int)
    requires |a| &gt; 0
{
    if |a| == 1 then a[0]
    else
      var minPrefix := Min(a[..|a|-1]);
      if a[|a|-1] &lt;= minPrefix then a[|a|-1] else minPrefix
}

function Max(a: seq&lt;int&gt;) : (m: int)
    requires |a| &gt; 0
{
    if |a| == 1 then a[0]
    else
      var maxPrefix := Max(a[..|a|-1]);
      if a[|a|-1] &gt;= maxPrefix then a[|a|-1] else maxPrefix
}

huangapple
  • 本文由 发表于 2023年6月15日 00:08:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76475562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定