簡體   English   中英

Dafny:驗證最簡單的數組求和是行不通的。 有人可以向我解釋為什么嗎?

[英]Dafny: Verification of the most simple array summation does not work. Can somebody explain me why?

當我有三個 arrays 和 c[j]:= b[h] + a[i] 時。 驗證 c[j] == b[h] + a[i] 不起作用。 有人可以解釋一下為什么嗎? 確保所有索引都在范圍內並且所有三個 arrays 都是 int arrays。這是我的代碼:

method addThreeArrays(a: array<int>, b: array<int>, c: array<int>, h: int, i: int, j: int)
  modifies c
  requires 0 <= h < a.Length
  requires 0 <= i < b.Length
  requires 0 <= j < c.Length
  
  ensures c[j] == a[h] + b[i]
  {
    c[j] := a[h] + b[i];
  }

我希望“確保”這一行是真實的。 但是 Dafny 給出了錯誤。 “后置條件”可能不成立。 我只想了解我的錯誤在哪里。 謝謝你們: :)

由於 Dafny arrays 分配在堆上,因此允許它們別名。 因此,可以使用例如c和指向 memory 中相同數組a指針來調用您的方法。此外, j == h也是可能的。 在那種情況下,后置條件可能不成立,因為寫入c[j]也寫入了a[h] (因為ca指向同一個數組和j == h )。

您可以通過添加前提條件a != cb != c來解決此問題。

我將您的示例寫入 Dafny 項目以及我們將如何使用代碼操作解決它: https://github.com/dafny-lang/dafny/issues/3102

我在這里重現了詳細的解決方案來計算最弱的前提條件


使斷言明確將導致

  {
    c[j] := a[h] + b[i];
    assert c[j] == a[h] + b[i];
  }

現在,我們不能只是“向上移動斷言”,因為否則我們將不得不在分配后推理堆的 state,而 old@ 不能引用之后定義的 label。 因此,下一步將是引入 label 並在賦值下方進行最弱前提演算

  {
    label before: // Added
    c[j] := a[h] + b[i];
    assert old@before(a[h] + b[i]) == a[h] + b[i]; // Added, now failing
    assert c[j] == a[h] + b[i];
  }

這樣做的好處是它可以幫助用戶以自然的方式發現“舊”語法。 因為最弱的前提條件現在看到兩個更可能沖突的引用,它可能會建議使用以下代碼操作在分配后刪除對堆的引用:

  {
    label before: // Added
    c[j] := a[h] + b[i];
    assert old@before(a[h] + b[i]) == (if a == c && j == h then old@before(a[h] + b[i]) else a[h]) + (if b == c && j == i then old@before(a[h] + b[i]) else b[i]); 
    assert c[j] == a[h] + b[i];
  }

現在,因為這個表達式在賦值c[j}之后根本不引用堆,所以最弱的前提演算能夠將這個斷言移到前面並刪除old@表達式。

  {
    assert a[h] + b[i] == (if a == c && j == h then a[h] + b[i] else a[h]) + (if b == c && j == i then a[h] + b[i] else b[i]); // Just added, now failing.
    label before:
    c[j] := a[h] + b[i];
    assert old@before(a[h] + b[i]) == (if a == c && j == h then old@before(a[h] + b[i]) else a[h]) + (if b == c && j == i then old@before(a[h] + b[i]) else b[i]); 
    assert old@before(a[h] + b[i]) == a[h] + b[i];
    assert c[j] == a[h] + b[i];
  }

並最終將其移至該方法的要求。 然后用戶可以改進這個最弱的先決條件,以便他們只保留a != c && b != c如果他們願意的話。 或不。

我也在添加另一個答案,因為我認為它是獨立的。 默認情況下,后置條件指的是方法末尾的堆。 您可以通過在堆的開頭引用ab的取消引用來使后置條件成立,方法是像這樣插入old(...)

method addThreeArrays(a: array<int>, b: array<int>, c: array<int>, h: int, i: int, j: int)
  modifies c
  requires 0 <= h < a.Length
  requires 0 <= i < b.Length
  requires 0 <= j < c.Length
  
  ensures c[j] == old(a[h] + b[i])
  {
    c[j] := a[h] + b[i];
  }

這就像一個魅力,正是你的方法正在做的。 感謝 Rustan Leino 為我指出了這個解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM