How let-such-that expressions could be done in Dafny 3.1.0? - dafny

Expressions let-such-that that worked in previous releases of Dafny do not work in Dafny 3.1.0. For example, the following code (also in https://rise4fun.com/Dafny/ABZpf) raise the error: "to be compilable, the value of a let-such-that expression must be uniquely determined".
datatype NNF_Formula = F
| T
| V(prop:string)
| NegV(prop:string)
| EX(f:NNF_Formula)
| AX(f:NNF_Formula)
| EG(f:NNF_Formula)
| AG(f:NNF_Formula)
| ER(f1:NNF_Formula,f2:NNF_Formula)
| AR(f1:NNF_Formula,f2:NNF_Formula)
| EF(f:NNF_Formula)
| AF(f:NNF_Formula)
| EU(f1:NNF_Formula,f2:NNF_Formula)
| AU(f1:NNF_Formula,f2:NNF_Formula)
| EUsel(f1:NNF_Formula,f2:NNF_Formula)
| AUsel(f1:NNF_Formula,f2:NNF_Formula)
| Or(f1:NNF_Formula,f2:NNF_Formula)
| And(f1:NNF_Formula,f2:NNF_Formula)
function method family(alpha: NNF_Formula): nat {
match alpha
case F => 0
case T => 1
case V(_) => 2
case NegV(_) => 3
case AX(_) => 4
case EX(_) => 5
case AG(_) => 6
case EG(_) => 7
case AR(_, _) => 8
case ER(_, _) => 9
case AF(_) => 10
case EF(_) => 11
case AU(_, _) => 12
case EU(_, _) => 13
case AUsel(_, _) => 14
case EUsel(_, _) => 15
case Or(_, _) => 16
case And(_, _) => 17
}
// ORDER IN NNF FORMULAS
predicate method leq_string(s1:string,s2:string) {
s1 == "" || (s2 != "" && s1[0] <= s2[0] && ( s1[0] == s2[0] ==> leq_string(s1[1..],s2[1..])))
}
lemma antisym_leq_string_Lemma (s1:string, s2:string)
requires leq_string(s1,s2) && leq_string(s2,s1)
ensures s1 == s2
{
if s1 != "" && s2 != "" { antisym_leq_string_Lemma(s1[1..],s2[1..]); }
}
predicate method leq_NNF_Formula (alpha:NNF_Formula, beta:NNF_Formula)
{
if family(alpha) < family(beta) then true
else if family(alpha) > family(beta) then false
else if family(alpha) <= 1 then true
else if 2 <= family(alpha) <= 3 then leq_string(alpha.prop,beta.prop)
else if 4 <= family(alpha) <= 7 || 10 <= family(alpha) <= 11 then leq_NNF_Formula(alpha.f,beta.f)
else leq_NNF_Formula(alpha.f1,beta.f1) && (alpha.f1 == beta.f1 ==> leq_NNF_Formula(alpha.f2,beta.f2))
}
lemma minimum_formula_Lemma (s:set<NNF_Formula>)
requires s != {}
ensures exists phi :: phi in s && forall psi :: psi in s-{phi} ==> (leq_NNF_Formula(phi,psi) && psi != phi)
function method pick_minimum_formula(s: set<NNF_Formula>): NNF_Formula
requires s != {}
{
minimum_formula_Lemma(s);
var phi :| phi in s && forall psi :: psi in s-{phi} ==> (leq_NNF_Formula(phi,psi) && psi != phi);
phi
}
For clarity, I have omitted the proof of the lemma, but it can be proved. I have also complicated a bit the ensures of the lemma for ensured uniqueness. In previous releases of Dafny also this works:
ensures exists phi :: phi in s && forall psi :: psi in s ==> leq_NNF_Formula(phi,psi).
I need some way of iteration on sets of NNF_Formula, is there a different way to do this on Dafny 3.1.0?

This error could certainly serve to be clearer.
This scenario is only disallowed for function methods. However, you could write it in an ordinary method and it would be fine.
method pick_minimum_formula(s: set<NNF_Formula>) returns (nnf: NNF_Formula)
requires s != {}
{
minimum_formula_Lemma(s);
var phi :| phi in s && forall psi :: psi in s-{phi} ==> (leq_NNF_Formula(phi,psi) && psi != phi);
nnf := phi;
}
You could also write it as a function, and it would be fine.
However, a function method does require that any let-such-that expression be unique. The reason is that a compiled let-such-that expression might be non-deterministic; on the other hand, any function must to be deterministic. But a function method must be a method whose output matches the result of the function! This cannot be guaranteed if the method would be nondeterministic.

Related

Multiset proof verification in dafny

I'm trying to prove a little lemma for a larger proof, the lemma definition is below:
lemma LoopLemma(a: seq<int>, b: seq<int>, c: seq<int>, k:int, i:int, j:int)
requires 0 <= i < |a| && 0<= j < |b| && 0 <= k < |c| && i +j ==k && |a| + |b| == |c|
requires Sorted(c[..k]) && Sorted(b) && Sorted(a)
requires multiset(c[..k]) == multiset(a[..i]+b[..j])
ensures Sorted(c[..k]+[b[j]]) && Sorted(c[..k]+[a[i]])
{
assert multiset(c[..k]) == multiset(a[..i]+b[..j]);
var q:=a[..i]+b[..j];
var c1 := c[..k];
assert Sorted(c1);
assert multiset(c1) == multiset(q);
assert |q| == i + j;
assert |c1| == k == i + j;
calc {
multiset(c1) == multiset(q);
==
forall l :: l in multiset(c1) ==> l in multiset(q);
== {assert forall l :: l in multiset(q) ==> exists r :: 0 <= r <|q| && l == q[r]; assert forall l :: l in multiset(c1) ==> exists r :: 0 <= r <|c1| && l == c1[r];}
forall l :: 0<=l <|c1| ==> exists r :: 0 <= r < |q| && q[r] == c1[l];
}
}
I get "the calculation step between the previous line and this line might not hold" for the last step, and I don't understand why.
All I'm saying there is that if the multisets of two sequences are equal, for any entry in the first sequence exists an entry in the second sequence with the same value.
I tried some simpler examples (where I define the sequences explicitly) and it worked. Maybe I don't understand something about multisets?
Any suggestions will help.
Additional hint that needed here is every element in sequence is in multiset i.e forall i :: 0 <= i < |c[..k]| ==> c[..k][i] in multiset(c[..k]) (hint in forward direction of reasoning). Following snippet verifies.
predicate Sorted(a: seq<int>)
{
if |a| <= 1 then true else (a[0] <= a[1]) && Sorted(a[1..])
}
lemma LoopLemma(a: seq<int>, b: seq<int>, c: seq<int>, k: int, i: int, j: int)
requires 0 <= i < |a| && 0 <= j < |b| && 0 <= k < |c| && i + j == k && |a| + |b| == |c|
requires Sorted(c[..k]) && Sorted(a) && Sorted(b)
requires multiset(c[..k]) == multiset(a[..i] + b[..j])
{
var s := a[..i] + b[..j];
calc {
multiset(c[..k]) == multiset(s);
forall e :: e in multiset(c[..k]) ==> e in multiset(s);
{
assert forall e :: e in multiset(c[..k]) ==>
exists r :: 0 <= r < |s| && s[r] == e;
// assert forall e :: e in multiset(c[..k]) ==>
// exists r :: 0 <= r < |c[..k]| && c[..k][r] == e;
assert forall i :: 0 <= i < |c[..k]| ==> c[..k][i] in multiset(c[..k]);
}
forall i :: 0 <= i < |c[..k]| ==> exists r :: 0 <= r < |s| && s[r] == c[..k][i];
}
}

Can I allow preconditions on the argument to a higher-order function in Dafny?

Is there a way to say that a higher-order function permits preconditions on the function it takes as an argument?
Here's the concrete situation I'm trying to solve. I wrote this function for filtering items in a seq based on a predicate:
function method filterSeq<T>(s: seq<T>, fn: T -> bool): seq<T>
ensures forall i | 0 <= i < |filterSeq(s, fn)| :: fn(filterSeq(s, fn)[i]) == true
ensures forall i | 0 <= i < |filterSeq(s, fn)| :: filterSeq(s, fn)[i] in s
ensures forall i | 0 <= i < |s| :: fn(s[i]) ==> s[i] in filterSeq(s, fn)
{
if |s| == 0 then [] else (
if fn(s[0]) then [s[0]] + filterSeq(s[1..], fn) else filterSeq(s[1..], fn)
)
}
This covers the postconditions I care about, but doesn't say anything about the argument to fn. I want to say that for any property which holds for all T in s, this property is permitted as a precondition on fn.
The problem that lead me to this was an attempt to filter a sequence containing other sequences:
var sequences := [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
assert forall i | 0 <= i < |sequences| :: |sequences[i]| == 3;
var result := filterSeq(sequences, sequence => sequence[0] == 4);
When I attempt this, I get an error on sequence[0], which says index out of range. Fair enough, I try to add a precondition to the lambda:
var sequences := [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
assert forall i | 0 <= i < |sequences| :: |sequences[i]| == 3;
var result := filterSeq(sequences,
sequence requires |sequence| == 3 => sequence[0] == 4);
Now I get the error value does not satisfy the subset constraints of 'seq<int> -> bool' (possible cause: it may be partial or have read effects) on the lambda argument. This also makes sense, I'm passing a partial function where I wrote the type signature for a non-partial one.
My question is: How do I change filterSeq to allow this? Can I somehow write it so that it will work with arbitrary preconditions, or will I have to write a separate filterSeqOfSequences method to cover this specific use-case?
Great question. The answer is yes. You need to use Dafny's notion of partial functions, which are written with a doubly-dashed arrow like T --> bool. If f has this type, then f.requires is its precondition. (In fact, you can think of the total function type T -> bool as a special case of T --> bool where f.requires is true for all values of type T.)
Here is one way to rewrite your higher-order function to accept a partial function as an argument:
function method filterSeq<T>(s: seq<T>, fn: T --> bool): seq<T>
requires forall x | x in s :: fn.requires(x) // ***
ensures forall x | x in filterSeq(s, fn) :: x in s // ***
ensures forall i | 0 <= i < |filterSeq(s, fn)| :: fn(filterSeq(s, fn)[i]) == true
ensures forall i | 0 <= i < |filterSeq(s, fn)| :: filterSeq(s, fn)[i] in s
ensures forall i | 0 <= i < |s| :: fn(s[i]) ==> s[i] in filterSeq(s, fn)
{
if |s| == 0
then []
else if fn(s[0])
then [s[0]] + filterSeq(s[1..], fn)
else filterSeq(s[1..], fn)
}
method Test()
{
var sequences := [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
assert forall i | 0 <= i < |sequences| :: |sequences[i]| == 3;
var result := filterSeq(sequences,
sequence requires |sequence| == 3 => sequence[0] == 4);
}
I just made two changes to your code, marked by ***.
First is the new precondition on filterSeq that you already mentioned in your question that requires that fn.requires holds on all elements of s. Second, we also need one new technical postcondition that guarantees the output of filterSeq is a subset of its input. This is needed to ensure the well formedness of the other postconditions, which try to call fn on elements of the output.
The Test method does not change at all. It just works with the new version of filterSeq.

Dafny How could I write a predicate to prove a string is sorted by 'b' => 'a' => 'd'?

Could somebody please help me out in writing a Dafny predicate that checks if a string is sorted in the order 'b' -> 'a' -> 'd'
i.e:
"bbbaaaaad" == true
"abd" == false
"bad" == true
The predicate should have the following form:
predicate sortedbad(s:string)
{
[???]
}
Thanks
Here is one way to do it.
predicate bad_compare(c1:char, c2:char) {
c1 == 'b' || (c1 == 'a' && c2 != 'b') || c2 == 'd'
}
predicate sortedbad(s:string)
{
forall i, j | 0 <= i <= j < |s| :: bad_compare(s[i], s[j])
}
lemma Test()
{
assert sortedbad("bbbbaaaadddd");
var s := "bbbbbbda";
assert !bad_compare(s[6], s[7]);
assert !sortedbad(s);
}

Given several axioms and a property, how do I structure a proof of the property?

Given the following axioms:
A>=0
forall n :: n>=0 && n<N1 ==> n < A
N1 >= A
We want to prove that N1==A using Dafny.
I have tried following Dafny program:
function N1(n: int,A: int):bool
requires A>=0 && n>=0
{
if n==0 && A<=n
then true else
if n>0
&& A<=n
&& forall k::
(if 0<=k && k<n
then A>k else true)
then true
else false
}
lemma Theorem(n: int,A: int)
requires A>=0 && n>=0 && N1(n,A)
ensures n==A;
{ }
But Dafny fails to prove that. Is there a way to N1==A from the given axioms?
Dafny can prove it just fine, but it needs a bit more help:
predicate P(n:int, N1:int)
{
n >= 0 && n < N1
}
lemma Lem(A:int, N1:int)
requires A>=0
requires forall n :: P(n, N1) ==> n < A
requires N1 >= A
ensures N1 == A
{
if(N1 > A)
{
assert A >= 0 && A < N1;
assert P(A, N1);
assert A < A;
assert false;
}
assert N1 <= A;
}
The proof proceeds by contradiction, and is quite standard. The only Dafny specific bit of the proof is that we have to give a name to the property that n >= 0 && n < N1. We give the property the name P by introducing it as a predicate. The requirement to introduce P comes from the interaction of Dafny with some details of how quantifier instantiation (trigger matching) works in the underlying SMT solver (Z3).
You may alternatively prefer to write the lemma this way:
lemma Lem(A:int, N1:int)
requires A>=0
requires forall n :: P(n, N1) ==> n < A
requires N1 >= A
ensures N1 == A
{
calc ==>
{
N1 > A;
{assert P(A, N1);}
A < A;
false;
}
assert N1 <= A;
}

cond style statements in erlang

Coming from a Lisp background, Erlang's case statement seems a bit baffling to me. I'm currently working on the Sieve of Eratosthenes problem, trying to generate a list of the prime factors of a number N. However I can't seem to migrate what seems like a simple cond statement in Lisp to the equivalent in Erlang.
So far I have constructed an if statement that resembles how I would go about things in Lisp:
prime_factors(N) -> pf_helper(N, [], 2).
pf_helper(M, PL, D) ->
if
prime_p(M) == true -> [ M | PL ];
(prime_p(D) == true) and (M rem D == 0) -> pl_helper(M div D, [ D | PL ], D+1);
(prime_p(D) == true) and (M rem D /= 0) -> pl_helper(M, PL, D+1);
prime_p(D) == false -> pl_helper(M, PL, D+1)
end.
I am aware that this will not compile since I can only have BIF calls in my guards. The problem is that I cannot conceptualize how this would run as a case statement, since case handles a conditional expression on one argument. In the case that I represent the three pf_helper arguments in a tuple:
pf_helper(M,PL,D) -> pf_helper({M, PL, D}).
what would the patterns be inside the case statements that correspond to the conditional expressions
prime_p(M) == true
(prime_p(D) == true) and (M rem D == 0)
(prime_p(D) == true) and (M rem D /= 0)
prime_p(D) == false
?
Use some guards:
case {prime_p(M), prime_p(D)} of
{true, _} -> [M|PL];
{false, true} when (M rem D == 0) -> ...;
{false, true} when (M rem D /= 0) -> ...;
{false, false} -> ...
end
I think Anthony Ramine was working on implementing cond at one point.

Resources