Я думаю, что проблема в том, что в графе решателя для dafny нет ничего, с чем можно было бы создать экземпляр квантификатора. Вы можете проверить его, добавив дополнительные утверждения, чтобы у Дафни возникла идея использовать эти значения для создания экземпляров квантификаторов.
Например это:
method Main() {
var b: array<char> := new char[5];
b[0], b[1], b[2], b[3], b[4] := 't', 'e', 's', 't', 's';
assert b[0] == 't';
assert b[3] == 't';
assert noDuplicates(b) == false;
}
Или это
method Main() {
var b: array<char> := new char[5];
b[0], b[1], b[2], b[3], b[4] := 't', 'e', 's', 't', 's';
assert b[0] == b[3];
assert noDuplicates(b) == false;
}
Почему это работает
Обычно, когда Dafny нужно доказать что-то, связанное с квантором, ему приходится выбирать значения для создания экземпляра квантора (из-за сокращения до SAT). Одной из вещей, которые он обычно пытается сделать, является свежая произвольная константа, но на этом вы далеко не продвинетесь. Вам нужно выбрать значения 0 и 3 (например). Однако существует много целых чисел, поэтому шансы выбрать такие значения наугад невелики — настолько малы, что на самом деле он даже не будет пытаться. Вместо этого он просматривает все факты, которые ему уже известны, и выбирает те, которые соответствуют форме атомов в количественной формуле. В этом случае он ищет такие вещи, как a[i]==a[j]
, поэтому, помещая утверждение, включающее b[0]
и b[3]
, это побуждает Дафни в конечном итоге попробовать значения 0
и 3
для i
и j
. Прямая версия b[0]==b[3]
работает совершенно напрямую, а непрямая версия b[0]==t && b[3]==t
косвенно заставит Дафни поместить ребра между b[0]
и b[3]
в своем эпграфе и вывести факт b[0]==b[3]
, который затем предложит ей попробовать 0
и 3
для создания экземпляра квантифера.
Мне было бы интересно услышать о любых других решениях.
ИЗМЕНИТЬ
Я подумал о другом решении, использующем аннотацию fuel
, но я не знаю, действительно ли это лучшее решение:
method Main() {
var b: array<char> := new char[5];
b[0], b[1], b[2], b[3], b[4] := 't', 'e', 's', 't', 's';
assert {:fuel contains,3} noDuplicates(b[..]) == false;
}
predicate noDuplicates (a:seq<char>)
{
a == [] || (!contains(a[1..], a[0]) && noDuplicates(a[1..]))
}
predicate contains (a:seq<char>, v:char)
{
a != [] && (a[0] == v || contains(a[1..],v))
}
person
lexicalscope
schedule
10.05.2016