【问题标题】:Generating certain permutations生成某些排列
【发布时间】:2014-10-27 20:30:24
【问题描述】:

我有 2 个变量...输入的数量 N 和历史 M 的长度。这两个变量决定了矩阵 V 的大小,即 n x m,即 n 行 m 列。

我很难想出一种算法,使我能够生成一定数量的排列(或序列,你认为合适的)。

如果有人可以在 Matlab 中帮助我提供算法,我将非常高兴,但伪算法也非常好。

我举三个例子:

  1. 如果输入数为 N = 1,历史长度为 M = 2,则我有 (M+1)^N 个不同的组合,在本例中为 3。排列为:

(如果您不熟悉 matlab 矩阵表示法,, 分隔列,; 分隔行。)

V(1) = [1,0,0] 
V(2) = [0,1,0]
V(3) = [0,0,1]
  1. 如果输入数为 N = 2,历史长度为 M = 2,我有 (M+1)^N 个不同的组合,在本例中为 9。

排列是:

V(1) = [1,0,0; 1,0,0]
V(2) = [1,0,0; 0,1,0]
V(3) = [1,0,0; 0,0,1]
V(4) = [0,1,0; 1,0,0]
V(5) = [0,1,0; 0,1,0]
V(6) = [0,1,0; 0,0,1]
V(7) = [0,0,1; 1,0,0]
V(8) = [0,0,1; 0,1,0]
V(9) = [0,0,1; 0,0,1]
  1. 如果输入数为 N = 3,历史长度为 M = 3,我有 (M+1)^N 个不同的组合,在本例中为 64。

排列是:

V(1)  = [1,0,0,0; 1,0,0,0; 1,0,0,0] 
V(2)  = [1,0,0,0; 1,0,0,0; 0,1,0,0]
V(3)  = [1,0,0,0; 1,0,0,0; 0,0,1,0]
V(4)  = [1,0,0,0; 1,0,0,0; 0,0,0,1]
V(5)  = [1,0,0,0; 0,1,0,0; 1,0,0,0]
        ...
V(8)  = [1,0,0,0; 0,1,0,0; 0,0,0,1]
V(9)  = [1,0,0,0; 0,0,1,0; 1,0,0,0]
        ...
V(16) = [1,0,0,0; 0,0,0,1; 0,0,0,1]
V(17) = [0,1,0,0; 1,0,0,0; 1,0,0,0]
        ...
V(64) = [0,0,0,1; 0,0,0,1; 0,0,0,1]

编辑:我刚刚找到了一种方法来生成非常大的矩阵 W,其中每一行代表 V(i)

对于第一种情况:

W = eye(3)

这里eye(k)创建一个大小为k x k的单位矩阵

对于第二种情况:

W = [kron(eye(3),    ones(3,1)), ...
     kron(ones(3,1),    eye(3))]

这里kron是大小为k x l的kronecker productones(k,l)creates a matrix with ones

对于第三种情况:

W = [kron(kron(eye(4),    ones(4,1)), ones(4,1)), ...
     kron(kron(ones(4,1),    eye(4)), ones(4,1)), ...
     kron(kron(ones(4,1), ones(4,1)),    eye(4))]

现在我们已经创建了矩阵 W,其中每一行以向量形式表示 V(i),V(i) 还不是矩阵。

观察两件事:

  1. 当输入 N 增加时,一个额外的列会添加一个额外的克罗内克积,并且单位矩阵会沿着向量移动。
  2. 当历史 M 的长度增加时,单位矩阵向量也会增加,例如 eye(4) -> eye(5)、ones(4,1) -> one(5,1)。

【问题讨论】:

  • 算法还是你只需要一个产生结果的函数?并且是 V 向量以重要的顺序返回(即,[1 0 0][0 1 0] 之前,反之亦然)。

标签: algorithm matlab matrix permutation


【解决方案1】:

我想这可以满足您的所有要求。甚至顺序对我来说也是正确的:

M=3;N=3;
mat1=eye(M+1);
vectors=mat2cell(repmat(1:M+1,N,1),ones(N,1),[M+1]);

超高效的笛卡尔积,取自here

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
n = numel(vectors); %// number of vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n); %// reshape to obtain desired matrix
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    

V=cell(size(combs,1),1);
for i=1:size(combs,1)
    for j=1:size(combs,2)
        V{i,1}=[V{i,1};mat1(combs(i,j),:)];
    end
end

输出:

M=2,N=2;

V=

[1,0,0;1,0,0]
[1,0,0;0,1,0]
[1,0,0;0,0,1]
[0,1,0;1,0,0]
[0,1,0;0,1,0]
[0,1,0;0,0,1]
[0,0,1;1,0,0]
[0,0,1;0,1,0]
[0,0,1;0,0,1]

M=3;N=3;  %order verified for the indices given in the question

V(1)  = [1,0,0,0; 1,0,0,0; 1,0,0,0] 
V(2)  = [1,0,0,0; 1,0,0,0; 0,1,0,0]
V(3)  = [1,0,0,0; 1,0,0,0; 0,0,1,0]
V(4)  = [1,0,0,0; 1,0,0,0; 0,0,0,1]
V(5)  = [1,0,0,0; 0,1,0,0; 1,0,0,0]
        ...
V(8)  = [1,0,0,0; 0,1,0,0; 0,0,0,1]
V(9)  = [1,0,0,0; 0,0,1,0; 1,0,0,0]
        ...
V(16) = [1,0,0,0; 0,0,0,1; 0,0,0,1]
V(17) = [0,1,0,0; 1,0,0,0; 1,0,0,0]
        ...
V(64) = [0,0,0,1; 0,0,0,1; 0,0,0,1]

【讨论】:

  • 非常感谢您的回答!我不知道你怎么这么快就想到了这个!但是非常感谢你:D
  • 关键观察是创建长度为 N 的向量的所有排列就足够了,它只有两个值 -> 0 和 1。所以这可以通过单位矩阵来实现。然后很容易看出,如果您只保持其中一个行不变并改变其他行以获得所有排列(由排列矩阵给出),那么您就会得到答案。
  • 是的,好吧,我也观察到了,但是将其翻译为更正 Matlab 代码对我来说是一个难题:P
  • @ParagS.Chandakkar 感谢您的参考 :-) 以及将数字“解码”为 0 和 1 的巧妙方法
  • @ParagS.Chandakkar,一个小问题,你为什么用V{i,1}而不是V{i}?这是更快还是不知何故?
【解决方案2】:

您可以通过考虑基数 M+1 中的输入来生成这些。

此基数中的每个数字都指定矩阵的哪一部分应在每行中设置为 1。

function V=makeperm(i,N,M)
i = i - 1;
V = zeros(N,M+1);
P = M+1;
% Generate digits in base P
for row = N:-1:1
    col=mod(i,P)+1;
    i=floor(i/P);
    V(row,col)=1;
end

此函数将为 N,M 的输入产生第 i^th 个排列。

例如

makeperm(17,3,3)
ans =

0   1   0   0
1   0   0   0
1   0   0   0

【讨论】:

    【解决方案3】:

    此代码使用allcomb tool from MATLAB file-exchange 生成与V 的每一行对应的十进制数。 allcomb的代码可以从here获取。

    解决上述问题的工作代码是 -

    power_vals = power(2,M:-1:0);
    pattern1 = repmat({power_vals},1,N);
    dec_nums = allcomb(pattern1{:});
    
    bin_nums = fliplr(de2bi(num2str(dec_nums,'%1d').'-'0')); %//'
    Vout = permute(reshape(bin_nums,N,size(bin_nums,1)/N,[]),[1 3 2]);
    

    因此,Voutnth 3D 切片将代表 V(n)

    示例运行 -

    使用M = 2N = 2,您将拥有 -

    >> Vout
    Vout(:,:,1) =
         1     0     0
         1     0     0
    Vout(:,:,2) =
         1     0     0
         0     1     0
    Vout(:,:,3) =
         1     0     0
         0     0     1
    Vout(:,:,4) =
         0     1     0
         1     0     0
    Vout(:,:,5) =
         0     1     0
         0     1     0
    Vout(:,:,6) =
         0     1     0
         0     0     1
    Vout(:,:,7) =
         0     0     1
         1     0     0
    Vout(:,:,8) =
         0     0     1
         0     1     0
    Vout(:,:,9) =
         0     0     1
         0     0     1
    

    【讨论】:

    • @ParagS.Chandakkar 谢谢!这里的用途是切割成 3D 切片。
    • @LuisMendo 好吧,我研究了dec2bin 一段时间但没有成功,所以切换船为de2bi 可以轻松使用数字数组。
    • @Divakar 应该注意的是,de2bi 在 Communcations System Toolbox 中,它不是默认的 MATLAB 发行版的一部分。
    • @MrAzzaman 没错!如果我需要对其进行任何修改,我想我将使用该信息编辑解决方案。感谢您对此处发布的解决方案的兴趣 :)
    • @LuisMendo 哦,我想,我首先用some_string - '0' 计算我输入de2bi 的数字。所以它有点像de2bi( '5' - '0')。希望这是有道理的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多