snippets / combinatorics

All snippets tagged combinatorics (1)

  1. Generate all partitions of an integer

    Iterative algorithms to generate all partitions of a given integer. Only tested with Python 2.5

      1 import itertools
    2
    3 class FixedLengthPartitionIterator:
    4 """Iterate over partitions of integer `N` into *exactly* `K`
    5 positive integers.
    6
    7 Each returned partition is a list of positive integers in
    8 descending order, such that their sum is `N`.
    9
    10 Arguments `min_` and `max_` bound the values in each partition.
    11
    12 Examples::
    13 >>> list(FixedLengthPartitionIterator(3,1))
    14 [(3,)]
    15 >>> list(FixedLengthPartitionIterator(3,2))
    16 [(2, 1)]
    17 >>> list(FixedLengthPartitionIterator(3,3))
    18 [(1, 1, 1)]
    19 >>> list(FixedLengthPartitionIterator(6,2))
    20 [(5, 1), (4, 2), (3, 3)]
    21 >>> list(FixedLengthPartitionIterator(8,3))
    22 [(6, 1, 1), (5, 2, 1), (4, 3, 1), (4, 2, 2), (3, 3, 2)]
    23 >>> list(FixedLengthPartitionIterator(8,4,2))
    24 [(2, 2, 2, 2)]
    25 >>> list(FixedLengthPartitionIterator(8,3,2))
    26 [(4, 2, 2), (3, 3, 2)]
    27 >>> list(FixedLengthPartitionIterator(8,3,2,3))
    28 [(3, 3, 2)]
    29 """
    30 def __init__(self, N, K, min_=1, max_=None):
    31 # `max_` really defaults to N
    32 if max_ is None:
    33 max_ = N
    34
    35 # rule out trivial cases
    36 if (K*min_ > N) or (K*max_ < N):
    37 self.done = True
    38 return
    39
    40 self._N = N #: integer to be partitioned
    41 self._K = K #: maximum number of nonzero parts
    42 self._k = 0 #: current number of nonzero parts
    43 self._min = min_ #: minimum value of each part
    44 self._max = max_ #: maximum value of each part
    45 self._p = [0] * K #: current partition
    46 self.done = False #: when `True`, enumeration is over
    47
    48 def __iter__(self):
    49 return self
    50
    51 def next(self):
    52 if self.done:
    53 raise StopIteration
    54 if self._N == self._K * self._min:
    55 self.done = True
    56 return tuple([self._min]*self._K)
    57 else:
    58 while self._k <= self._K:
    59 i = self._k - 1
    60 while i > 0:
    61 if (self._p[i]+1 <= self._p[i-1]-1) \
    62 and (self._p[i-1]-1 >= self._min) \
    63 and (self._p[i]+1 <= self._max):
    64 self._p[i-1] -= 1
    65 self._p[i] += 1
    66 return tuple(self._p)
    67 else:
    68 i -= 1
    69 # only change the first `k` parts
    70 self._k += 1
    71 head = (self._N - self._k - self._min*self._K + self._min + 1)
    72 if (head < self._min+1) or (head > self._max) \
    73 or (self._k > self._K):
    74 continue
    75 # advance to next partition:
    76 # [N-2*(k-1)-(K-k), 2, ..., 2, (k-1 times) 1, ..., 1 (K-k times)]
    77 self._p = [head] \
    78 + ([self._min + 1] * (self._k - 1)) \
    79 + ([self._min] * (self._K - self._k))
    80 return tuple(self._p)
    81 raise StopIteration
    82
    83
    84 def PartitionIterator(N, K, min_=1, max_=None):
    85 """Iterate over partitions of integer `N` into *at most* `K`
    86 positive integers.
    87
    88 Each returned partition is a list of positive integers in
    89 descending order, such that their sum is `N`.
    90
    91 Optional arguments `min_` and `max_` bound the values in each
    92 partition.
    93
    94 Examples::
    95 >>> list(PartitionIterator(2,1))
    96 [(2,)]
    97 >>> list(PartitionIterator(3,3))
    98 [(3,), (2, 1), (1, 1, 1)]
    99 >>> list(PartitionIterator(8,3,2))
    100 [(8,), (6, 2), (5, 3), (4, 4), (4, 2, 2), (3, 3, 2)]
    101 >>> list(PartitionIterator(8,3,2,3))
    102 [(3, 3, 2)]
    103 """
    104 return itertools.chain(*[FixedLengthPartitionIterator(N,k,min_,max_)
    105 for k in xrange(1,K+1)])
showing 10, 25, 50 items per pages

Pages : 1