Combinatorics

Peter Dobcsanyi dpeter at designtheory.org
Thu Oct 10 08:49:20 EDT 2002


Peter Dobcsanyi <dpeter at designtheory.org> wrote:
> Risking the sin of premature optimization :-), here is a version for
> comb() not defined in terms of the factorial function.
> 
> def combo(n, k):
>     if k < 0 or n < k :
>         return 0
>     if 2 * k > n :
>         k = n - k 
>     b = 1
>     if k > 0 :   
>         for i in xrange(k):
>             b = (b * (n - i)) / (i + 1)
>     return b
> 

Alex Martelli <aleax at aleax.it> wrote:
> I think a simpler optimization is to memoize fact (untested, I'm
> just typing this in by memory):
> 
> _facts = [1]
> def fact(integer):
>    assert integer >= 0
>    for i in range(len(_facts), integer+1):
>        _facts.append(i*_facts[-1])
>    return _facts[integer]
> 
> This makes it fast enough in an amortized sense to use freely
> as a primitive.  And you only need to pre-populate _facts in
> the obvious way to a greater extent to reduce the startup
> cost to be amortized.

I don't know which one is simpler, but for "large" numbers the memoizing
version is not a win in this case, it has a rather big memory footprint.

For example, clocking the time of comb(32000, 31000)  I got:

                 time         memory size

combo           0.02 sec      2.5 Mbyte
memoizing       0.42 sec      839 Mbyte         !!!

The time for the memoizing version was taken the second time around, so
_facts was already populated. Continuing with the populated _facts:

      n         k       combo     memoizing

    32000    16000      1.51        1.99
    15000     7500      0.35        0.42
    15000    14000      0.02        0.16
    10000     5000      0.17        0.19
    10000     9000      0.02        0.09
     5000     2500      0.04        0.04
     5000     4500      0.01        0.02
     1000      500      0.0         0.0

 Peter



More information about the Python-list mailing list