Эпсилон-оператор Гильберта

Почему вы можете использовать оператор Гильберта эпсилон в методе и в функции, но не в «методе функции»?

method choose<T>(s:set<T>) returns (x:T)
	requires s != {}
{
var z :| z in s;
return z;
}

function choose'<T>(s:set<T>):T
// function method choose'<T>(s:set<T>):T // Activate this line and comment the previous line to see the error
	requires s != {}
{
var z :| z in s;
z
}


person jiplucap    schedule 06.07.2018    source источник
comment
Вы не сказали, какую фактическую ошибку вы нашли. Текущий Dafny (3.1.0) жалуется, что для компиляции значение выражения let-so-that должно быть однозначно определено.   -  person hmijail mourns resignees    schedule 29.04.2021


Ответы (2)


Для того чтобы оператор Гильберта эпсилон, также известный в Дафни как выражение пусть такой-то,

var z :| P; E

чтобы быть компилируемым, ограничение P должно однозначно определять z. В вашем случае ограничение P равно z in s, которое не определяет z однозначно, за исключением одноэлементных наборов.

Если бы s имел тип set<int>, вы могли бы (неэффективно) выполнить это требование, изменив свою функцию choose' на:

function method choose'<T>(s:set<int>):int
  requires s != {}
{
  var z :| z in s && forall y :: y in s ==> z <= y;
  z
}

Почти. Вам нужно убедить Дафни, что такой z существует. Вы можете сделать это в лемме. Вот работающая лемма, вероятно, длиннее, чем необходимо, но первое, что я получил, которая делает это. Обратите внимание, что в лемме также используется оператор Гильберта, но в контексте оператора, поэтому требование уникальности не применяется.

function method choose'<T>(s:set<int>):int
  requires s != {}
{
  HasMinimum(s);
  var z :| z in s && forall y :: y in s ==> z <= y;
  z
}

lemma HasMinimum(s: set<int>)
  requires s != {}
  ensures exists z :: z in s && forall y :: y in s ==> z <= y
{
  var z :| z in s;
  if s == {z} {
    // the mimimum of a singleton set is its only element
  } else if forall y :: y in s ==> z <= y {
    // we happened to pick the minimum of s
  } else {
    // s-{z} is a smaller, nonempty set and it has a minimum
    var s' := s - {z};
    HasMinimum(s');
    var z' :| z' in s' && forall y :: y in s' ==> z' <= y;
    // the minimum of s' is the same as the miminum of s
    forall y | y in s
      ensures z' <= y
    {
      if
      case y in s' =>
        assert z' <= y;  // because z' in minimum in s'
      case y == z =>
        var k :| k in s && k < z;  // because z is not minimum in s
        assert k in s';  // because k != z
    }
  }
}

К сожалению, тип вашего s не set<int>. Я не знаю, как получить уникальное значение из общего набора. :(

Информацию о важности требования уникальности в скомпилированных выражениях см. в этой статье.

Рустан

person Rustan Leino    schedule 09.07.2018
comment
Хотя этот ответ очень информативный, на самом деле он не отвечает на вопрос, почему проблема возникает только в методе функции. Насколько я понимаю, функция не может вызвать ошибку компиляции, потому что она никогда не компилируется. Метод также не вызывает ошибки, потому что методы не обязаны возвращать один и тот же результат при выполнении с одним и тем же вводом/состоянием. Но методы функций скомпилированы И, как ожидается, всегда будут возвращать один и тот же результат для заданного ввода, чего оператор let-so-that не делает сам по себе в Dafny (как подробно описано в упомянутой статье), поэтому он нуждается в ограничении. - person hmijail mourns resignees; 29.04.2021
comment
Да, то, что вы сказали, верно. - person Rustan Leino; 30.04.2021

Хорошо, спасибо, я понимаю проблему компиляции не однозначно определенного значения. Однако, согласно вашему ответу, мой первый метод выбора должен вызывать ту же ошибку, что и метод выбора функции, не так ли?

method choose<T>(s:set<T>) returns (x:T)
	requires s != {}
{
var z :| z in s;
return z;
}

function choose'<T>(s:set<T>):T
// function method choose'<T>(s:set<T>):T // Activate this line and comment the previous line to see the error
	requires s != {}
{
var z :| z in s;
z
}

person jiplucap    schedule 10.07.2018
comment
Добавление еще одного ответа на ваш вопрос - не лучший способ продолжить работу - возможно, Рустан даже этого не видел. Вы должны были добавить комментарий к его ответу. - person hmijail mourns resignees; 15.04.2021
comment
Как прокомментировал выше @hmijailmournsresignees, есть два оператора :|. Оператор назначить такой-то может быть недетерминированным. Выражение let-some-that должно быть детерминированным, т. е. оно должно оцениваться чем-то, что является функцией его аргументов. В фантомном контексте (например, в function, который является фантомной функцией) только верификатор должен знать, как детерминистически произвести значение, поэтому вам не нужно делать что-либо еще. Однако для скомпилированного выражения (например, function method, которое является скомпилированной функцией) вы несете ответственность за уникальность. - person Rustan Leino; 30.04.2021
comment
Да понятно. Спасибо. - person jiplucap; 03.05.2021