Estou trabalhando com Dafny e tentando entender como as especificações, particularmente modifica e garante multiconjuntos, afetam a verificação.
Tenho um método do_nothing
especificado para modificar um array a, mas que garante que o multiconjunto de seus elementos permaneça inalterado. O corpo do método está vazio.
method do_nothing(a: array<int>)
modifies a
ensures multiset(a[..]) == multiset(old(a[..]))
{
// nothing is done
}
method test()
{
var a := new int[6] [2, -3, 4, 1, 1, 7];
assert a[..] == [2, -3, 4, 1, 1, 7]; // Verifies
assert a[0] !=0 ; // Verifies
do_nothing(a);
assert a[0] != 0; // <-- Verification Error: This assertion cannot be proved
}
Minha expectativa:
Como não há 0 dentro a
de nada, e dafny concorda que isso do_nothing
garante multiset(a[..]) == multiset(old(a[..]))
. Portanto, a afirmação a[0] != 0 deve ser válida e verificada com sucesso.
O problema:
Dafny falha ao verificar a afirmação final assert a[0] != 0;
Seu método
do_nothing
é especificado apenas para mantermultiset(a[..])
intacto, não necessariamente o arraya
. Como os elementos em um multiconjunto não têm uma ordem definida, essa propriedade é mantida mesmo se você permutar entradas no array. Por exemplo, a seguir está uma implementação correta de umdo_nothing
whena.Length >1
:Agora, no site de chamada de
do_nothing
, dentro detest
, Dafny não se importa com sua implementação dedo_nothing
, ele apenas considera sua especificação -- e como visto acima, isso não garante quea[0]
não possa ter sido trocado por algum outroa[i]
.Os multiconjuntos têm gatilhos ocultos para evitar sobrecarregar o verificador de Dafny com gatilhos.
Você pode adicionar esta afirmação depois
do_nothing
para ajudar Dafny a acionar alguns axiomas necessários em multiconjuntos.Isso fará com que seu código passe na verificação. Observe que, como se trata de gatilhos, inserir o seguinte código no-op faria o mesmo