dafny нарушение утверждения при использовании результата метода

Я написал программу ниже, чтобы проверить, является ли массив «чистым» от любого конкретного элемента или нет. У меня возникли проблемы с утверждением результата метода. Я продолжаю получать нарушение утверждения при попытке подтвердить результат метода.

method Main (){
 
  
  var a:= new int[3];
  
  a[0], a[1], a[2] := 1,2,3;
  var v := isClean (a, 1);
  assert v == false;

}



method isClean (a : array <int>, key : int) returns (clean : bool)
  
  requires a.Length > 0


{
  
  var i := 0;
  
  while (i < a.Length)
  
  invariant 0 <= i <= a.Length
  invariant forall k :: 0 <= k < i ==> a[k] != key
  
  {
    
    if (a[i] == key) {
      
      clean := false;
      return;
    }
    
    i := i + 1;
    
  }
  
  clean := true;
  
}

Dafny 2.3.0.10506
stdin.dfy(8,11): Error: assertion violation

Dafny program verifier finished with 2 verified, 1 error


person Arthur    schedule 09.09.2020    source источник


Ответы (1)


Вам нужно указать пункт ensures на isClean. Когда Dafny проверяет программу, она просматривает только один method за раз. Поэтому, когда Дафни проверяет Main, он вообще не смотрит на определение isClean. Вместо этого он смотрит только на предложения requires и ensures.

У вас уже есть трудная часть доказательства в инварианте цикла. По сути, вам просто нужно изменить копию этого инварианта, чтобы он имел смысл в контексте вызывающей стороны, как предложение ensures, например:

ensures clean <==> (forall k :: 0 <= k < a.Length ==> a[k] != key)

(Добавьте это прямо под предложением requires в isClean.) В этом предложении ensures clean относится к именованному возвращаемому значению метода isClean. Если вы добавите это предложение, Dafny все равно будет жаловаться, потому что вы просите его доказать, что квантификатор forall равен false. Это эквивалентно попытке доказать квантор exists true и требует явного свидетеля, который представляет собой значение k, из-за которого тело формулы оказывается true/false.

В этом случае интуитивная причина, по которой isClean возвращает false, заключается в том, что a[0] имеет значение 1, поэтому a не чисто от 1. Мы можем продемонстрировать этот свидетель Дафни, добавив утверждение

assert a[0] == 1;

в тело Main сразу после вызова isClean.


Для ясности вот полная версия программы, которая проверяет:

method Main() {
  var a := new int[3];
  a[0], a[1], a[2] := 1,2,3;
  var v := isClean (a, 1);
  assert a[0] == 1;
  assert v == false;
}

method isClean(a: array <int>, key: int) returns (clean: bool)
  requires a.Length > 0
  ensures clean <==> (forall k :: 0 <= k < a.Length ==> a[k] != key)
{
  var i := 0;
  while (i < a.Length)
    invariant 0 <= i <= a.Length
    invariant forall k :: 0 <= k < i ==> a[k] != key
  {
    if (a[i] == key) {
      clean := false;
      return;
    }
    i := i + 1;
  }
  clean := true;
}
person James Wilcox    schedule 09.09.2020
comment
спасибо Джеймс. вы всегда так полезны, это определенно имеет смысл - person Arthur; 09.09.2020