Im trying to write a simple verified implementation of the substring method. My method accepts 2 strings and checks whether str2 is in str1. Im trying to figure out firstly why my invairant doesnt hold - Dafny marks that the invariant might not hold on entry and while my pre/post conditions fail. My thoughts on the invairant are that there 3 main scenarios: 1. The loop failed to find the substring at index i and there are more indexes to explore 2. The loop failed to find the substring at index i - no more indexes to explore 3. The loop found substring at index i
Code:
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) 
    {}
Link: http://rise4fun.com/Dafny/QaAbU Any help would be appreciated.
                        
http://rise4fun.com/Dafny/q9BG
1)
|str1| > 0 && |str2| > 0ininvwas failing because this condition is not added in the requirement of the functionFindSubstring2) Since while loop body in
FindSubstringchecks substring foroffset+1, the while loop only has to run foroffset < (|str1| - |str2|)because ifoffset == (|str1| - |str2|)then there doesn't exist any offset which would satisfystr2 <= str1[offset..]3) Added quantifier in
invwhich ensures that for all the offsetskwhere0 <= k <= offset, there doesn't exist anykwhichstr2 <= str1[offset..]A small advice to debug the failing invariant that might help: replace the
invcall with the actual body ofinvand dafny will pinpoint the failing condition in the invariant.Hope this makes sense.