Bil*_*ham 14 random matlab integer
在MATLAB中,我想生成n范围内的随机整数对[1, m],其中每对都是唯一的.为了唯一性,我认为对中的数字的顺序是无关的,[3, 10]等于[10, 3].此外,每对应由两个不同的整数组成; 即[3, 4]好,但[3, 3]会被拒绝.
编辑:应该选择具有相同可能性的每个可能的对.
(显然,对参数的约束是n <= m(m-1)/2.)
我m很小的时候就能成功地做到这一点,就像这样:
m = 500; n = 10; % setting parameters
A = ((1:m)'*ones(1, m)); % each column has the numbers 1 -> m
idxs1 = squareform(tril(A', -1))';
idxs2 = squareform(tril(A, -1))';
all_pairs = [idxs1, idxs2]; % this contains all possible pairs
idx_to_use = randperm( size(all_pairs, 1), n ); % choosing random n pairs
pairs = all_pairs(idx_to_use, :)
pairs =
254 414
247 334
111 146
207 297
45 390
229 411
9 16
75 395
12 338
25 442
Run Code Online (Sandbox Code Playgroud)
但是,矩阵A的大小m x m,意味着当m变大(例如超过10,000)时,MATLAB会耗尽内存.
我考虑过生成一堆随机数randi(m, [n, 2]),并反复拒绝重复的行,但我担心在n接近时陷入循环m(m-1)/2.
是否有更简单,更清晰的方法来生成独特的不同整数对?
小智 11
当以正确的方式观看时,容易,轻松.
你希望生成n对整数,[p,q],使得p和q位于区间[1,m]和p中
有多少可能的对?对的总数仅为m*(m-1)/ 2.(即1到m-1之间的数字之和.)
因此我们可以在[1,m*(m-1)/ 2]范围内生成n个随机整数.Randperm做得很好.(较旧的matlab版本不允许第二个参数为randperm.)
k = randperm(m/2*(m-1),n);
Run Code Online (Sandbox Code Playgroud)
(请注意,我用滑稽的方式用m表示这个表达式,在可能是一个奇怪的地方除以2.这避免了m值接近上限的精度问题.)
现在,如果我们将每个可能的对[p,q]与k中的一个整数相关联,我们可以向后工作,从k中生成的整数到一对[p,q].因此,该列表中的前几对是:
{[1,2], [1,3], [2,3], [1,4], [2,4], [3,4], ..., [m-1,m]}
Run Code Online (Sandbox Code Playgroud)
我们可以将它们视为大小为m乘m的严格上三角形阵列中的元素,因此这些元素位于主对角线上方.
q = floor(sqrt(8*(k-1) + 1)/2 + 1/2);
p = k - q.*(q-1)/2;
Run Code Online (Sandbox Code Playgroud)
看到这些公式从k中的展开元素中恢复p和q.我们可以说服自己这确实有效,但也许这里的一个简单方法就是这个测试:
k = 1:21;
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
[k;p;q]'
ans =
1 1 2
2 1 3
3 2 3
4 1 4
5 2 4
6 3 4
7 1 5
8 2 5
9 3 5
10 4 5
11 1 6
12 2 6
13 3 6
14 4 6
15 5 6
16 1 7
17 2 7
18 3 7
19 4 7
20 5 7
21 6 7
Run Code Online (Sandbox Code Playgroud)
另一种测试方法是显示所有对都是针对小案例生成的.
m = 5;
n = 10;
k = randperm(m/2*(m-1),n);
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
sortrows([p;q]',[2 1])
ans =
1 2
1 3
2 3
1 4
2 4
3 4
1 5
2 5
3 5
4 5
Run Code Online (Sandbox Code Playgroud)
是的,看起来一切都很完美.现在尝试使用m和n的一些大数来测试使用的时间.
tic
m = 1e6;
n = 100000;
k = randperm(m/2*(m-1),n);
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
toc
Elapsed time is 0.014689 seconds.
Run Code Online (Sandbox Code Playgroud)
由于双精度的精度误差,该方案在失败之前将适用于大约1e8的m.在m/2*(m-1)超过2 ^ 53之前,精确限制应该是m不大于134217728.一个很好的功能是不需要拒绝重复对.