of Volume 25 the ACM Number 8 1. Introduction Algorithm 1. Recursive generation of combinations with minimal change property.
A combination is a k-subset of an n-set. A combina- procedure ALGOR1 ( i : integer);
tion generation has the minimal change property if every v a r j : integer; combination, except the first, is obtained from the pre- begin vious combination by replacing only one element. As if i rood 2 = 0 introduced by Ehrlich [2, 3], a combination algorithm is then loopless if the maximum number of operations required for j := i to a[i+ 1] - 1 do to generate each combination, except the first one, is a begin a[i] : = j ; A L G O R I ( i - 1 ) end constant independent of n and k. We assume throughout else this paper that the underlying n-set is {1, 2 . . . . . n} and f o r j := a[i+l] - 1 downto i do that n_> k > 0. begin a[i] : = j ; Our work is motivated by the algorithm of Bitner i f / = 1 then PROCESS else ALGOR1 ( i - 1 ) et al. [1], which was the most efficient and simplest end method published in the generation of combinations end; (* A L G O R I *) with the minimal change and loopless properties. The After assigning the value n + 1 to a[k + 1], the initial description of this algorithm is repeated in [5], which call to generate all the combinations is A L G O R I (k). also contains a summary of other combination algori- It is a simple exercise to prove that Algorithm 1 thms published. Bitner's algorithm is based on the binary generates all the different k-subsets of the n-set {1, reflected Gray code and uses a special implementation 2 . . . . . n}. We shall now prove that it has the minimal of a stack in order to achieve the loopless property. change property. First of all, we give the following Interestingly, we can show that our algorithms generate definitions. combinations in the same order as Bitner's if k is even Let a[l .. k] be a combination with a[k + l] = n + and in the reverse order if k is odd. However, our 1. For l __ i <_ k, we define Algorithm 1 is based on making a minor change to the i if i is even, usual recursive method that generates combinations in start(/)= a[i+ 1 ] - 1 if iisodd, reverse lexicographical order. This change destroys the ordering and the generated combinations then have the = (a[i + l] - 1 if i is even, minimal change property. The second algorithm uses stop (i) if i is odd. only a standard stack to eliminate recursion and to The element a[i] is said to be moveable if a[i] ~ stop (i). achieve the loopless property. The final algorithm is an The idea o f moveability is intimately related to the optimized version of the second one, obtained by treating execution of Algorithm 1. After returning from the pro- separately some frequently occurring cases and by im- cedure PROCESS, the next combination is generated by plementing a special stack as in Bitner's algorithm. In backing up the recursion stack until an i is found such our test runs, our Algorithm 3 is 9 times faster than that a[i] is moveable. The element a[/] is changed and Bitner's algorithm when n = 24, k = 6. A L G O R 1 is then called recursively until i = 1. The next All the algorithms were coded in Pascal and tested combination is then available. We now show that this extensively on a CDC Cyber 172/2. The programs are new combination differs from the previous one by re- available from the authors. placing one element.
THEOREM 2.1. Algorithm 1 has the minimal change prop-
erty. 2. The Three Algorithms PROOF. Let a l l . . k ] be a given combination. If none of In this paper, the algorithms are presented in Pascal. the a[i]'s is moveable, the algorithm terminates. Other- A k-subset is represented by a global array a [ 1 . . k] of wise, let a[i] be the moveable element with the smallest integers. The d u m m y element a[k + 1] is often used to index. In other words, a[j] = stop(j) for all j < i and store the value n + 1. Every time a combination is a[i] ~ stop(i). It is clear that the next combination is generated, the procedure PROCESS is called to process obtained without changing any a[j] where j > i. The that combination. element a[i] is either increased by l or decreased by 1 It is clear that all the k-subsets can be generated in depending on the parity of i. The remaining elements reverse lexicographical order by k nested loops. These a[j], j < i, are assigned the value start ( j ) in decreasing nested loops can be reduced to a single loop by using order o f j . Table I summarizes the differences between recursion. Algorithm 1 is obtained by insisting that the the old and the new combinations. loop which controls the generation of the element a[i] If i > l, then the new combination differs from the shall depend on the parity of the index variable i. This old one either by replacing i - l by x + 1 or by replacing algorithm will have the minimal change property. x by i - l, depending on the parity of i. If i = 1 then x
556 Communications August 1982
of Volume 25 the ACM Number 8 Table 1. The Effect of Generating a N e w C o m b i n a t i o n W h e n a[i] is begin POP (i); the Moveable Element with the Smallest Index. ifimod2=Othen i even i odd begin a [ i - l ] := a[i]; a[i] := a[O + 1; if a[0 < a [ i + l ] - 1 then PUSH (i); old new old new P U S H ( i - 1); a[i] x x + 1 x x- 1 if i > 2 then P U S H (i-2) a[i--l] i-- 1 x x- 1 i- 1 end else a[i-- 2] i-- 2 i-- 2 i-- 2 i-- 2 begin if i > 1 t h e n a [ i - l ] : = i - 1; a[q := a[/'] - 1; a[l] 1 1 1 1 if a[i] > i then begin PUSH (i); i f / > 1 then PUSH (i-1) is replaced by x - 1. Hence, the algorithm has the end minimal change property. [] end; PROCESS The preceding proof describes the necessary changes end (* main loop *) to go from one combination to the next, provided that the moveable element with the smallest index is known. The efficiency of Algorithm 2 depends on how effi- The standard method to eliminate the recursion in Al- ciently the stack operations can be implemented. Using gorithm 1 would be to push the index i of each recursive the method of counting operations, as in [4], Algorithm call, in decreasing order, onto a stack. However, in 2 is comparable in efficiency to Bitner's algorithm. Algorithm 2, we only push the indices of the moveable Algorithm 3 is derived from Algorithm 2 by making a[i]'s. Thus, the top element of the stack contains the changes that improve the efficiency. The major change smallest index i such that a[i] is moveable. In general, is to treat i = 1 and i = 2 as special cases. We shall prove Algorithm 2 proceeds as follows. After an i is popped in the next theorem that these two cases occur frequently. from the stack, a[i] and, if necessary, a[i - 1] are We define a(i) as the number of times i is popped changed. These operations may cause a[i - 1] and from the stack in Algorithm 2. Let C(r, s) be the number a[i - 2] to be moveable. The indices of the moveable of combinations or r things taken s at a time, and let C(r,s) = 0ifr<s. elements among a[i], a[i - 1], and a[i - 2] are then pushed onto the stack in decreasing order. At this point, THEOREM 2.2 a ( i ) = C(n - i, k - i + 1). the new combination has been generated and the stack has been updated. We now have a nonrecursive algo- PROOF. If i is odd, then o~(i) is equal to the number of rithm with the minimal change and loopless properties. ways of choosing a[i] < . . . < a [ k ] from the set {i + In the description of Algorithm 2, we assume the l . . . . . n}. Hence a(i) is given by Theorem 2.2. If i is existence of the standard stack operations PUSH (i), even, then a(i) is equal to the number of ways of choosing POP (i), and the Boolean function STACKEMPTY, a[i] < . . . < a [ k ] from the set {i, . . . . n} with the extra which returns the value of true if the stack is empty. The condition that a[i] ~ a[i + 1]-1. As usual, we assume procedure C L E A R S T A C K empties the stack. a[ k + 1] = n + 1. Each of these choices can be generated by choosing a[i] < . . . < a [ k ] from {i + 1. . . . . n} and Algorithm 2. Nonrecursive generation of combinations then subtracting 1 from a[i]. Hence Theorem 2.2 is also with minimal change and loopless properties. correct when i is even. [] (* initialization *) CLEARSTACK; Every time an i is popped from the stack, a new if k mod 2 = 0 then combination is generated. We define P(i) as the proba- begin a [ k + l ] := n + 1; a[k] := k; bility that a combination is generated by popping i from if k < n then P U S H (k) the stack. end else Thus begin a[k] := n; 1'(i) = a ( i ) / C(n, k) if k < n then begin PUSH (k); By simple algebraic manipulations, one can show that i l k > 1 then P U S H ( k - l ) P(1) = 1 - k / n , end P(2) = (1 - k / n ) [ k / ( n - 1)], and end; P(I) + e(2) = 1 - k ( k - l ) / [ n ( n - 1)] (1) fori:= 1 tok- 1 doa[i]:=i; PROCESS; (* first combination *) Equation (1) implies that the probability of popping (* main loop to generate all other combinations *) an i > 2 from the stack is approximately ( k / n ) 2. If k is while not S T A C K E M P T Y do small compared to n, then this is a rare event. This
557 Communications August 1982
of Volume 25 the A C M Number 8 observation suggests that one should optimize the han- begin t[top-1] := t[top]; t[top] := top + 1 dling of the two cases, i = 1 and i = 2. In Algorithm 3, end; whenever a 2 is popped from the stack, all the combi- top := top - 2 nations obtainable by changing only a[1] and a[2] are end else generated in two nested loops. A side effect of this begin a[top] := a[top] - 1; optimization step is that the portion of the algorithm if a[top] > top then handling the cases where i > 2, does not have to test the begin top := top - 1; a[top] := top condition i > 2 nor the condition i > 1. Hence, this end else segment of the algorithm becomes simpler. One should begin a [ t o p - 1 ] := top - 1; i := top; note also that 2 is now the smallest i that can be pushed top := t[top]; t[i] := i + 1 onto the stack. However, we must now treat k = 1 as a end special case. end; The next improvement is to make the stack opera- PROCESS tions more efficient. On the C D C Cyber 172/2, stack end operations are not basic instructions. We found through The remaining case k = 1, can be handled easily with a timing tests that it is most efficient to implement the single loop and the code for it is not shown. stack in a manner similar to Bitner et al. [1]. The vector t[2.. k] is used to implement the stack. The convention is that if i is in the stack, then t[i] gives the next element 3. Concluding Remarks down in the stack. I f i is not in the stack, then t[i] is i + 1. The variable top contains the top element of the stack. We shall give some empirical and theoretical com- The bottom of the stack is denoted by 0. To avoid parisons between Bitner's algorithm and Algorithm 3. popping and then pushing the same element, the element Algorithm 3 was coded with the remainder tests mod 2 top is popped from the stack only if a[top] = stop(top). replaced by indexing into a precomputed Boolean array. The pushing of one or more successive elements onto the Bitner's algorithm was coded in Pascal. After verifying stack is performed by one assignment statement. its correctness, we did timing comparisons. Some sample Algorithm 3. Optimized version of Algorithm 2 for results are shown in Table II. The unit of time is a k>l. second. The timing statistics do not include the time spent in calling the procedure PROCESS. In the table, top := 0; (* clear the stack *) the notation T+ corresponds to the Pascal compiler's if k rood 2 = 0 then option that includes runtime tests and T - corresponds begin a [ k + l ] := n + 1; a[k] := k; to no runtime tests. Also, timing can fluctuate by as i l k < n then top := k m u c h as l0 percent on our C D C Cyber 172/2 computer. end else As used by Ives in [4], we can also compare the two begin a[k] := n; algorithms by counting the n u m b e r of operations per- ifk<nthentop:=k- 1 formed. A representative operation is the assignment end; operation. To generate the next combination, Bitner's a[1] := l; algorithm needs a m i n i m u m of 7 and a m a x i m u m of 9 t[k] := O; assignment operations. W h e n top > 2, Algorithm 3 needs for i : = 2 t o k - ldo either 3 or 5 assignment operations to generate the next begin a[i] := i; t[i] := i + 1 end; combination. The latter case occurs if the element top is PROCESS; (* first combination *) to be deleted from the stack. When top = 2, Algorithm (* main loop to generate all other combinations *) 3 takes 4 assignment operations to generate the first while top < > 0 do combination, and each of the remaining combinations if top = 2 then generated in the two nested repeat loops requires either begin (* special handling for a[2] and a[1] *) l or 2 assignment operations. The counts for all the other top := t[2]; t[2] := 3; types of operations can be obtained in a similar manner. repeat We now make two final observations. First of all, the a[1] := a[2]; a[2] := a[2] + 1; analysis of Algorithm 3 depends on how often a[top] = PROCESS; repeat a[1] := a[l] - 1; Table II. Timing Comparison of Algorithm 3 and Bitner's Algorithm PROCESS with Time in Seconds. until a[l] = 1 until a[2] = a[3] - 1 Algorithm 3 Bitner's Algorithm end else n k T+ T- T+ T- begin if top mod 2 = 0 then 24 6 1.6 1.4 13.9 9.3 22 11 16.2 11.8 66.1 44.1 begin a [ t o p - 1 ] := a[top]; a[top] := a[top] + 1; 24 18 5.9 3.6 13.2 8.8 if a[top] = a[top+ 1] - 1 then
558 Communications August 1982
of Volume 25 the ACM Number 8 stop(top). In such a situation, the element top has to be Programming Techniques M. Douglas Mcllroy* deleted from the stack and more operations are required and Data Structures Editor to generate the next combination. When k > top > 2, one can show that the probability for a specific value of The Solution for the top that a[top] = stop(top) is a(top + l)/a(top), which Branching Factor of the reduces to (k - top + l ) / ( n - top). Hence, when k is small compared to n, it is very unlikely that the next Alpha-Beta Pruning combination is generated by using the theoretical maxi- Algorithm and its Optimality m u m n u m b e r of operations. I f k is very small compared to n, then P(I), the Judea Pearl probability that a combination is generated by changing University of California, Los Angeles only a[1], is approximately 1. In this case, almost all the combinations are generated by the single statement a[1] := a[1] - 1. It is doubtful that any combination algorithm This paper analyzes N,.d, the average number of would require less work than this to generate a combi- terminal nodes examined by the a - f l pruning algorithm nation. in a uniform game tree of degree n and depth d for which the terminal values are drawn at random from a contin- Received 8/79; revised 10/81; accepted 11/81 uous distribution. It is shown that increasing the search References depth by one extra step would increase N,~d by a factor 1. Bitner, J.R., Ehrlich, G., and Reingold, E.M. Efficient generation (called the branching factor) ~t~_,(n) = ~,/1 - ~n ~ n 3/4 of the binary reflected Gray code and its applications. Comm. ,4 CM, where ~,~ is the positive root of x" + x - 1 = 0. This 19, 9 (Sept. 1976), 517-521. 2. Ehrlich, G. Algorithm 466, Four combinatorial algorithms. implies that for a given search time allotment, the a - f l Comm. ACM, 16, II (Nov. 1973), 690-691. pruning allows the search depth to be increased by a 3. Ehrlich, G. Loopless algorithms for generating permutations, combinations and other combinatorial configurations. J. ,4 CM, 20, factor = 4/3 over that of an exhaustive minimax search. (1973), 500-513. Moreover, since the quantity (~n/1 - ~,~)d has been 4. Ives, F.M. Permutation enumeration: Four new permutation identified as an absolute lower bound for the average algorithms. Comm. ACM, 19, 2 (Feb. 1976), 68-72. complexity of all game searching algorithms, the equality 5. Reingold, E.M., Nievergelt, J., and Deo, N. Combinatorial Algorithms: Theory and Practice. Prentice-Hall, New Jersey, 1977. ;JC~_~(n) = ~,,/1 - ~n now renders a-fl asymptotically optimal C R Categories and Subject Descriptors: 1.2.8 [Artifi- cial Intelligence]: Problem Solving, Control Methods and Search--graph and tree search strategies, heuristic methods; F.2.2 [Analysis of Algorithms and Problem Complexity]: Nonnumerical Algorithms and P r o b l e m s - - complexity of proof procedures, sorting and searching; G.2.2 [Discrete Mathematics]: G r a p h Theory--graph algorithms, trees General Term: Algorithms Additional Key Words and Phrases: alpha-beta search, game searching, games, minimax algorithms, branch and bound search, average case analysis
This work was supported in part by the National Science Foun-