I am trying to prove the correctness of a binary search tree implementation in Dafny, but I am struggling to prove that the computed size corresponds to the size of the elements set.
So far I have written the following code:
datatype TreeSet =
Leaf
| Node(left: TreeSet, data: int, right: TreeSet)
predicate Valid(treeSet: TreeSet) {
match treeSet
case Leaf => true
case Node(left, data, right) => Valid(left) && Valid(right)
&& treeSet != left && treeSet != right
&& (forall elem :: elem in elems(left) ==> elem < data)
&& (forall elem :: elem in elems(right) ==> elem > data)
&& treeSet !in descendants(left)
&& treeSet !in descendants(right)
}
function descendants(treeSet: TreeSet) : set<TreeSet> {
match treeSet {
case Leaf => {}
case Node(left, _, right) => descendants(left) + descendants(right)
}
}
function size(treeSet: TreeSet): nat
requires Valid(treeSet)
ensures |elems(treeSet)| == size(treeSet)
{
match treeSet
case Leaf => 0
case Node(left,_,right) =>
size(left) + 1 + size(right)
}
function elems(treeSet: TreeSet): set<int>
{
match treeSet
case Leaf => {}
case Node(left, data, right) => elems(left) + {data} + elems(right)
}
Dafny is failing to prove the size
function, specifically the ensures |elems(treeSet)| == size(treeSet)
postcondition.
It can infer that the cardinality of the element set is lesser than or equal to the size function, but not that it is equal. I tried to assert both the tree invariant the uniqueness of elements in the Valid
predicate, but it still cannot prove the correctness of the function. Any idea of how I could make this work?