A "partition" is a way of representing a given integer as a sum of zero or more positive integers, e.g. the partitions of 4 are 1+1+1+1, 1+1+2, 2+2, 1+3, and 4. This recipe uses simple generators recursively to produce a stream of all partitions of its argument. Each partition is represented as a sorted list of the numbers to be summed, e.g. [1,1,1,1], [1,1,2], [2,2], [1,3], [4].
1 2 3 4 5 6 7 8 9 10 11 | def partitions(n):
# base case of recursion: zero is the sum of the empty list
if n == 0:
yield []
return
# modify partitions of n-1 to form partitions of n
for p in partitions(n-1):
yield [1] + p
if p and (len(p) < 2 or p[1] > p[0]):
yield [p[0] + 1] + p[1:]
|
Partitions, like permutations and combinations, form one of the basic primitives for generating many other kinds of combinatorial object.
One issue with this method is that each item in the output stream is created as a new list object, so the amount of time per step can be linear in n. It would be possible to modify this method so that it reuses the same list for each yielded result, in constant amortized time per step, by using reverse-sorted order for each partition and using push-pop operations, but reusing the same list object could lead to confusion. Additionally, I think the speedup of such a modification would be limited to such large values of n that it wouldn't make sense to try to list all partitions of those numbers.
Explanation. Maybe I should explain in a little more detail how this works. If you have a partition of n, you can reduce it to a partition of n-1 in a canonical way by subtracting one from the smallest item in the partition. E.g. 1+2+3 => 2+3, 2+4 => 1+4. This algorithm reverses the process: for each partition p of n-1, it finds the partitions of n that would be reduced to p by this process. Therefore, each partition of n is output exactly once, at the step when the partition of n-1 to which it reduces is considered.
Upper bound. The number of partitions grows quickly.
Two variations. This recipe is really interesting.
I made two variations on this recipe.
tuple version
Each partition is represented as a tuple instead of a list.
This version runs faster than a list equivalent.
reverse order
Each partition is represented in descending order.
For example:
Slightly simpler example which generates the sequence from high to low.
This code works just like the given code, but does not create the list from smallest to largest, but rather the other way around. It doesn't need complicated fiddling, and could be sped up considerably by creating a cache for all parts yielded for each num,lt.
Or if you do need speed ... Sometimes I do need speed, and then a multiset representation allows several efficiences, such as O(1) time per iteration (not just amortized O(1)), and compactness (the largest data structure constructed takes O(sqrt(N)) space; the important part of that is there's so much less the partition _consumer_ needs to examine each time -- something to remember next time you find your code endlessly crawling over long strings of ones):
list of tuples. This is the same approach as in my recipe 221132.
See also http://www.cs.sunysb.edu/~algorith/files/generating-partitions.shtml
Here is a modification of Tim's routine that limits the number of partitions to value <= k:
It returns elements going high to low and doesn't create new lists. It runs twice as fast on my computer.
Or if you need more speed and actually don't mind crawling over ones...
Hi, this is an interesting topic. I have a question: is it possible to have an alghorithm that creates the specific partition combination giving only n and the number of the specific combination ?
Example: the partitions of 4 are:
If I need only the combination number 3, ( 2+1+1 ) how can I create it without generating all the partitions ? There is a mathematic formula for this ?