Странный(?) результат от БВД для программы Дафни

Когда я проверяю следующий фрагмент программы, в котором есть одна ошибка, метод Дафни, воспроизведенный ниже

Я получаю следующий результат от BVD, который я не понимаю.

Результат BVD

Меня озадачивает то, что второй инвариант, кажется, был проигнорирован при создании контрпримера. Если двумя инвариантами являются I0 и I1, а охраной является G, то, конечно, условие проверки равно I0 && I1 && !G ==> qy > x, и контрпример должен удовлетворять отрицанию этого. Что я неправильно понял?


Код воспроизводится ниже для удобства всех желающих.

function TwoToThe( i : int ) : int
decreases i 
requires i >= 0
{
    if i==0 then 1 else 2*TwoToThe( i-1 )
}

method interestingBVD(x : int, y : int)
    requires y > 0 
    requires x >= 0
{
    var q := 1 ;
    var qy := y ; // Tracks q*y
    ghost var i := 0 ;
    // Double q until q*y exceeds x
    while( qy < x )  // Off by one error.
        invariant qy == q*y
        invariant q == TwoToThe(i)
        decreases 2*x-qy ;
    {
        q, qy, i := 2*q, 2*qy, i + 1 ;
    }
    // In the BVD we get actual numbers!!
    assert q*y == qy > x && q == TwoToThe(i) ; 
}

person Theodore Norvell    schedule 04.10.2016    source источник


Ответы (1)


Отладчик проверки указывает, что qy может равняться x, и, в частности, они оба могут быть 2988. Действительно, !G в вашем комментарии - это x <= qy, а не qy > x.

Пока мы находимся в этом примере, есть еще одна примечательная проблема:

Из второго инварианта верификатор знает q == TwoToThe(i). Это ожидаемо и может быть проверено с помощью assert, как вы это сделали. Другими словами, верификатор знает, что q равно результату применения TwoToThe к i. Отладчик проверки показывает, что q и i имеют значения 2988 и 5330. Это может показаться странным, поскольку мы знаем, что TwoToThe(5330) намного больше, чем 2988. Итак, что здесь происходит?

Чтобы вычислить значение TwoToThe(5330), нужно развернуть определение TwoToThe 5330 раз. Верификатор не пытается разворачивать определение столько раз, поэтому 2988 по-прежнему представляется правдоподобным значением TwoToThe(5330), насколько он может судить. Это может быть полезной информацией при отладке неудачной проверки.

В заключение, отладчик верификации дает представление о мире согласно верификатору, то есть понимание того, что «думает» верификатор. Здесь мы видим, что он «думает», что TwoToThe(5330) возвращает 2988. Затем мы, в свою очередь, узнаем, что либо определение TwoToThe не соответствует его названию, либо верификатор не полностью расширяет тысячи рекурсивных вызовов TwoToThe, необходимых для определения значения.

Рустан

person Rustan Leino    schedule 21.11.2018