英文:
Is this invariant correct?
问题
我试图迭代计算一个自然数序列的最大元素,但在循环不变式中出现错误。
有人能告诉我正确的代码循环不变式是什么吗?
这是代码:
```dylan
function maximo(s: seq<nat>): nat
  decreases |s|
{
  if s == [] then 0 else if s[0] > maximo(s[1..]) then s[0] else maximo(s[1..])
}
method maximo_it(s: seq<nat>) returns (max: nat) 
  ensures max == maximo(s);
{
  max := 0;
  var i := 0;
  while i < |s|
  decreases |s| - i
  invariant 0 <= i <= |s|
  invariant max == maximo(s[..i])
  { 
    if (max < s[i]) { max := s[i]; }
    i := i + 1;
  }    
}
我尝试进行了更改,但我认为我的解决方案是正确的。我看到了一种可能的解决方案,它从末尾到开头遍历序列,我的解决方案只是从零位置开始相同。
以下是解决方案的代码:
method maximo_it(s: seq<nat>) returns (max: nat) 
  ensures max == maximo(s);
{
  max := 0;
  var i := |s|;
  while i > 0
    decreases i
    invariant 0 <= i <= |s|
    invariant max == maximo(s[i..]) 
  {  
    i := i - 1; 
    if s[i] > max
    { 
      max := s[i];
    }
  }
}
<details>
<summary>英文:</summary>
I'm trying to calculate the maximum element of a sequence of naturals in dafny iteratively and I get an error in the loop's invariant.
Could someone tell me which would be the correct invariant for the code?
This is the code:
function maximo (s:seq<nat>):nat
decreases |s|
{
if s == [] then 0 else if s[0] > maximo(s[1..]) then s[0] else maximo(s[1..])
}
method maximo_it (s:seq<nat>) returns (max: nat)
ensures max == maximo(s);
{
max :=0;
var i:=0;
while i < |s|
decreases |s|-i
invariant 0<=i<=|s|
invariant max == maximo(s[..i])
{
if (max < s[i]) { max:=s[i];}
i:=i+1;
} 
}
I tried to change it but I do think mi solution is correct. I´ve seen a possible solution that goes across the sequence from the end to the beginning, my solution is just the same but starting from the zero position.
Here is the solution's code: 
method maximo_it (s:seq<nat>) returns (max: nat)
ensures max == maximo(s);
{
max := 0;
var i := |s|;
while i > 0
decreases i
invariant 0 <= i <= |s|
invariant max == maximo(s[i..])
{
i := i-1;
if s[i] > max
{
max := s[i];
}
}
}
</details>
# 答案1
**得分**: 2
```python
如果您想按与函数不同的顺序编写迭代代码,那么您需要一个引理来证明这两种顺序是一致的。
```python
函数 maximo(s: seq<nat>): nat
  减少 |s|
{
  如果 s == [] 则
    返回 0
  否则 如果 s[0] > maximo(s[1..]) 则
    返回 s[0]
  否则
    返回 maximo(s[1..])
}
引理 maximo_unroll(s: seq<nat>)
  需要 s != []
  确保 maximo(s) == 如果 s[|s|-1] > maximo(s[..|s|-1]) 则 s[|s|-1] 否则 maximo(s[..|s|-1])
{
  如果 s != [] 则 {
    变量 butlast := s[..|s|-1];
    变量 rest := s[1..];
    如果 butlast != [] 则 {
      maximo_unroll(rest);
      断言 rest[..|rest|-1] == s[1..|s|-1];
    }
  }
}
方法 maximo_it (s: seq<nat>) 返回 (max: nat) 
  确保 max == maximo(s);
{
  max := 0;
  变量 i := 0;
  当 i < |s|
    减少 |s| - i
    不变量 0 <= i <= |s|
    不变量 max == maximo(s[..i])
  { 
    maximo_unroll(s[..i+1]);
    断言 s[..i+1][..|s[..i+1]|-1] == s[..i];
    如果 (max < s[i]) 则 {
      max := s[i];
    } 
    i := i+1;
  }
  断言 s == s[..|s|];
} 
英文:
If you want to write the iterative code in a different order than the function, then you need a lemma to show that the two orders agree.
function maximo(s: seq<nat>): nat
  decreases |s|
{
  if s == [] then
    0
  else if s[0] > maximo(s[1..]) then
    s[0]
  else
    maximo(s[1..])
}
lemma maximo_unroll(s: seq<nat>)
  requires s != []
  ensures maximo(s) == if s[|s|-1] > maximo(s[..|s|-1]) then s[|s|-1] else maximo(s[..|s|-1])
{
  if s != [] {
    var butlast := s[..|s|-1];
    var rest := s[1..];
    if butlast != [] {
      maximo_unroll(rest);
      assert rest[..|rest|-1] == s[1..|s|-1];
    }
  }
}
method maximo_it (s: seq<nat>) returns (max: nat) 
  ensures max == maximo(s);
{
  max := 0;
  var i := 0;
  while i < |s|
    decreases |s| - i
    invariant 0 <= i <= |s|
    invariant max == maximo(s[..i])
  { 
    maximo_unroll(s[..i+1]);
    assert s[..i+1][..|s[..i+1]|-1] == s[..i];
    if (max < s[i]) {
      max := s[i];
    } 
    i := i+1;
  }
  assert s == s[..|s|];
} 
答案2
得分: 2
与其使用词形,这种情况下的另一个选择是调整 `maximo()` 函数本身。这是我想出的最干净的解决方案:
```lang-dafny
function maximo(s:seq<nat>, n: nat):(r:nat)
requires n <= |s|
decreases n
{
    if n == 0 then 0
    else
        var last := s[n-1];
        var max := maximo(s,n-1);
        if last >= max then last
        else max
}
method maximo_it(s:seq<nat>) returns (max: nat)
ensures max == maximo(s,|s|);
{
  max :=0;
  var i:=0;
  while i < |s|
  decreases |s|-i
  invariant i <= |s|
  invariant max == maximo(s,i)
  {
    if max <= s[i] { max := s[i]; }
    i:=i+1;
  }
}
在这里,我重新调整了 maximo() 函数的迭代顺序。
<details>
<summary>英文:</summary>
Instead of using a lemma, another option in this case is to tweak the `maximo()` function itself.  This is the cleanest solution I came up with:
```lang-dafny
function maximo(s:seq<nat>, n: nat):(r:nat)
requires n <= |s|
decreases n
{
    if n == 0 then 0
    else
        var last := s[n-1];
        var max := maximo(s,n-1);
        if last >= max then last
        else max
}
method maximo_it(s:seq<nat>) returns (max: nat)
ensures max == maximo(s,|s|);
{
  max :=0;
  var i:=0;
  while i < |s|
  decreases |s|-i
  invariant i <= |s|
  invariant max == maximo(s,i)
  {
    if max <= s[i] { max := s[i]; }
    i:=i+1;
  }
}
Here, I've reworked the order of iteration for the maximo() function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论