Counting Binary Combinations Counting Nested Pairs The following question was inspired by a passage on page 6 i SICP where it is pointed out that prefix notation does not leave room for ambiguity. In contrast, infix notation requires either a set of precedence rules or a consistent use of parentheses to ensure unambiguity. The question is: Given a list of n terms and n – 1 operators (t1 o1 t2 … tn-1 on-1 tn) how many unambiguous combinations can we produce solely by the use of parentheses. If we require that an expression such as (a o b p c), where o and p are operators, must have one of the two interpretations (a o (b p c)) and ((a o b) p c), even if o = p, we do not have to consider the operators and can formulate the questions as follows: In how many ways can we combine the elements of a list of numbers by pairing sub expressions, such that each element of a pair is either a number or a pair.? E.g. (a, b) is a pairing of itself, (a, (b c)) and ((a b) , c) are the two nested pairings of (a, b, c), and ((a, b) , (c, d)) is one of the nested pairing of (a, b, c, d)? A combination is a nest of ordered pairs where the innermost pairs contain numbers. Let (L) be the set of combinations of the list L. For every subdivision (X, Y) of L the combinations of X and Y together = (X) × (Y), and the set of combinations of L is the union of the cartesian products of the combinations of all binary sub divisions of L. E.g. (a, b, c, d) has the binary divisions (a, (b, c, d)), ((a, b) , (c, d)) , ((a, b, c) , d). The singletons and the pairs have one combination each and the triples have two: (a) = {(a)}, (a, b) = {(a, b)} and (a, b, c) = {(a, (b, c)), ((a, b) , c)}. This gives the products (a) × (b, c, d,) = {(a, (b, (c, d))), (a, ((b, c) , d))} (a, b) × (c, d) = {((a, b) , (c, d))} (1) (a, b c) × (d) = {(((a, b) , c) , d), ((a, (b, c)) , d)}, and the union of these is {(a, (b, (c, d))), (a, ((b, c) , d)), ((a, b) , (c, d)), (((a, b) , c) , d), ((a, (b, c)) , d)}. (2) Generally, for the list (t1, .., tn), we have (t1) = {(t1)}, (t1, t2) = {(t1 t2)}, (t1, .., tn) = (t1) × (t2, .., tn) .. (t1, .., tn–1) × (tn), for n > 2 (3) Since a combination is a nest of ordered pairs every combinations is distinct, thus |( X) × ( Y)| = |(X)| |(Y)| and we can define the function | N N, (x) = the number of combinations of a list of x elements, as follows: (n) = (1)(n – 1) + .. + (n – 1)(1) = n-1 ∑ (i)·(n−i) , n > 2 (4) i=1 We know that (1) = (2) = 1, and then (3) = 11 + 11 = 2, (4) = 12 + 11 + 21 = 5, etc. (5) Counting Binary Trees Can we reason the same way as above about the problem of finding the number of binary trees with n nodes? The answer is not immediately clear since a binary tree is a combination of triples whereas a parenthetical structure is a combination of pairs. We cannot argue that a binary operation is a triple with the operator in the middle, since the operator does not enter into the computation. A binary tree is either empty or a triple (L, n, R) where n is a node, typically a number, and L and R are binary trees such that every node in L is less than n, and every node in R is greater than n. We can omit the references to empty subtrees without loss of information, thus (, n, R) (n, R), (L, n, ) (L, n) and (, n, ) (n). Let B be the set of binary trees, let | B 2N, (X) = the set of nodes in X, and let | N 2 2B, (x, y) = {X B | (X) = [x, y]}. Then, given the numbers n and k n, the set of binary trees where k is the root = (1, k – 1) (k + 1, n), (6) Since there is one such set for every number from 1 to n we have that (1, 0) = , (1, 1) = {(1)}, and (7) (1, n) = (2, n) (1, 1) (3, n), ..., (1, n – 1) . E.g. (1, 2) = {((1) 2), (1 (2))}, and (8) (1, 3) = {(((1) 2) 3), ((1 (2)) 3), ((1) 2 (3)), (1 ((2) 3)), (1 (2 (3)))}. By a similar argument as the one we applied to the problem of counting nested pairs we can define the function | N N, (x) = the number of binary trees with n nodes, as follows (n) = (0)(n – 1) + .. + (n – 1)g(0) = n-1 ∑ (i)·(n−i) , n > 2 (9) i=1 We know that and then (0) = (1) = 1, (10) (2) = 11 + 11 = 2, (3) = 12 + 11 + 21 = 5, etc. (11) and we see that (x) = (x + 1) for every x > 0, i.e. the number of binary threes with x nodes equals the number of parenthetical combinations of a sequence of x + 1 elements. (12) Implementation To implement we need a function for the sum: (k, n) = n-1 ∑ (i)·(n−i) (13) i=k (n) = (1, n), for n > 2. (n, n) = 0, (i, n) = (i)·(n − i) + (i + 1, n), for 0 < i < n (14) The implementation looks like this: (15) (define (p1 n) (define (s i n) (if (= i n) 0 (+ (* (p1 i) (p1 (- n i))) (s (+ i 1) n)))) (if ( n 2) 1 (s 1 n))) This gives (p1 (n)) 3n. The following iterativ solution gives (p2 (n)) n2. By (3) we can compute (i+1) by means of the list of the results that we already have obtained, ((1), ..., (i)), by taking the sum of the products of the list of results and its reversal. E.g. we compute f(7) and then f(8) from the results list thus: 1 1 2 5 14 42 42 14 5 2 1 1 1 (7) = + + + + + (8) = + 132 = 42 + 14 + 10 + 10 + 14 + 42 = 132 1 2 5 14 42 132 + + + + + 42 14 5 2 1 1 = 132 + 42 + 28 + 25 + 28 + 42 + 132 = 429 (16) The implementation looks like this: (17) (define (p2 n) (define (s i sums) ; sums = (sum1 .. sumi–1). (let ((sum (apply + (map * sums (reverse sums))))) (if (= i n) sum (s (+ i 1) (cons sum sums))))) (if (<= n 2) 1 (s 3 (list 1 1)))) As can be seen from (16) the result list is symmetrical around the middle, making it possible to at least halve1 the number of multiplications, i.e., if we have an even number of sums, we double the sum of the products of the first half, and if we have an odd number of sums, we add the square of the sum in the middle to the double of the sum of the products up to the middle. E.g. (1 42 + 1 14 + 2 5 + 5 2 + 14 1 + 42 1) = 2(1 42 + 1 14 + 2 5) (18) 2 (1 132 + 1 42 + 2 14 + 5 5 + 14 2 + 42 1 + 132 1) = 2(1 132 + 1 42 + 2 14) + 5 . (The implementation is straightforward but somewhat lengthy compared to (17), so I do not show it here.) 1 For some reason this solution reduces the workload by 2/3, not only by 1/2, i.e. (p3 (n)) = (p2 (n))/3. Now, assume that there is a function such that (n) = (n)(n–1). As it turns out, there is such a function, and that function it is linear, thus there must be an implementation p4 of f such that (p4(n)) = n. (14) ((2) / (1), …, (n) / (n – 1)) = 1, 2, 1 2 —, 2 4 2 —, 5 1 3 —, 7 3, 1 3 —, 4 1 3 —, 3 2 3 —, 5 5 3— 11 (15) There is a pattern here that we can make more appearant by multipling the numerators and denominators of some of the fractions: 2 —, 2 = 6 —, 3 10 —, 4 14 —, 5 18 —, 6 22 —, 7 26 —, 8 30 —, 9 34 —, 10 38 — 11 (17) We see that the numerator = 2(2 denominater – 3), thus (n) = 2(2n – 3)/n = (4 – 6/n) (18) (Notice that for large n, (n) 4(n – 1), which means that grows almost exponentially.) The Scheme implementation looks like this: (define (p4) (if (< n 2) 1 (* (- 4 (/ 6 n)) (f (- n 1))))) (19) We can rewrite in terms of the factorial through the following steps. 2(2n – 3) (n – 1) (n) = ———————, n > 1 (1) = 1, (20) n 2(22 – 3) 2(23 – 3) ... 2(2n – 3) 2n–113 ... (2n – 3) 2n–113 ... (2n – 3)24 ... (2n – 4) (n) = 1 ——————————————— = ———————— = ——————————————— 2 3 ... n n! 2 4 ... (2n – 4) n! (22) 2 (2n – 3)! ——————— n!24 ... (2n – 4) n–1 = 2 (2n – 3)! —————— 2n–2 n! (n – 2)! n–1 = 2(2n – 3)! = ———— n!(n – 2)! = 2(n – 1)n(2n – 3)! ———————— = … = n!(n – 2)!(n – 1)n n(2n – 2)! ————— (n!)2 (This of course just a rearrangment of terms that has no bearing on the growth order of an implementation.) (23)