【问题标题】:Dafny - Substring implementationDafny - 子字符串实现
【发布时间】:2017-05-14 19:50:28
【问题描述】:

我正在尝试编写一个经过验证的 substring 方法的简单实现。 我的方法接受 2 个字符串并检查 str2 是否在 str1 中。 我首先试图弄清楚为什么我的不变量不成立 - Dafny 标记该不变量可能在输入时不成立,而我的前置/后置条件失败。 我对不变量的想法是有 3 种主要情况: 1.循环找不到索引i处的子字符串,还有更多索引需要探索 2. 循环未能找到索引 i 处的子字符串 - 没有要探索的索引 3. 循环在索引 i 处找到子字符串

代码:

method Main() {
    var str1,str2 := "Dafny","fn";
    var found,offset := FindSubstring(str1,str2);
    assert found by
    {
        calc {
            str2 <= str1[2..];
        ==>
            IsSubsequenceAtOffset(str1,str2,2);
        ==>
            IsSubsequence(str1,str2);
        ==
            found;
        }
    }
    assert offset == 2 by
    {
        assert found && str2 <= str1[2..];
        assert offset != 0 by { assert 'D' == str1[0] != str2[0] == 'f'; }
        assert offset != 1 by { assert 'a' == str1[1] != str2[0] == 'f'; }
        assert offset != 3 by { assert 'n' == str1[3] != str2[0] == 'f'; }
        assert !(offset >= 4) by { assert 4 + |str2| > |str1|; }
    }
    print "The sequence ";
    print str2;
    print " is a subsequence of ";
    print str1;
    print " starting at element ";
    print offset;
}

predicate IsSubsequence<T>(q1: seq<T>, q2: seq<T>)
{
    exists offset: nat :: offset + |q2| <= |q1| && IsSubsequenceAtOffset(q1,q2,offset)
}

predicate IsSubsequenceAtOffset<T>(q1: seq<T>, q2: seq<T>, offset: nat)
{ 
    offset + |q2| <= |q1| && q2 <= q1[offset..]
}

predicate Inv<T>(str1: seq<T>, str2: seq<T>, offset: nat, found: bool)
{
    |str1| > 0 && |str2| > 0 && |str1| >= |str2| && offset <= |str1|-|str2| &&
    (!found && offset < |str1|-|str2| ==> !(str2 <= str1[offset..])) &&
  (!found && offset == |str1| -|str2| ==> !IsSubsequence(str1, str2)) && 
    (found ==> IsSubsequenceAtOffset(str1, str2, offset))
}

method FindSubstring(str1: string, str2: string) returns (found: bool, offset: nat)

    requires |str2| <= |str1|
    ensures found <==> IsSubsequence(str1,str2)
    ensures found ==> IsSubsequenceAtOffset(str1,str2,offset)  
  {
     found, offset := str2 <= str1[0..], 0;
     assert Inv(str1,str2,offset,found);

     while !found && offset <= (|str1| - |str2|) 
        invariant Inv(str1,str2,offset,found)
     {
       if str2 <= str1[(offset + 1)..] {
         found, offset := true, offset + 1;
       } else {
         offset := offset + 1;
       }
     } 
     Lemma(str1,str2,found,offset);
  }

  lemma Lemma(str1: string, str2: string, found: bool, offset: nat)
    requires !(!found && offset <= (|str1| - |str2|))
    requires Inv(str1,str2,offset,found)
    ensures found <==> IsSubsequence(str1,str2)
    ensures found ==> IsSubsequenceAtOffset(str1,str2,offset) 
    {}

链接:http://rise4fun.com/Dafny/QaAbU 任何帮助,将不胜感激。

【问题讨论】:

    标签: substring verification proof dafny


    【解决方案1】:

    http://rise4fun.com/Dafny/q9BG

    1) inv 中的 |str1| &gt; 0 &amp;&amp; |str2| &gt; 0 失败,因为此条件未添加到函数 FindSubstring 的要求中

    2) 由于FindSubstring 中的while 循环体检查offset+1 的子字符串,因此while 循环只需为offset &lt; (|str1| - |str2|) 运行,因为如果offset == (|str1| - |str2|) 则不存在任何满足str2 &lt;= str1[offset..] 的偏移量

    3) 在inv 中添加了量词,确保对于0 &lt;= k &lt;= offset 的所有偏移量0 &lt;= k &lt;= offset,不存在任何k 其中str2 &lt;= str1[offset..]

    一个调试失败不变量的小建议可能会有所帮助:将 inv 调用替换为 inv 的实际主体,dafny 将查明不变量中的失败条件。

    希望这是有道理的。

    【讨论】:

    • 感谢您的详细解答!
    猜你喜欢
    • 2012-10-17
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多