For the following code:
bool assertTest(int? n1, int? n2) {
return (n1 == null) || (n1 != null && n2 != null);
}
there is a warning at n1 != null saying The operand can't be null, so the condition is always true.
Why does this warning show up? n1 is obviously nullable.
The boolean operation are lazy, it means that if you evaluate a || b and a is true, then b is not even evaluated.
In your case, if b = (n1 != null && n2 != null) is evaluated, it means a = (n1 == null) = false, which means n1 != null so the check n1 != null will always be true.
Related
For some reason dafny reports that the ensure condition for PreorderTraversalChildrenAreLater might not always hold even though the quantified expression always holds... later on in the same lemma. Ideally, once I've shown the existence k, I was attempting to show that all child elements of the root.repr will appear later in the PreorderTraversal.
ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> forall child :: child in PreorderTraversal(root)[k].repr && child != PreorderTraversal(root)[k] ==> exists j :: k < j < |PreorderTraversal(root)| && PreorderTraversal(root)[j] == child
function PreorderTraversal(root: TreeNode): seq<TreeNode>
reads root.repr
requires root.Valid()
ensures forall x :: x in root.repr ==> x in PreorderTraversal(root)
ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> PreorderTraversal(root)[k] in root.repr && PreorderTraversal(root)[k].Valid()
// ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> PreorderTraversal(root)[k] in root.repr
{
if root.left != null && root.right != null then [root]+PreorderTraversal(root.left)+PreorderTraversal(root.right) else if root.left != null then [root]+PreorderTraversal(root.left) else if root.right != null then [root]+PreorderTraversal(root.right) else [root]
}
lemma {:verify true} PreorderTraversalChildrenAreLater(root: TreeNode)
requires root.Valid()
//the following does not verify
ensures forall x :: x in root.repr ==> exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x
{
// var what := PreorderTraversal(root);
assert forall x :: x in root.repr ==> x in PreorderTraversal(root);
forall x | x in root.repr
ensures exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x
{
assert x in PreorderTraversal(root);
seqbusiness(PreorderTraversal(root), x);
}
// but it verifies here, at least I get the green checkmark
assert forall x :: x in root.repr ==> exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x;
}
lemma seqbusiness<A>(s: seq<A>, elem: A)
requires elem in s
ensures exists k:nat :: 0 <= k < |s| && s[k] == elem
{
}
class TreeNode {
var val: int;
var left: TreeNode?;
var right: TreeNode?;
ghost var repr: set<TreeNode>;
constructor(val: int, left: TreeNode?, right: TreeNode?)
requires left != null ==> left.Valid()
requires right != null ==> right.Valid()
requires left != null && right != null ==> left.repr !! right.repr
ensures this.val == val
ensures this.left == left
ensures this.right == right
ensures left != null ==> this !in left.repr
ensures right != null ==> this !in right.repr
ensures Valid()
{
this.val := val;
this.left := left;
this.right := right;
var leftRepr := if left != null then {left}+left.repr else {};
var rightRepr := if right != null then {right}+right.repr else {};
this.repr := {this} + leftRepr + rightRepr;
}
predicate Valid()
reads this, repr
decreases repr
{
this in repr &&
(this.left != null ==>
(this.left in repr
&& this !in this.left.repr
&& this.left.repr < repr
&& this.left.Valid()
))
&& (this.right != null ==>
(this.right in repr
&& this !in this.right.repr
&& this.right.repr < repr
&& this.right.Valid())) &&
(this.left != null && this.right != null ==> this.left.repr !! this.right.repr && this.repr == {this} + this.left.repr + this.right.repr)
&& (this.left != null && this.right == null ==> this.repr == {this} + this.left.repr)
&& (this.right != null && this.left == null ==> this.repr == {this} + this.right.repr)
&& (this.right == null && this.left == null ==> this.repr == {this})
}
}
I agree it doesn't verify as is and its not clear why. However, I did manage to get it to go through by lifting out a predicate as follows:
predicate WithinRootPreorder(root:TreeNode, x: TreeNode)
reads root.repr
requires root.Valid()
requires x in root.repr {
exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x
}
lemma {:verify true} PreorderTraversalChildrenAreLater(root: TreeNode)
//reads root.repr
requires root.Valid()
ensures root.repr == old(root.repr)
//the following does not verify
ensures forall x :: x in root.repr ==> WithinRootPreorder(root,x)
{
...
assert forall x :: x in root.repr ==> WithinRootPreorder(root,x);
}
That seemed to work for me.
I'm trying to define an operation on classes and then prove properties about it.
//the following resolves the error with substring, but creates problems down the line
//predicate isSubstring<A(!new)>(sub: seq<A>, super: seq<A>) {
predicate isSubstring<A>(sub: seq<A>, super: seq<A>) {
|sub| <= |super| && exists xs: seq<A> :: IsSuffix(xs, super) && sub <= xs
}
predicate IsSuffix<T>(xs: seq<T>, ys: seq<T>) {
|xs| <= |ys| && xs == ys[|ys| - |xs|..]
}
However, the IsSubstring method produces the following error.
a exists expression involved in a predicate definition is not allowed to depend on the set of allocated references, but values of 'xs' may contain references (see documentation for 'older' parameters
I am aware that I can set (!new) restriction on the type variable A. That resolves the issue at the predicate. However I am presented with another issue.
lemma AllChildrenTraversalsAreSubstrings(root: TreeNode)
requires root.Valid()
ensures forall x :: x in root.repr && x in PreorderTraversal(root) ==> isSubstring(PreorderTraversal(x), PreorderTraversal(root))
{
forall x | x in root.repr && x in PreorderTraversal(root)
ensures isSubstring(PreorderTraversal(x), PreorderTraversal(root))
{
if x == root {
}else if x == root.left || x == root.right {
PreorderTraversalSubstrings(root);
}else {
if root.left != null && x in root.left.repr {
AllChildrenTraversalsAreSubstrings(root.left);
}
if root.right != null && x in root.right.repr {
AllChildrenTraversalsAreSubstrings(root.right);
}
}
}
}
In the forall ensure it reports:
type parameter (A) passed to predicate isSubstring must support no references (got TreeNode)
function method PreorderTraversal(root: TreeNode): seq<TreeNode>
reads root.repr
requires root.Valid()
// ensures forall x :: x in PreorderTraversal(root) ==> x.Valid()
ensures forall x :: x in root.repr ==> x in PreorderTraversal(root)
ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> PreorderTraversal(root)[k] in root.repr && PreorderTraversal(root)[k].Valid()
ensures injectiveSeq(PreorderTraversal(root))
ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> PreorderTraversal(root)[k] in root.repr
// ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> forall child :: child in PreorderTraversal(root)[k].repr && child != child in PreorderTraversal(root)[k] ==> exists j :: k < j < |PreorderTraversal(root)| && PreorderTraversal(root)[j] == child
{
if root.left != null && root.right != null then [root]+PreorderTraversal(root.left)+PreorderTraversal(root.right) else if root.left != null then [root]+PreorderTraversal(root.left) else if root.right != null then [root]+PreorderTraversal(root.right) else [root]
}
lemma PreorderTraversalSubstrings(root: TreeNode)
requires root.Valid()
ensures root.left != null ==> isSubstring(PreorderTraversal(root.left), PreorderTraversal(root))
ensures root.right != null ==> isSubstring(PreorderTraversal(root.right), PreorderTraversal(root))
{
if root.left != null && root.right != null {
calc {
PreorderTraversal(root);
[root]+PreorderTraversal(root.left)+PreorderTraversal(root.right);
}
assert |PreorderTraversal(root.left)| < |PreorderTraversal(root)|;
assert |PreorderTraversal(root.right)| < |PreorderTraversal(root)|;
assert IsSuffix(PreorderTraversal(root.left)+PreorderTraversal(root.right), PreorderTraversal(root));
assert IsSuffix(PreorderTraversal(root.right), PreorderTraversal(root));
assert PreorderTraversal(root.left) <= PreorderTraversal(root.left)+PreorderTraversal(root.right);
}else if root.left != null && root.right == null {
calc {
PreorderTraversal(root);
[root]+PreorderTraversal(root.left);
}
assert |PreorderTraversal(root.left)| < |PreorderTraversal(root)|;
assert IsSuffix(PreorderTraversal(root.left), PreorderTraversal(root));
}else if root.left == null && root.right != null {
calc {
PreorderTraversal(root);
[root]+PreorderTraversal(root.right);
}
assert |PreorderTraversal(root.right)| < |PreorderTraversal(root)|;
assert IsSuffix(PreorderTraversal(root.right), PreorderTraversal(root));
}
}
class TreeNode {
var val: int;
var left: TreeNode?;
var right: TreeNode?;
ghost var repr: set<TreeNode>;
constructor(val: int, left: TreeNode?, right: TreeNode?)
requires left != null ==> left.Valid()
requires right != null ==> right.Valid()
requires left != null && right != null ==> left.repr !! right.repr
ensures this.val == val
ensures this.left == left
ensures this.right == right
ensures left != null ==> this !in left.repr
ensures right != null ==> this !in right.repr
ensures Valid()
{
this.val := val;
this.left := left;
this.right := right;
var leftRepr := if left != null then {left}+left.repr else {};
var rightRepr := if right != null then {right}+right.repr else {};
this.repr := {this} + leftRepr + rightRepr;
}
predicate Valid()
reads this, repr
decreases repr
{
this in repr &&
(this.left != null ==>
(this.left in repr
&& this !in this.left.repr
&& this.left.repr < repr
&& this.left.Valid()
))
&& (this.right != null ==>
(this.right in repr
&& this !in this.right.repr
&& this.right.repr < repr
&& this.right.Valid())) &&
(this.left != null && this.right != null ==> this.left.repr !! this.right.repr && this.repr == {this} + this.left.repr + this.right.repr)
&& (this.left != null && this.right == null ==> this.repr == {this} + this.left.repr)
&& (this.right != null && this.left == null ==> this.repr == {this} + this.right.repr)
&& (this.right == null && this.left == null ==> this.repr == {this})
}
}
Oddly enough,PreorderTraversalSubstrings verifies just fine even with the (!new) restriction but the ensure statement of the forall in AllChildrenTraversalsAreSubstrings throws the above error. How should I proceed? Switching to a datatype would make my life easier but I'm trying to verify programs involving classes.
Do I define the binary tree datatype and then assert that all operations on it are equivalent to the valid class tree version? Is that even possible if existence quantifier expressions can't refer to allocated value?
Right, so I am trying to verify the following fill() method. Currently the first and third invariant clauses fail, and I'm not entirely surely why. Any thoughts appreciated!
class List {
var data : int;
var next : List?;
ghost var rep : set<List>;
constructor(d : int)
ensures this.valid();
{
this.data := d;
this.next := null;
this.rep := {this};
}
predicate valid()
reads this, rep;
decreases rep + {this};
{
this in rep
&& (next != null ==> (
next in rep
&& next.rep <= rep
&& this !in next.rep
&& next.valid()
))
}
}
method fill(ol : List, on : int)
requires ol.valid();
requires on >= 0;
modifies ol.rep;
{
assert ol in ol.rep;
var n := on;
var l : List? := ol;
//
//
while(n >= 0 && l != null)
invariant ol.valid();
invariant (l != null) ==> l.valid();
invariant (l != null) ==> (l in ol.rep);
modifies l.rep;
{
l.data := n;
l := l.next;
n := n - 1;
}
}
Here's one way to do it.
class List {
var data : int;
var next : List?;
ghost var rep : set<List>;
constructor(d : int)
ensures valid()
{
data := d;
next := null;
rep := {this};
}
predicate valid()
reads this, rep
decreases rep + {this}
{
&& this in rep
&& (next != null ==>
&& next in rep
&& next.rep <= rep
&& this !in next.rep
&& next.valid())
}
static twostate lemma valid_frame(a: List)
requires old(a.valid())
requires forall x | x in old(a.rep) :: unchanged(x`next)
requires forall x | x in old(a.rep) :: unchanged(x`rep)
decreases old(a.rep)
ensures a.valid()
{}
}
method fill(ol : List, on : int)
requires ol.valid()
requires on >= 0
modifies ol.rep
ensures ol.valid()
{
var n := on;
var l : List? := ol;
label L:
while(n >= 0 && l != null)
invariant l != null ==> l.valid()
invariant l != null ==> l.rep <= old(ol.rep)
modifies ol.rep`data
{
l.data := n;
l := l.next;
n := n - 1;
}
List.valid_frame#L(ol);
}
The basic idea of this proof is that the valid predicate only depends on the next and rep fields of List. Since fill only writes to the data field, it must preserve validity.
To implement the idea, we can use a twostate lemma in Dafny. The way to "pass" a particular old state to such a lemma uses a combination of the label feature and #.
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 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;
}