如何在一个 1×41 向量中生成定位 20 个 -1 值的每个排列?
Posted
技术标签:
【中文标题】如何在一个 1×41 向量中生成定位 20 个 -1 值的每个排列?【英文标题】:how to produce every permutation of positioning 20 values of -1 in a 1-by-41 vector of ones? 【发布时间】:2019-01-04 22:37:10 【问题描述】:我编写了不同的代码来产生不同的排列组合。它们适用于小尺寸的矩阵:
例如:
S=[-1 -1 1 1 1 1 1 1];
P=unique(perms(S),'rows');
产生:
-1 -1 1 1 1 1 1 1
-1 1 -1 1 1 1 1 1
-1 1 1 -1 1 1 1 1
-1 1 1 1 -1 1 1 1
-1 1 1 1 1 -1 1 1
-1 1 1 1 1 1 -1 1
-1 1 1 1 1 1 1 -1
1 -1 -1 1 1 1 1 1
1 -1 1 -1 1 1 1 1
1 -1 1 1 -1 1 1 1
1 -1 1 1 1 -1 1 1
1 -1 1 1 1 1 -1 1
1 -1 1 1 1 1 1 -1
1 1 -1 -1 1 1 1 1
1 1 -1 1 -1 1 1 1
1 1 -1 1 1 -1 1 1
1 1 -1 1 1 1 -1 1
1 1 -1 1 1 1 1 -1
1 1 1 -1 -1 1 1 1
1 1 1 -1 1 -1 1 1
1 1 1 -1 1 1 -1 1
1 1 1 -1 1 1 1 -1
1 1 1 1 -1 -1 1 1
1 1 1 1 -1 1 -1 1
1 1 1 1 -1 1 1 -1
1 1 1 1 1 -1 -1 1
1 1 1 1 1 -1 1 -1
1 1 1 1 1 1 -1 -1
或
indices = nchoosek(1:41, 6);
N = size(indices, 1);
S = ones(N, 41);
S(sub2ind([N 41], [1:N 1:N 1:N 1:N 1:N 1:N].', indices(:))) = -1;
可以生产 6 减一(-1)和 35 一(1)的所有排列的 4496388_by_41 矩阵。
这些代码适用于较小尺寸的矩阵,但不适用于较大尺寸的矩阵。
我的目标是产生 20 减一 (-1) 和 21 一 (1) 的所有排列,这个矩阵有 269128937220 行和 41 列。但以下代码不起作用:
indices = nchoosek(1:41, 20);
N = size(indices, 1);
S = ones(N, 41);
S(sub2ind([N 41], [1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N 1:N].', indices(:))) = -1;
或
S=[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1];
P=unique(perms(S),'rows');
我对每个排列(这个矩阵的每一行)做一个简单的计算。如果我可以用 for 循环编写该矩阵的每一行,然后对该行进行计算,我将能够保持最佳结果,在这种情况下,我不必将所有这些数据保存在内存中,我会'不要从 matlab 中得到内存错误。
如果您知道如何使用 for 循环或任何其他方式将它们存储在我的计算机中,请帮助生成一个包含 20 减一 (-1) 和 21 一 (1) 的所有排列的矩阵。
提前致谢
【问题讨论】:
您已确定有 269128937220 个组合。你打算用这些做什么?假设您每秒可以评估 1000 个组合:269128937220 / 1000 / 60 / 60 / 24 = 3114.9
天!您确定需要检查所有可能的组合吗?我觉得这不是您要解决的任何问题的正确方法...
269128937220 行和 41 列。这意味着 80 TB 的内存。你有吗?
我认为this may be relevant。
@SardarUsama 让我们清楚,80TB 的 RAM!甚至没有ROM!请 ehsun,花点时间看看这是多么荒谬。
@CrisLuengo,不一定是 3000 天……我们只需要几个小时!
【参考方案1】:
我不是Matlab
方面的专家,所以我不能代表所有可用资源,但是,我知道您的任务在没有任何花哨的高性能服务(例如https://aws.amazon.com/hpc/)的标准笔记本电脑上是可行的.
我在R
中编写了一个名为RcppAlgos
的包,它能够在几个小时内轻松完成这项任务。代码如下:
options(scipen = 999)
library(parallel)
library(RcppAlgos)
## WARNING Don't run this unless you have a few hours on your hand
## break up into even intervals of one million
firstPart <- mclapply(seq(1, 269128000000, 10^6), function(x)
temp <- permuteGeneral(c(1L,-1L), freqs = c(21,20), lower = x, upper = x + 999999)
## your analysis here
x
, mc.cores = 8)
## get the last few results and complete analysis
lastPart <- permuteGeneral(c(1L, -1L), freqs = c(21, 20),
lower = 269128000000, upper = 269128937220)
## analysis for last part goes here
为了向您展示此设置的效率,我们将展示前十亿个结果的完成速度。
system.time(mclapply(seq(1, 10^9, 10^6), function(x)
temp <- permuteGeneral(c(1L, -1L), freqs = c(21, 20), lower = x, upper = x + 999999)
## your analysis here
x
, mc.cores = 8))
user system elapsed
121.158 64.057 27.182
1000000000 个结果不到 30 秒!!!!!!
因此,正如@CrisLuengo 计算的那样,这不会花费超过 3000 天,而是保守估计每十亿人需要 30 秒:
(269128937220 / 1000000000 / 60) * 30 ~= 134.5645 minutes
我还应该注意,通过上面的设置,您一次只使用1251.2 Mb
,因此您的内存不会爆炸。
testSize <- object.size(permuteGeneral(c(1L,-1L), freqs = c(21,20), upper = 1e6))
print(testSize, units = "Mb")
156.4 Mb ## per core
所有结果均在 MacBook Pro 2.8GHz 四核(4 个虚拟核心......总共 8 个)上获得。
编辑:
正如@CrisLuengo 指出的那样,上述仅测量生成那么多排列,并没有考虑分析每个计算所花费的时间。经过更多澄清和一个新问题,我们现在有 answer... 大约 2.5 天!!!
【讨论】:
135 分钟,如果你不对这些排列做任何事情。在“您的分析”部分中添加一些有意义的内容,然后您的时间会显着增加。我不知道 OP 需要这些排列做什么,你也不知道。 :) @CrisLuengo,感谢您的客气话。是的,你不知道每个排列的分析结果是正确的。当我有机会时,我会编辑我的答案以明确这一点。 非常感谢您的帮助。计算包括对每一行的以下操作: (SLS')/4 其中 S 是该矩阵的每一行(1 x 41 数组)。 S' 是 S(一个 41 x 1 数组)的转置。 L 是一个 41 x 41 矩阵,每行的最终结果是一个数字。你认为这样的计算可行吗? @ehsun,我已经制定了一个解决方案,但是我认为编辑这个答案或在这篇文章中添加另一个答案是不合适的。您能否在R
的框架内提出另一个问题,每个排列所需的具体计算?
没问题,我会做的以上是关于如何在一个 1×41 向量中生成定位 20 个 -1 值的每个排列?的主要内容,如果未能解决你的问题,请参考以下文章