为什么Dafny验证程序反例错误?

时间:2020-04-19 15:47:58

标签: dafny

我正在尝试练习,如以下视频中稍后所述:https://www.youtube.com/watch?v=-_tx3lk7yn4

该方法应实现BinarySearch,当未找到键时,该方法应返回索引,如果将其插入到搜索数组中,键将以该键结束。我相信该练习的正确附加规范如下:

ensures 0 <= r <= a.Length
ensures forall i :: 0 <= i < r ==> a[i] < key
ensures forall i :: r < i < a.Length ==> a[i] >= key

我的实现:

method BinarySearch(a: array<int>, key: int) returns (r: int) 
    requires forall i,j :: 0 <= i < j < a.Length ==> a[i] <= a[j] // a is a sorted array
    // old specification
    //ensures 0 <= r ==> r < a.Length && a[r] == key // when found a[r] is key
    //ensures r < 0 ==> forall i :: 0 <= i < a.Length ==> a[i] != key // when no key found return negative value

    // restrictions for simpler debugging
    requires a.Length == 2
    requires forall i :: 0 <= i < a.Length ==> 0 <= a[i] < 5

    // new specification
    ensures 0 <= r <= a.Length // "it will always return some indication between 0 and the length of the array inclusive"
    ensures forall i :: 0 <= i < r ==> a[i] < key // "all values to the left of the value R that you're returning are strictly smaller than the key"
    ensures forall i :: r < i < a.Length ==> a[i] >= key // "from all values to the right of R is either the key or larger"
{
    // simple/common cases first
    // if array is empty
    if a.Length == 0
    {
        return 0;
    }
    // if key larger than largest
    else if key > a[a.Length - 1]
    {
        return a.Length;
    }
    // if key equal or smaller than smallest
    else if key <= a[0]
    {
        return 0;
    }
    // key is in array range
    var lo, hi := 0, a.Length;
    while lo < hi
        decreases hi - lo
        invariant 0 <= lo <= hi <= a.Length
        invariant forall i :: 0 <= i < lo ==> a[i] != key
        invariant forall i :: hi <= i < a.Length ==> a[i] != key
    {
        var mid := (lo + hi) / 2;
        if key < a[mid]
        {
            hi := mid;
        }
        else if a[mid] < key
        {
            lo := mid + 1;
        }
        else
        {
            // key found, decrease while preceding value is equal
            while mid != 0 && a[mid-1] == a[mid]
                decreases mid
                invariant 0 <= mid < a.Length
                invariant lo < hi
                invariant forall i :: 0 <= i < lo ==> a[i] != key
                invariant forall i :: hi <= i < a.Length ==> a[i] != key
            {
                mid := mid - 1;
            }
            return mid;
        }
    }
    return lo;
}

我的问题是验证者说规范不成立,然后给了我一个反例,而这种反例最初不会发生:

bad counter example

我怀疑while循环本身缺少规范,但是我不知道要填补什么空白。

使用最新的Visual Code和Dafny插件。

0 个答案:

没有答案