Binary Search Tree-ness
Due: Thursday, February 27, 00:00AM
We implemented binary search trees in class and proved the following theorem:
Axiom search_insert : forall k v t, search k (insert k v t) = Some v.
However, this theorem doesn’t tell us that t truly is a binary search tree. For example, if insert always inserted at the head and search searched the whole tree, the theorem would still be provable.
A key part of the problem is that values of type tree are freely-generated binary trees, and not just binary search tress.
Your task for this assignment is to define a predicate that defines binary search trees:
Axiom BST : tree -> Prop.
And use this predicate to strengthen the type of insert:
Axiom insert : nat -> A -> forall (t : tree), BST t -> {r : tree | BST r}
This is not total correctness for insert (why not?), but a step in that direction.
Hints
-
For the proof, you cannot define
insertdirectly. You need an auxiliary function, sayins, with a stronger return type.To insert into the left-hand side of a node, you need to know that if all keys in
tare less thanjandi < jthen all keys in(ins i v t)are also less thanj.You need to know something similar to insert into the right-hand side. Both these propositions need to added to the proposition in the return type of
ins(use/\). -
Use
refineto define your functions so that you can fill in the proof terms using tactics. -
A simple way to do the proofs is to manually apply
inversionandsubstto some hypotheses. E.g., if you have a hypothesisH: BST (Node lhs k v rhs), you’ll need toinversion Hto revealBST lhsandBST rhs. Once you’ve revealed enough information,intuitioncan tackle the rest. -
Define the auxiliary
insfunction like this:Fixpoint ins (k : nat) (v : A) (t : tree) { struct t } : BST t -> { r:tree | BST r /\ ... }. refine (match t with | Leaf => fun isBST => ... | Node lhs j w rhs => fun isBST => ... end). (* Proof obligations *) ... Defined.Notice that each case of the
matchexpression is a function that takes theBST targument. Section 6.1 of CPDT explains why this is necessary and why the obvious definition doesn’t work.
Binary trees (from class)
For your reference, here is the code we developed in class. You may wish to use the comparison operation and the definition of trees.
Set Implicit Arguments.
Require Import Cpdt.CpdtTactics.
Require Import List Arith Bool.
Section Compare.
Inductive compare (x y : nat) : Set :=
| EQ : x = y -> compare x y
| LT : y > x -> compare x y
| GT : x > y -> compare x y.
Lemma compare_impl :
forall x y, compare x y -> compare (S x) (S y).
intros.
destruct H.
apply EQ. crush.
apply LT. crush.
apply GT. crush.
Qed.
Fixpoint cmp (x y : nat) : compare x y :=
match x, y with
| O, O => EQ (eq_refl O)
| S x', O => GT (lt_O_Sn x')
| O, S y' => LT (lt_O_Sn y')
| S x', S y' => compare_impl (cmp x' y')
end.
End Compare.
Module BinaryTree.
Variable A : Set.
Inductive tree : Set :=
| Leaf : tree
| Node : tree -> nat -> A -> tree -> tree.
Fixpoint insert (k : nat) (v : A) (t : tree) :=
match t with
| Leaf => Node Leaf k v Leaf
| Node lhs k' v' rhs =>
match cmp k k' with
| EQ _ => Node lhs k' v rhs
| LT _ => Node (insert k v lhs) k' v' rhs
| GT _ => Node lhs k' v' (insert k v rhs)
end
end.
Fixpoint search (k : nat) (t : tree) :=
match t with
| Leaf => None
| Node lhs k' v rhs =>
match cmp k k' with
| EQ _ => Some v
| LT _ => search k lhs
| GT _ => search k rhs
end
end.
Theorem search_insert :
forall k v t,
search k (insert k v t) = Some v.
Proof.
induction t.
+ simpl.
destruct (cmp k k); crush.
+ simpl.
destruct (cmp k n).
- crush.
destruct (cmp n n); crush.
- crush.
destruct (cmp k n); crush.
- simpl.
destruct (cmp k n); crush.
Qed.
End BinaryTree.