MATLAB: create a large matrix by repeating elements of a vector, with increasing stride for each column

巧了我就是萌 提交于 2019-12-08 01:54:43

问题


In MATLAB I have a vector x of length n, where n is usually O(10), and I would like to build a tall matrix A of size [n^m,m], where m is again 0(10). The matrix has a peculiar form: if n=4 and m=6, let

x=[x1; x2; x3; x4]

then A is

   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

In practice, each column is obtained by repeating the elements of x, with an increasing stride for each column. How can I do that? If possible, I'd prefer an efficient (vectorized) solution, because, as you can see, the number of rows of A increases exponentially with m. Thanks very much,

Sergio

EDIT: whoops, sorry! I forgot I also need to build a vector V of size [n^m,1], based on vector w having the same length of x

w=[w1; w2; w3; w4]

V is

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

Hope the crappy graphics is clear enough. Anyway, V is a column vector of lenght n^m. Guess I could create a matrix B from w, in the same way one creates a matrix A from x, and then use prod(B,2)?


回答1:


Use allcomb tool from MATLAB file-exchange to generate the possible combinations of the indices [1 2 3 4] and then use them to index into x -

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

Also, it seems instead of using fliplr, you can use - allcomb(v{:},'matlab') instead.

For the edited part of the question, you can use a modified version of it -

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

Benchmarking

Please note that these are for runnable solutions posted here.

Benchmarking Code

%// 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

Results

-------- 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.



回答2:


One-liner based only on built-in functions (namely, mod and the very powerful bsxfun):

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



回答3:


Try this: (all are bulit-in functions)

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

Explanation:

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

For The EDIT part:

You can do what you said i.e do prod(B,2) where B is a matrix calculated using above code




回答4:


I think the generalized truth table function from the file exchange will help you

try (not tested):

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



回答5:


Okay, there are tricky one-liner solutions for this. There is, however, a file on matlab file exchanging providing the solution that you are looking at if the order doesn't matter. See here combn. It basically makes use of the same tricks as the one-liner presented by other answers. If the order matters, you might have to do some sorting aftwerwards or adjust the source code directly.



来源:https://stackoverflow.com/questions/25245105/matlab-create-a-large-matrix-by-repeating-elements-of-a-vector-with-increasing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!