Source code for combalg.subset

'''
subset.py
=========
Enumeration and random selection of arbitrary and k-element restricted
subsets.

Members
-------
'''
import random as rng



[docs]def powerset(elements): ''' A generator that produces all subsets of the input 'set' of elements. The input doesn't need to be a set, any iterable will do (I think). The point is that the elements need not be unique, but will be treated as unique with respect to the subset generation. For example: powerset(['a','a']) will give the sequence ['a','a'], ['a'], ['a'], [] :param elements: input set :type elements: list :return: one of the subsets of the input set :rtype: list ''' if len(elements) == 0: yield [] else: for item in powerset(elements[1:]): yield [elements[0]]+item yield item
[docs]def all_k_element(elements, k): ''' A generator that produces all k-element subsets of the input elements in lexicographic order. :param elements: the input set :type elements: list :param k: size of the output set :type k: int :return: one of the k-element subsets of the input set :rtype: list ''' n = len(elements) a = list(range(k)) h = 0 done = False first = True while not done: if not first: h = 0 if a[k-h-1] < n-h-1 else h+1 a[k-h-1] += 1 for j in range(k-h,k): a[j] = a[j-1] + 1 done = (k == 0) or (k == n) or (a[0] == n - k) first = False yield list(map(lambda x: elements[x], a))
[docs]def random(elements): ''' Returns a random subset of a set of elements. Equivalent to randomly selecting an element of powerset(elements). For each element of the universal set, select it to be in the subset with p=0.5 :param elements: the input set :type elements: list :return: a random subset of the input set :rtype: list ''' return filter(lambda x: rng.random() <= 0.5, elements)
[docs]def random_k_element(elements, k): ''' Returns a random k-element subset of a set of elements. This is a clever algorithm, explained in [NW1978]_ but not actually implemented. Essentially starting with the first element of the universal set, include it in the subset with p=k/n. If the first was selected, select the next with p=(k-1)/(n-1), if not p = k/(n-1), etc. :param elements: the input set :type elements: list :param k: the size of the output set :type k: int :return: a random k-element subset of the input set :rtype: list ''' a = [] c1 = k c2 = len(elements) i = 0 while c1 > 0: if rng.random() <= float(c1)/c2: a.append(elements[i]) c1 -= 1 c2 -= 1 i += 1 return a