MATLAB:通过重复向量的元素来创建一个大矩阵,每个列的步幅越来越大

时间:2014-08-11 13:59:45

标签: matlab matrix vectorization repeat

在MATLAB中我有一个长度为n的向量x,其中n通常是O(10),我想构建一个大小为[n ^ m,m]的高矩阵A,其中m再次为0(10) )。矩阵具有一种特殊的形式:如果n = 4且m = 6,则让

x=[x1; x2; x3; x4]

然后A是

   x1 x1 x1 x1 x1 x1
   x2 x1 x1 x1 x1 x1
   x3 x1 x1 x1 x1 x1
   x4 x1 x1 x1 x1 x1
   x1 x2 x1 x1 x1 x1
   x2 x2 x1 x1 x1 x1
   x3 x2 x1 x1 x1 x1
   x4 x2 x1 x1 x1 x1
   x1 x3 x2 x1 x1 x1
   .               .         
   .               . 
   .               .
   x4 x4 x4 x4 x4 x4

实际上,每列都是通过重复x的元素获得的,每列的步幅越来越大。我怎样才能做到这一点?如果可能的话,我更喜欢有效的(矢量化)解决方案,因为正如您所看到的,A的行数随m呈指数增长。非常感谢,

塞尔吉奥

编辑:哎呀,对不起!我忘了我还需要建立一个大小为[n ^ m,1]的向量V,基于具有相同长度x的向量w

w=[w1; w2; w3; w4]

V是

   w1^6
   w2*w1^5
   w3*w1^5
     .
     .
     .
   w4^6

希望糟糕的图形足够清晰。无论如何,V是长度为n ^ m的列向量。猜猜我可以用w创建矩阵B,就像从x创建矩阵A一样,然后使用prod(B,2)?

5 个答案:

答案 0 :(得分:5)

使用 allcomb tool from MATLAB file-exchange 生成索引[1 2 3 4]的可能组合,然后使用它们索引到x -

v = repmat({1:numel(x)},1,m);
A = x(fliplr(allcomb(v{:})));

此外,它似乎不是使用fliplr,而是使用 - allcomb(v{:},'matlab')代替。

对于问题的编辑部分,您可以使用它的修改版本 -

V = prod(x(allcomb(v{:})),2)

基准

请注意,这些是针对此处发布的可运行解决方案。

基准代码

%// Parameters and input x
n = 10; m = 6;num_runs = 20; x =  randi(9,n,1);

disp('-------- With allcomb')
tic
for runs = 1:num_runs
    v = repmat({1:numel(x)},1,m);
    A = x(fliplr(allcomb(v{:})));
end
toc,    clear v A

disp('-------- With bsxfun')
tic
for runs = 1:num_runs
    A = x(floor(mod(bsxfun(@rdivide, (0:n^m-1).', n.^[0:m-1] ), n)+1)); %//'
end
toc,    clear A

disp('-------- With ttable')
tic
for runs = 1:num_runs
    I = ttable(n*ones(1,m));
    A = x(I);
end
toc,    clear I A

disp('-------- With arrayfun')
tic
for runs = 1:num_runs
    A = cell2mat(arrayfun(@(i)...
        (repmat(reshape(repmat(x',n^(i-1),1),[],1),n^(m-i),1)),1:m,'uni',0));
end
toc

<强>结果

-------- With allcomb
Elapsed time is 6.544981 seconds.
-------- With bsxfun
Elapsed time is 11.547062 seconds.
-------- With ttable
Elapsed time is 15.729932 seconds.
-------- With arrayfun
Elapsed time is 4.319048 seconds.

答案 1 :(得分:4)

单行内容仅基于内置函数(即mod和非常强大的bsxfun):

result = x(floor(mod(bsxfun(@rdivide, (0:n^m-1).', n.^[0:m-1] ), n)+1));

答案 2 :(得分:2)

试试这个:(所有都是bulit-in函数)

A = cell2mat(arrayfun(@(i)(repmat(reshape(repmat(x',n^(i-1),1),[],1),n^(m-i),1)),1:m,'UniformOutput',0))

说明:

n = 2;
m = 4;
x = (1:n)';
A = [];
for i = 1:m
%// temp1 is (n^(i-1)) x n matrix with each row equal to x' 
    temp1 = repmat(x',n^(i-1),1); 
%// temp2 is (n^(i-1))*n x 1 column vector with corresponding elements of temp1
    temp2 = reshape(temp1,[],1);
%// temp3 is a (n^(m-i))*(n^(i-1))*n x 1, i.e n^m x 1 column vector with elements of temp2 repeated n^(m-i) times
    temp3 = repmat(temp2,n^(m-i),1);
%// A is appending temp3 into its ith column
    A = cat(2,A,temp3);
end

编辑部分:

你可以做你所说的,即做prod(B,2),其中B是使用上面代码计算的矩阵

答案 3 :(得分:1)

我认为文件交换中的generalized truth table函数可以帮助您

尝试(未测试):

I = ttable(n*ones(1,m));
x(I);

答案 4 :(得分:0)

好的,有一个棘手的单线解决方案。但是,在matlab文件交换上有一个文件,如果订单无关紧要,则提供您正在查看的解决方案。见combn。它基本上使用了与其他答案所呈现的单线程相同的技巧。 如果订单很重要,您可能需要进行一些排序或直接调整源代码。