We’re calling our sig tree
, but we don’t enforce that it actually is a tree, and then we check that later in our isBTree
predicate. It would have been better to name the sig NodeSet
or something. This is a small design point, but our models are getting larger, so design is becoming more important.
Now we are going to expand our model to support adding nodes.
There are two cases: either the tree was empty to start, or it wasn’t.
If there is no root in the tree to start (ie. the tree was empty):
Add the node to the post
tree
Otherwise, finding
is the Descent
down the pre
tree searching for the val
that you are trying to add.
If finding
ends with the value you are trying to add (ie. it was already in the tree), the post
tree is the same as the pre
tree.
Otherwise, add the node to the post
tree.
See the Alloy file for the exact details of the add
event
Why would we want to allow add
to take a binary search tree and produce something that is not a binary search tree?
You can then use Alloy to see if there is a way that would ever be possible. This allows you to confirm that your algorithm preserves binary search trees correctly.
Why did we talk about induction last class?
What is the relation between preservation and induction?
Answer: We can show that the empty tree is a BST, and each AddNode
action takes a BST and produces another BST, and so on and so on. Then, we can prove that AddNode
preserves binary search trees
Aren’t we only proving it up to some bound?
Yes! But usually bugs in algorithms have small counterexamples. So Alloy is quite helpful even though we can’t prove preservation for all trees
What are we inducting over?
Last class, we did induction over the natural numbers. There was a clear growth of the natural numbers (plus one, plus one, …). It’s not immediately clear how to create this sort of ordering over binary trees. But, what we are actually going to do induction over is the number of AddNode actions (which is the natural numbers!).
Now we want to formalize this idea of preservation in Alloy. What is the relationship between the pre
and the post
tree?
This is a basic template for preservation: Basically, you want to say that if the predicate holds for the pre
state, that implies that the predicate is true for the post
state.
assert addpreserves {
all a: AddNode {
isBSTree[a.pre] implies isBSTree[a.post]
}
}
Oh no! We find a counterexample! We will investigate what happened, and fix it for the file that is posted.