Algorithm 均匀生成最多重复k次的置换?

Algorithm 均匀生成最多重复k次的置换?,algorithm,random,language-agnostic,permutation,uniform,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

我们已经设置了
{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
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
次才能生成序列,这一点非常明显

第二种是不产生均匀排列(一些排列的概率比其他排列的概率大)


你知道如何快速、一致地生成这样的序列吗?

这假设你有足够的内存来保存数字[1..n]k次

  • 设置数组[1..n]

  • 将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中

  • 在大型重复阵列上运行a的前m个步骤,以获得所需的排列。不需要洗牌整个数组,因为您只需要m个数字


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

  • 设置数组[1..n]

  • 将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中

  • 在大型重复阵列上运行a的前m个步骤,以获得所需的排列。不需要洗牌整个数组,因为您只需要m个数字


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

  • 设置数组[1..n]

  • 将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中。 就像@rossum提议的那样

  • 生成此大型阵列的概率均匀(1/(k*n))

  • 重复m次:

  • 从结果数组中获取一个数字
  • 设置抽取项目概率为0的概率,其余为 相同的值在它们之间均匀分布1/(k*n),我们刚刚设置为0
  • 例如:

    设S=[1,1,1,2,2,3,3,3,4,4]是一个大数组,其中每个项都有k,k=3,m=4

  • 生成p=[1/12]*len(S)

  • 结果=随机(S,p)假设结果=[1]

  • 概率将是这样的p=[0,1/12+1/36,1/12+1/36,1/12+1/36,其余保持不变]

  • 重复步骤2和3 m次


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

    如果我没记错的话。选择有一个选项来给出概率,那么你可以这样做:

  • 设置数组[1..n]

  • 将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中。 就像@rossum提议的那样

  • 生成此大型阵列的概率均匀(1/(k*n))

  • 重复m次:

  • 从结果数组中获取一个数字
  • 设置抽取项目概率为0的概率,其余为 相同的值在它们之间均匀分布1/(k*n),我们刚刚设置为0
  • 例如:

    设S=[1,1,1,2,2,3,3,3,4,4]是一个大数组,其中每个项都有k,k=3,m=4

  • 生成p=[1/12]*len(S)

  • 结果=随机(S,p)假设结果=[1]

  • 概率将是这样的p=[0,1/12+1/36,1/12+1/36,1/12+1/36,其余保持不变]

  • 重复步骤2和3 m次


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

    不必是Python。我在寻找更多的想法,而不是程序。不必是Python。我寻找的更多的是一个想法,而不是程序。它不会返回一致的随机排列。有了列表[1,2,1,2]和m=2,我会收到概率:(1,1)->1/6,(2,2)->1/6,(1,2)->2/6,(2,1)->2/6尝试检查F-Y洗牌代码是否正常工作。您需要移动大型阵列中的元素,以便只能拾取一次。它洗牌[1,2,3,4,5,6]正确吗?还可以查看RNG的输出;它是否显示出一种模式?例如,一些简单的RNG交替使用奇数和偶数。@rossum:(注释修订)不,OP是对的。你的算法不统一。假设你计算所有2n![1..2n]的置换,并查看每个置换中的前两个数字。你更愿意打赌这两个数字具有相同的奇偶性还是具有不同的奇偶性?答复:(b)。有2n(2n-1)对;其中n(n-1)都是偶数,n(n-1)都是奇数,而n²是偶数/奇数,n²是奇数/偶数。所以不同的奇偶比相同的奇偶更可能是n/(n-1)。如果n为2,这一点尤其明显,如上面OP的例子中所示。当然,这取决于“统一”的精确定义。统一的意思是,任何一对可能的配置都具有相同的概率。不会返回统一的随机排列。有了列表[1,2,1,2]和m=2,我会收到概率:(1,1)->1/6,(2,2)->1/6,(1,2)->2/6,(2,1)->2/6尝试检查F-Y洗牌代码是否正常工作。您需要移动大数组中的元素,以便它们只能