Powersets of a list?

Emile van Sebille emile at fenx.com
Sun May 27 14:33:02 EDT 2001


"David C. Ullrich" <ullrich at math.okstate.edu> wrote in message
news:3b11015c.2099508 at nntp.sprynet.com...
> On Sat, 26 May 2001 20:09:20 +0200, "Alex Martelli"
<snip>
> There have been several power set routines posted.
> I suspect that they're all O(N*2^N), but when I time
> them (on Windows, starting with a list of length 15)
> some of them are at least 10 time faster than
> others.
>

Timing results for four of the powerset generators posted to this thread
(format edited for usenet):

SetSize: 5   enum recurs1 recurs2 lComp
 reps:  5 :  0.01   0.00    0.00   0.02
 reps: 10 :  0.02   0.00    0.01   0.02
 reps: 15 :  0.03   0.01    0.01   0.04
SetSize: 10
 reps:  5 :  0.50   0.08    0.06   0.63
 reps: 10 :  1.01   0.14    0.13   1.24
 reps: 15 :  1.46   0.23    0.19   1.88
SetSize: 15
 reps:  5 : 26.23   6.75    5.84  32.00
 reps: 10 : 56.81  13.31   14.05  64.70
 reps: 15 : 90.25  20.51   25.01  97.16

--

Emile van Sebille
emile at fenx.com

---------

#---powersetTimings.py

def toggle(pattern):
    if pattern[-1] == 0:
        pattern[-1] = 1
    else:
        pattern[-1] = 0
        pattern[:-1] = toggle(pattern[:-1])
    return pattern

def genNibbles(qty):
    rslt = [[0]*qty]
    for i in xrange(2**qty - 1):
        rslt.append(toggle(rslt[-1][:]))
    return rslt

def enum(set):
    incl = genNibbles(len(set))
    sq = range(len(set))
    rslt = []
    for i in incl:
        sset = []
        for j in sq:
            if i[j] == 1:
                sset.append(set[j])
        rslt.append(sset)
    return rslt


def recurs1(seq):
    """
    To computer the powerset of seq, we need to know the powerset of
    seq[1:] and combine a copy of it with seq[0] (as well as keeping
    an unmodified copy).

    We stop the recursion when seq is a singleton -- the powerset of
    [a] is [[a], []].
    """
    # Trivial case
    if len(seq) == 1:
        return [seq, []]
    # Now do the recursion and combine the results
    subSet = recurs1(seq[1:])
    resultSoFar = subSet[:]
    for set in subSet:
        resultSoFar.append([seq[0]] + set)
    return resultSoFar


def AddTo(list, elt):
    return list + [elt]

def recurs2(list):
  if list:
    ans = recurs2(list[:-1])
    return ans + map(AddTo, ans, [list[-1]]*len(ans))
  else:
    return [[]]


def lComp(L):
    N = len(L)
    return [ [L[i] for i in range(N) if X&(1L<<i)]
        for X in range(2**N) ]



from time import time

for setSize in (3, 8, 15):
    print "\n\nSetSize: %s" % setSize
    set = range(setSize)
    for iterations in (5, 10, 25):
        print ("\n\n%6d : " % iterations),
        for func in (enum, recurs1, recurs2, lComp):
            print '%8s:' % func.__name__,
            start = time()
            for i in range(iterations):
                assert len(func(set)) == 2**setSize
            print '%5.2f' % (time()-start),






More information about the Python-list mailing list