Python中随机生成特定长度整数分区的算法?

Python中随机生成特定长度整数分区的算法?,python,combinatorics,sage,Python,Combinatorics,Sage,我一直在使用SAGE提供的random\u element()函数为特定长度(S)的给定整数(N)生成随机整数分区。我试图从所有分区的集合中为N和S的给定值生成无偏随机样本。SAGE的函数快速返回N的随机分区(即分区(N).random_element()) 但是,当添加S(即分区(N,长度=S).random_元素())时,速度会大大减慢。同样地,过滤掉长度为S的N的随机分区速度非常慢 但是,我希望这对某些人有所帮助,我发现当函数返回的分区N与长度S不匹配时,共轭分区的长度通常为S。也就是说:

我一直在使用SAGE提供的
random\u element()
函数为特定长度(
S
)的给定整数(
N
)生成随机整数分区。我试图从所有分区的集合中为
N
S
的给定值生成无偏随机样本。SAGE的函数快速返回N的随机分区(即
分区(N).random_element()

但是,当添加
S
(即
分区(N,长度=S).random_元素()
)时,速度会大大减慢。同样地,过滤掉长度为
S
N
的随机分区速度非常慢

但是,我希望这对某些人有所帮助,我发现当函数返回的分区
N
与长度
S
不匹配时,共轭分区的长度通常为S。也就是说:

S = 10
N = 100
part = list(Partitions(N).random_element())
    if len(part) != S:
        SAD = list(Partition(part).conjugate())
        if len(SAD) != S:
            continue
这增加了发现长度为
S
的分区的速度,并似乎产生了无偏样本(我已经针对
N
S
的不同值对整个分区集的结果进行了检查)


但是,我使用了N(例如
10000
)和S(例如
300
)的值,这使得这种方法的速度不切实际。与SAGE的
random_element()
函数相关的注释承认存在大量优化空间。那么,是否有一种方法可以更快地生成与给定值
N
S
匹配的整数分区的无偏(即随机均匀)样本,或者,不生成与
S
不匹配的分区?此外,在许多情况下,使用共轭分区可以很好地生成无偏样本,但我不能说我确切地理解了原因

简单方法:随机分配整数:

def random_partition(n, s):
    partition = [0] * s
    for x in range(n):
        partition[random.randrange(s)] += 1
    return partition

当我试图计算强生日问题的概率时,我遇到了一个类似的问题

首先,当只给出少量的数字时,配分函数爆炸。您将返回大量信息。无论使用哪种方法,N=10000和S=300都会生成大量的数据。这将是缓慢的。您使用的任何纯python实现都可能同样慢或更慢。期待制作一个CModule

如果您想尝试python,我采用的方法是将itertools和生成器结合起来,以降低内存使用率。我似乎不再手边有我的代码,但这里有一个很好的补充:

编辑:

找到我的代码:

def partition(a, b=-1, limit=365):
  if (b == -1):
    b = a
  if (a == 2 or a == 3):
    if (b >= a and limit):
      yield [a]
    else:
      return
  elif (a > 3):
    if (a <= b):
      yield [a]
    c = 0
    if b > a-2:
      c = a-2
    else:
      c = b
    for i in xrange(c, 1, -1):
      if (limit):
        for j in partition(a-i, i, limit-1):
          yield [i] + j
def分区(a,b=-1,limit=365):
如果(b==-1):
b=a
如果(a==2或a==3):
如果(b>=a和极限):
收益率[a]
其他:
返回
elif(a>3):
如果(a-2:
c=a-2
其他:
c=b
对于x范围内的i(c,1,-1):
如果(限制):
对于分区中的j(a-i,i,极限-1):
收益率[i]+j

最后,我有一个绝对无偏的方法,具有零拒绝率。当然,我已经测试过它,以确保结果是整个可行集的代表性样本。它非常快速且完全无偏。享受吧

from sage.all import *
import random
首先是一个函数,用于查找n与s部分的分区的最小最大加数

def min_max(n,s):

    _min = int(floor(float(n)/float(s)))
    if int(n%s) > 0:
        _min +=1

    return _min
接下来是一个使用缓存和备忘录查找分区数的函数 n的s部分中,x是最大的部分。这很快,但我认为有 一个更优雅的解决方案。例如,通常是:P(N,S,max=K)=P(N-K,S-1) 感谢ante()帮助我做到这一点:


感谢您的回复,但我不知道此函数如何基于均匀随机采样生成分区。@klocey,我错过了您从序列生成随机元素的事实,抱歉。我实现了此函数,并将其生成的随机样本与完整的分区集进行了比较,以进行N和S的几种组合。比较使用分区方差生成的核密度曲线生成。与我尝试过的所有其他采样策略一样,此函数生成有偏差的样本(低于预期方差的分区).显然,对于给定的总N和长度S,从所有分区的集合中生成无偏随机样本非常困难。SAGE函数是我得到的最接近的函数,但它远不是最优的。是的,组合爆炸很难实现。但是,我一次生成一个随机分区,只为c保留一个小的随机样本比较分析。我试图获得一个小的、无偏的、随机的、给定长度的N个分区样本。SAGE的函数在Cython中运行,我自己的脚本也是如此,所以高效的速度并不是一个问题,而是找到一种算法或一种方法来调整SAGE的函数,以避免生成不必要的分区(即长度不为S的分区)。我将查看您的实现和“强生日问题”。谢谢。找到了我的代码,它是一个生成器,它可以找到大小为2或更大的分区(最大为给定数字),您可以删除阻止分区小于2的逻辑。但我怀疑它是否会更快。
D = {}
def P(n,s,x):
    if n > s*x or x <= 0: return 0
    if n == s*x: return 1
    if (n,s,x) not in D:
        D[(n,s,x)] = sum(P(n-i*x, s-i, x-1) for i in xrange(s))
    return D[(n,s,x)]
def random_partition(n,s):
    S = s
    partition = []
    _min = min_max(n,S)
    _max = n-S+1

    total = number_of_partitions(n,S)
    which = random.randrange(1,total+1) # random number

    while n:
        for k in range(_min,_max+1):
            count = P(n,S,k)
            if count >= which:
                count = P(n,S,k-1)
                break

        partition.append(k)
        n -= k
        if n == 0: break
        S -= 1
        which -= count
        _min = min_max(n,S)
        _max = k

    return partition