3 Generate all binary trees of size n.
5 Given n, the program return an array a of size n+1 such that
6 a[i] contains the list of all binary trees of size i.
8 TODO: tail-recursive version of combine
11 module GenerateAllTrees
21 type tree = Empty | Node tree tree
23 function size (t: tree) : int = match t with
25 | Node l r -> 1 + size l + size r
28 lemma size_nonneg: forall t: tree. size t >= 0
31 forall t: tree. size t > 0 ->
32 exists l r: tree. t = Node l r /\ size l < size t
34 predicate all_trees (n: int) (l: list tree) =
36 forall t: tree. size t = n <-> mem t l
38 lemma all_trees_0: all_trees 0 (Cons Empty Nil)
41 forall l1 l2: tree. size l1 <> size l2 ->
42 forall r1 r2: tree. Node l1 r1 <> Node l2 r2
44 (* combines two lists of trees l1 and l2 into the list of trees
45 with a left sub-tree from l1 and a right sub-tree from l2 *)
46 let combine (i1: int) (l1: list tree) (i2: int) (l2: list tree)
47 requires { 0 <= i1 /\ all_trees i1 l1 /\ 0 <= i2 /\ all_trees i2 l2 }
48 ensures { distinct result }
49 ensures { forall t:tree. mem t result <->
50 (exists l r: tree. t = Node l r /\ size l = i1 /\ size r = i2) }
51 = let rec loop1 (l1: list tree) : list tree variant { l1 }
52 requires { distinct l1 }
53 ensures { distinct result }
54 ensures { forall t:tree. mem t result <->
55 (exists l r: tree. t = Node l r /\ mem l l1 /\ mem r l2) }
59 let rec loop2 (l2: list tree) : list tree variant { l2 }
60 requires { distinct l2 }
61 ensures { distinct result }
62 ensures { forall t:tree. mem t result <->
63 (exists r: tree. t = Node t1 r /\ mem r l2) }
66 | Cons t2 l2 -> Cons (Node t1 t2) (loop2 l2)
74 let all_trees (n: int)
76 ensures { forall i: int. 0 <= i <= n -> all_trees i result[i] }
77 = let a = make (n+1) Nil in
78 a[0] <- Cons Empty Nil;
80 invariant { forall k: int. 0 <= k < i -> all_trees k a[k] }
83 invariant { forall k: int. 0 <= k < i -> all_trees k a[k] }
84 invariant { distinct a[i] }
85 invariant { forall t: tree. mem t a[i] <->
86 (exists l r: tree. t = Node l r /\ size t = i /\ size l < j) }
87 a[i] <- (combine j a[j] (i-1-j) a[i-1-j]) ++ a[i]