Для оператора Эпсилона Гильберта, также известного в Дафни как выражение «пусть такое-то»,
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>
. Я не знаю, как получить уникальное значение из общего набора. (
Информацию о том, почему требование уникальности важно в скомпилированных выражениях, см. в этом документе .
Rustan