2
## yacinechaouche@yahoo.com
3
## http://ychaouche.wikispot.org
7
This file contains the combo function : a generator that takes numbers
8
as parameter (any number of numbers), and generates every possible combination
9
of simple algebric expressions with these numbers.
11
For example combo([2,4,9]) -> : (108 combinations)
13
(2+(4-9)) (2+(4+9)) (2+(4*9)) (2+(4/9)) (2+(9/4)) (2+(9-4)) (4+(9+2)) (4+(9-2)) (4+(9*2))
14
(2-(4-9)) (2-(4+9)) (2-(4*9)) (2-(4/9)) (2-(9/4)) (2-(9-4)) (4-(9+2)) (4-(9-2)) (4-(9*2))
15
(2*(4-9)) (2*(4+9)) (2*(4*9)) (2*(4/9)) (2*(9/4)) (2*(9-4)) (4*(9+2)) (4*(9-2)) (4*(9*2))
16
(2/(4-9)) (2/(4+9)) (2/(4*9)) (2/(4/9)) (2/(9/4)) (2/(9-4)) (4/(9+2)) (4/(9-2)) (4/(9*2))
17
((4-9)/2) ((4+9)/2) ((4*9)/2) ((4/9)/2) ((9/4)/2) ((9-4)/2) ((9+2)/4) ((9-2)/4) ((9*2)/4)
18
((4-9)-2) ((4+9)-2) ((4*9)-2) ((4/9)-2) ((9/4)-2) ((9-4)-2) ((9+2)-4) ((9-2)-4) ((9*2)-4)
20
(4+(9/2)) (4+(2/9)) (4+(2-9)) (9+(2+4)) (9+(2-4)) (9+(2*4)) (9+(2/4)) (9+(4/2)) (9+(4-2))
21
(4-(9/2)) (4-(2/9)) (4-(2-9)) (9-(2+4)) (9-(2-4)) (9-(2*4)) (9-(2/4)) (9-(4/2)) (9-(4-2))
22
(4*(9/2)) (4*(2/9)) (4*(2-9)) (9*(2+4)) (9*(2-4)) (9*(2*4)) (9*(2/4)) (9*(4/2)) (9*(4-2))
23
(4/(9/2)) (4/(2/9)) (4/(2-9)) (9/(2+4)) (9/(2-4)) (9/(2*4)) (9/(2/4)) (9/(4/2)) (9/(4-2))
24
((9/2)/4) ((2/9)/4) ((2-9)/4) ((2+4)/9) ((2-4)/9) ((2*4)/9) ((2/4)/9) ((4/2)/9) ((4-2)/9)
25
((9/2)-4) ((2/9)-4) ((2-9)-4) ((2+4)-9) ((2-4)-9) ((2*4)-9) ((2/4)-9) ((4/2)-9) ((4-2)-9)
27
The abelian operations are not doubled, this means that for the + and for the *
28
operations, only a+b and a*b are generated (b*a and b+a are considered duplicates).
29
This is not true however for non abelian operations like - and / .
31
You can verify that all these combinations are unique, if that sounds amusing to you.
32
Some of them may have the same value, but they're not obtained the same way, so they're
33
not considered the same. This may seem more obvious to you in large combinations (6 to 9 numbers)
34
where one problem may have tens of solutions.
41
S is a Serie of numbers (okay, it's just a list...). But for the purposes of our function,
42
it's treated like a Stack (hence the S).
44
If S contains just two numbers, for example 9 and 8, then combo will generate all possible
45
algebric operations with these two numbers, with the help of the _combo function (notice the
46
leading underscore). So for example combo([9,8]) is a list of six items, returned
47
by the helper funciton _combo(9,8) :
56
If S has more than just two numbers, for example :
60
then take the first number (4) out of the stack...
64
...and combine it with every combination c of the remaining numbers, which are obtained by simply
65
calling combo recursively on the Stack. These recursive calls will end when there are just
66
two numbers remaining in the stack, because in each call to Combo, one number is removed as we
69
So for example (recursive calls) :
71
-> combo([4,5,8,9,12]) is _combo(4,X) for every X in combo([5,8,9,12]) #removes 4 from the stack
72
-> combo([5,8,9,12]) is _combo(5,Y) for every Y in combo([8,9,12]) #removes 5 from the stack
73
-> combo([8,9,12]) is _combo(8,Z) for every Z in combo([9,12]) #removes 8 from the stack
74
-> combo([9,12]) -> _combo(9,12) (all 6 algebric operations).
75
-> the recursion ends here, return all the combinations of 9 and 12
76
-> return all the combinations of [8,9,12]
77
-> return all the combinations [5,8,9,12]
78
-> combine 4 with every combination of [5,8,9,12]
80
Let's take an example with just three numbers : 4,5, and 8.
81
We decide to execute combo([4,5,8])
83
We remove 4 from the stack, and combine it with every combinations of the remaining numbers
86
combo([4,5,8]) is _combo(4,c) for every c in combo([5,8]).
88
combo([5,8]) : the stack has only two numbers, so its combinations are simply _combo(5,8),
89
a list of 6 combos : (5+8),(5-8),(5*8),(5/8),(8-5),(8/5).
90
(remember that (8*5) and (8+5) are the same as (5*8) and (5+8) so they're not generated.)
92
What we'll do is take every one of these combinations, let's call them c, and make
93
a combination out of 4, the number we took from S earlier, and c. That's what the line
95
_combo(4,c) for every c in combo([5,8])
99
_combo(4,c) has also six possibilities (4+c, 4-c, 4*c, 4/c, c-4,c/4), so for each
100
value of c we have 6 possible combinations with 4, and there are 6 values of c,
101
so the total possibilities of _combo(4,c) is 6 * 6 = 36 possible combos :
103
(4+(5+8)) (4+(5-8)) (4+(5*8)) (4+(5/8)) (4+(8/5)) (4+(8-5))
104
(4-(5+8)) (4-(5-8)) (4-(5*8)) (4-(5/8)) (4-(8/5)) (4-(8-5))
105
(4*(5+8)) (4*(5-8)) (4*(5*8)) (4*(5/8)) (4*(8/5)) (4*(8-5))
106
(4/(5+8)) (4/(5-8)) (4/(5*8)) (4/(5/8)) (4/(8/5)) (4/(8-5))
107
((5+8)/4) ((5-8)/4) ((5*8)/4) ((5/8)/4) ((8/5)/4) ((8-5)/4)
108
((5+8)-4) ((5-8)-4) ((5*8)-4) ((5/8)-4) ((8/5)-4) ((8-5)-4)
110
Notice how 4 is always in one side of the operation and (8,5) is on the other side ?
111
There are still many combinations left where 4 is "in the middle" of the expression,
112
not just on its sides. And so does for 5 and 8.
114
We can simply acheive this by putting 4 back in the stack...
122
and make every combinations of 5 with every combinations of 4 and 8. We get this :
124
(5+(8+4)) (5+(8-4)) (5+(8*4)) (5+(8/4)) (5+(4/8)) (5+(4-8))
125
(5-(8+4)) (5-(8-4)) (5-(8*4)) (5-(8/4)) (5-(4/8)) (5-(4-8))
126
(5*(8+4)) (5*(8-4)) (5*(8*4)) (5*(8/4)) (5*(4/8)) (5*(4-8))
127
(5/(8+4)) (5/(8-4)) (5/(8*4)) (5/(8/4)) (5/(4/8)) (5/(4-8))
128
((8+4)/5) ((8-4)/5) ((8*4)/5) ((8/4)/5) ((4/8)/5) ((4-8)/5)
129
((8+4)-5) ((8-4)-5) ((8*4)-5) ((8/4)-5) ((4/8)-5) ((4-8)-5)
131
Now we put back five in the stack...
139
Then generate all combinations of 8 with all combinations of 4 and 5.
141
(8+(4+5)) (8+(4-5)) (8+(4*5)) (8+(4/5)) (8+(5/4)) (8+(5-4))
142
(8-(4+5)) (8-(4-5)) (8-(4*5)) (8-(4/5)) (8-(5/4)) (8-(5-4))
143
(8*(4+5)) (8*(4-5)) (8*(4*5)) (8*(4/5)) (8*(5/4)) (8*(5-4))
144
(8/(4+5)) (8/(4-5)) (8/(4*5)) (8/(4/5)) (8/(5/4)) (8/(5-4))
145
((4+5)/8) ((4-5)/8) ((4*5)/8) ((4/5)/8) ((5/4)/8) ((5-4)/8)
146
((4+5)-8) ((4-5)-8) ((4*5)-8) ((4/5)-8) ((5/4)-8) ((5-4)-8)
148
Done ! you have cycled through all elements of your stack, and so you have all
149
108 possible combinations of 4,5 and 8 taken in any possible order. If all the
150
numbers are different, all the combinations are unique.
152
Let's analyze this algorithme and see if we're going to explode the memory for
153
high numbers of stack size. Here's how our algorithme looks like
155
combo([4,5,8,12,9]) is : _combo(4,X) for every X in combo([5,8,12,9])
157
_combo(5,Y) for every Y in combo([4,8,12,9])
159
_combo(8,Z) for every Z in combo([4,5,12,9])
161
_combo(12,W) for every W in combo([4,5,8,9])
163
_combo(9,V) for every V in combo([4,8,5,12])
165
You can figure out from this demonstration that the total number of combinations
166
for a stack of n numbers, for n > 2 is :
173
(Is this is a geometrical serie ?)
175
Now you'll understand why we don't put the results in a list before returning them :
176
For 3 numbers, the number of possibilities is 108.
177
For 4 numbers, 2.592.
180
7 -> 117.573.120. That's a lot of memory :
182
Each character is one byte and for 7 numbers you may have expressions like (5+(3*(8+2))/((4-2)*6)
183
which are 22 characters long.
185
22 characters are 22 bytes, which multiplies 117.573.120 is 2,586,608,640.
186
That's approximatively 2.5 Gb of RAM, and that's why I got a memory error when I tried the
187
list version of combo. So I rewrote it in a generative way (combo is a generator).
189
The code to do this is 11 lines :
192
if len(S) == 2: # If there's only two numbers remaining in the stack
193
for c in _combo(S[0],S[1]):
201
# don't throw away the yields ! use the generator
204
for c in _combo(e,es):
210
a and b mustn't be lists
220
#L.append( b+"+"+a) # addition and multiplication are abelian,
221
#L.append( b+"*"+a) # no need to repeat them
226
from number_pprint import number_pprint
232
print number_pprint(i),"possibilities for",len(L),"numbers"
234
if __name__ == "__main__":