最多重复k次重复产生均匀排列的置换?

时间:2019-06-01 18:37:35

标签: algorithm random language-agnostic permutation uniform

我们设置了{1, 2, 3, ...,n}个数字。我们希望生成由这些数字创建的m个长度的置换,每个数字最多重复k次。

如果我们假设n=5, k=2, m=3,那么我们可以收到:{3,3,1},但不能收到{3, 3, 3},因为第二个示例中的3恰好是输出的三倍,这是大于k。

有没有一种快速统一生成这种排列的方法?

我尝试了两种不同的解决方案。

第一:

1)生成具有重复的随机排列,有n^m个不同的排列。

2)检查这是否是正确的排列(如果它包含的次数不超过相同数字的k

3)如果是,则返回,否则转到1)

Python代码段:

import numba
import numpy as np


@numba.jit(nopython=True)
def gen_sequence1(n, k, m):
    result = np.random.randint(0, n, (1, m))[0]
    while not is_correct(result, k):
        result = np.random.randint(0, n, (1, m))[0]
    return result


@numba.jit(nopython=True)
def most_frequent(iter):
    return np.bincount(iter).max()


@numba.jit(nopython=True)
def is_correct(pruf, k):
    return most_frequent(pruf) <= k

第二种方法:

生成随机整数,仅在k次之前没有出现时才将其添加到序列中。这些单词的优化版本如下所示(用Python编写)。 Python片段:

def gen_seq(n, d, m):
    choices = list(range(n))
    degrees = [0] * n
    result = []
    k = n - 1
    for i in range(m):
        rand = np.random.randint(0, k)
        result.append(choices[rand])
        degrees[choices[rand]] += 1
        if degrees[choices[rand]] == d:
            choices[rand], choices[k] = choices[k], choices[rand]
            k -= 1
    return result

问题在于第一种方法在n=30, m=28, d=1时非常慢,它需要10^9次才能生成序列,这很明显。

第二个不是生成统一排列(某些排列的概率比其他排列大)。

您是否知道如何快速而均匀地生成这样的序列?

2 个答案:

答案 0 :(得分:0)

这假定您有足够的内存来保存数字[1..n] k次。

  1. 设置数组[1..n]。

  2. 将数组k次复制:[1..n,1..n,1..n,... 1..n]到大数组中。

  3. 在大型重复数组上运行Fisher-Yates shuffle的前m个步骤,以获取所需的排列。因为只需要m个数字,所以不需要重新整理整个数组。

答案 1 :(得分:0)

如果我没记错的话,np.choice有一个给出概率的选项,那么您可以这样做:

  1. 设置数组[1..n]。

  2. 将数组复制k次:[1..n,1..n,1..n,... 1..n]成一个大数组。 就像@rossum建议的一样。

  3. 生成这种大阵列均匀(1 /(k * n))的概率。

重复m次:

  1. 为结果数组获取一个数字
  2. 设置概率,得出的项目概率为0,其余的概率为 它们之间的相同值均匀分布为我们刚刚设置为0的1 /(k * n)

示例:

让S = [1,1,1,2,2,2,3,3,3,4,4,4]是一个大数组,里面每个元素都有k个,k = 3和m = 4。

  1. 生成P = [1/12] * len(S)

  2. 结果= random(S,P)假设结果= [1]

  3. 概率将像这样P = [0,1 / 12 + 1 / 36,1 / 12 + 1 / 36,1 / 12 + 1/36,其余保持不变]

    < / li>

重复步骤2和3 m次

如果没有更多与绘制的值相同的值,则将其设置为0并设置静息概率以将该比率和总和保持为1。我认为最困难的部分是操纵概率。