Hi,

This is a follow on to yesterdays thread about computing
multiplicative partitions of integers...

Today, a co-worker and myself found a (non-obvious) fast algorithm for
doing this.  Suprisingly, the tree based methods we began to discuss
yesterday turned out to be quite slow as you end up finding various
partitions multiple times.  We haven't worked out how the algorithm
scales, but it seems very  fast (as the tests below show) even though
it is pure python as of yet.

The algorithm is recursive - at each step you need to calculate
divisors of integers.  The thing which makes the algorithm efficient
is that as it progresses we are able to strongly limit the number of
divisors needed.  This is possible as it gets rid of the duplicates
seen in the tree based algorithms.

Question:  where would we begin looking to see if this algorithm is
known already?

Thanks everyone for your thoughts on this one.

Here is the code (BSD licensed, authors, Brian Granger and Dan Karipedes):

def divisors_minmax(n, dmin, dmax):
    """Find the divisors of n in the interval (dmin,dmax]."""
    i = dmin+1
    while i<=dmax:
        if n % i == 0:
            yield i
        i += 1

def list_or_tuple(seq):
    return isinstance(seq, (list, tuple))

def flatten(seq, to_expand=list_or_tuple):
    """Flatten a nested sequence"""
    for item in seq:
        if to_expand(item):
            for subitem in flatten(item, to_expand):
                yield subitem
        else:
            yield item

def mult_partitions(n, s):
    """Compute the multiplicative partitions of n of size s"""
    return [tuple(flatten(p)) for p in mult_partitions_recurs(n,s)]

def mult_partitions_recurs(n, s, pd=1):
    if s == 1:
        return [n]
    divs = divisors_minmax(n, pd, int(sqrt(n)))
    fs = []
    for d in divs:
        fs.extend([(d,f) for f in mult_partitions_recurs(n/d, s-1, pd)])
        pd = d
    return fs


A demo:

In [14]: mult_partitions(23452345,3)
Out[14]:
[(5, 7, 670067),
 (5, 67, 70007),
 (5, 73, 64253),
 (5, 137, 34237),
 (5, 469, 10001),
 (5, 511, 9179),
 (5, 959, 4891),
 (7, 67, 50005),
 (7, 73, 45895),
 (7, 137, 24455),
 (7, 335, 10001),
 (7, 365, 9179),
 (7, 685, 4891),
 (35, 67, 10001),
 (35, 73, 9179),
 (35, 137, 4891),
 (67, 73, 4795),
 (67, 137, 2555),
 (67, 365, 959),
 (67, 511, 685),
 (73, 137, 2345),
 (73, 335, 959),
 (73, 469, 685),
 (137, 335, 511),
 (137, 365, 469)]


And some timing:

In [10]: %timeit -n1 -r1 mult_partitions(23452345,2)
1 loops, best of 1: 2.5 ms per loop

In [11]: %timeit -n1 -r1 mult_partitions(23452345,3)
1 loops, best of 1: 5.55 ms per loop

In [12]: %timeit -n1 -r1 mult_partitions(23452345,4)
1 loops, best of 1: 6.79 ms per loop

In [13]: %timeit -n1 -r1 mult_partitions(23452345,5)
1 loops, best of 1: 6.54 ms per loop

--~--~---------~--~----~------------~-------~--~----~
To post to this group, send email to sage-devel@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/sage-devel
URLs: http://www.sagemath.org
-~----------~----~----~----~------~----~------~--~---

Reply via email to