I have a N x 1 array A, and want to get the result matrix with elements being evaluation of function f (such as max) on pairs A(i) & A(j) (i, j =1,...,N). The result matrix will look like [ f(A(i), A(j))]. Any one have suggestions to achieve this without using loop? Also better avoid bsxfun, since bsxfun is not implemented in some program. TKS
Use meshgrid and arrayfun:
[ii jj ] = ndgrid(1:N, 1:N); %// generate all combinations of i and j
result = arrayfun(#(n) f(A(ii(n)), A(jj(n))), 1:N^2);
result = reshape(result, length(A)*[1 1]); %// reshape into a matrix
Example:
N = 3;
A = [4 5 2];
f = #(x,y) max(x,y);
>>[ii jj ] = ndgrid(1:N, 1:N);
result = arrayfun(#(n) f(A(ii(n)), A(jj(n))), 1:N^2);
result = reshape(result, length(A)*[1 1])
result =
4 5 4
5 5 5
4 5 2
If you do not want loops and no bsxfun you are left with repmat
ra = repmat( A, [1 size(N,1)] );
res = f( ra, ra' ); % assuming f can be vectorized over matrices
Related
In matlab, I would like to multiply M vectors using L matrices, resulting with M x L new vectors. Specifically, say I have a matrix A of size N x M and a matrix B of size N x N x L matrix, I would like to calculate a matrix C of size N x M x L where the result is exactly like the following slow code:
for m=1:M
for l=1:L
C(:,m,l)=B(:,:,l)*A(:,m)
end
end
but do achieve this efficiently (using native code rather than matlab looping).
We could ab-use fast matrix-multiplication here, just need to rearrange dimensions. So, push back the second dimension of B to the end and reshape to 2D such that the first two dims are merged. Perform matrix-multiplication with A to give us a 2D array. Let's call it C. Now, C's first dim were the merged dims from B. So, split it back into their original two dim lengths with reshaping resulting in a 3D array. Finally push back the second dim to the back with one more permute. This is the desired 3D output.
Hence, the implementation would be -
permute(reshape(reshape(permute(B,[1,3,2]),[],N)*A,N,L,[]),[1,3,2])
Benchmarking
Benchmarking code :
% Setup inputs
M = 150;
L = 150;
N = 150;
A = randn(N,M);
B = randn(N,N,L);
disp('----------------------- ORIGINAL LOOPY -------------------')
tic
C_loop = NaN(N,M,L);
for m=1:M
for l=1:L
C_loop(:,m,l)=B(:,:,l)*A(:,m);
end
end
toc
disp('----------------------- BSXFUN + PERMUTE -----------------')
% #Luis's soln
tic
C = permute(sum(bsxfun(#times, permute(B, [1 2 4 3]), ...
permute(A, [3 1 2])), 2), [1 3 4 2]);
toc
disp('----------------------- BSXFUN + MATRIX-MULT -------------')
% Propose in this post
tic
out = permute(reshape(reshape(permute(B,[1,3,2]),[],N)*A,N,L,[]),[1,3,2]);
toc
Timings :
----------------------- ORIGINAL LOOPY -------------------
Elapsed time is 0.905811 seconds.
----------------------- BSXFUN + PERMUTE -----------------
Elapsed time is 0.883616 seconds.
----------------------- BSXFUN + MATRIX-MULT -------------
Elapsed time is 0.045331 seconds.
You can do it with some permuting of dimensions and singleton expansion:
C = permute(sum(bsxfun(#times, permute(B, [1 2 4 3]), permute(A, [3 1 2])), 2), [1 3 4 2]);
Check:
% Example inputs:
M = 5;
L = 6;
N = 7;
A = randn(N,M);
B = randn(N,N,L);
% Output with bsxfun and permute:
C = permute(sum(bsxfun(#times, permute(B, [1 2 4 3]), permute(A, [3 1 2])), 2), [1 3 4 2]);
% Output with loops:
C_loop = NaN(N,M,L);
for m=1:M
for l=1:L
C_loop(:,m,l)=B(:,:,l)*A(:,m);
end
end
% Maximum relative error. Should be 0, or of the order of eps:
max_error = max(reshape(abs(C./C_loop),[],1)-1)
I wanted to compute the following matrix in Matlab:
g=[I
A
.
.
.
A^N]
I used the following program in Matlab:
A=[2 3;4 1];
s=A;
for n=1:1:50
s(n)=A.^n;
end
g=[eye(1,1),s];
I am getting the following error:
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in s_x_calcu_v1 (line 5)
s(n)=A.^n;
The problem is that you are trying to assign a matrix to a single element. In matlab calling s(n) mean you get the nth element of s, regardless of the dimensions of s. You can use a three dimensional matrix
N = 50;
A=[2 3;4 1];
[nx,ny] = size(A);
s(nx,ny,N) = 0; %makes s a nx x ny x N matrix
for n=1:1:N
s(:,:,n)=A.^n; %Colon to select all elements of that dimension
end
g=cat(3, eye(size(A)) ,s); %Add the I matrix of same size as A
Or a vectorized version
s = bsxfun(#power, A(:), 1:N);
s = reshape(s,2,2,N);
g = cat(3, eye(size(A)) ,s);
And a third solution using cumprod
s = repmat(A(:), [1 N]);
s = cumprod(s,2);
s = reshape(s,2,2,N);
g = cat(3, eye(size(A)) ,s);
Your s array is a 2-by-2 array, you cannot index it to store the result of your compuation at each step of your loop.
For this, the simpler is probably to define s as a cell:
% --- Definitions
A = [2 3;4 1];
N = 50;
% --- Preparation
s = cell(N,1);
% --- Computation
for n=1:N
s{n} = A.^n;
end
Best,
When you loop from 1 to N computing each time A.^n you are doing LOTS of redundant computations! Note that
A.^n = (A.^(n-1)).*A; %//element-wise power
A^n = (A^n) * A; %// matrix power
Therefore,
A = [2 3;4 1];
N = 50;
s = cell(N+1,1);
s{1} = eye(size(A,1));
for ii=1:N
s{ii+1} = s{ii}.*A; %// no powers, just product!
end
g = vertcat( s{:} );
BTW, the same holds if you want to compute matrix power (instead of element-wise powers), all you need is changing to s{ii+1} = s{ii}*A;
As always trying to learn more from you, I was hoping I could receive some help with the following code.
I need to accomplish the following:
1) I have a vector:
x = [1 2 3 4 5 6 7 8 9 10 11 12]
2) and a matrix:
A =[11 14 1
5 8 18
10 8 19
13 20 16]
I need to be able to multiply each value from x with every value of A, this means:
new_matrix = [1* A
2* A
3* A
...
12* A]
This will give me this new_matrix of size (12*m x n) assuming A (mxn). And in this case (12*4x3)
How can I do this using bsxfun from matlab? and, would this method be faster than a for-loop?
Regarding my for-loop, I need some help here as well... I am not able to storage each "new_matrix" as the loop runs :(
for i=x
new_matrix = A.*x(i)
end
Thanks in advance!!
EDIT: After the solutions where given
First solution
clear all
clc
x=1:0.1:50;
A = rand(1000,1000);
tic
val = bsxfun(#times,A,permute(x,[3 1 2]));
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]);
toc
Output:
Elapsed time is 7.597939 seconds.
Second solution
clear all
clc
x=1:0.1:50;
A = rand(1000,1000);
tic
Ps = kron(x.',A);
toc
Output:
Elapsed time is 48.445417 seconds.
Send x to the third dimension, so that singleton expansion would come into effect when bsxfun is used for multiplication with A, extending the product result to the third dimension. Then, perform the bsxfun multiplication -
val = bsxfun(#times,A,permute(x,[3 1 2]))
Now, val is a 3D matrix and the desired output is expected to be a 2D matrix concatenated along the columns through the third dimension. This is achieved below -
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[])
Hope that made sense! Spread the bsxfun word around! woo!! :)
The kron function does exactly that:
kron(x.',A)
Here is my benchmark of the methods mentioned so far, along with a few additions of my own:
function [t,v] = testMatMult()
% data
%{
x = [1 2 3 4 5 6 7 8 9 10 11 12];
A = [11 14 1; 5 8 18; 10 8 19; 13 20 16];
%}
x = 1:50;
A = randi(100, [1000,1000]);
% functions to test
fcns = {
#() func1_repmat(A,x)
#() func2_bsxfun_3rd_dim(A,x)
#() func2_forloop_3rd_dim(A,x)
#() func3_kron(A,x)
#() func4_forloop_matrix(A,x)
#() func5_forloop_cell(A,x)
#() func6_arrayfun(A,x)
};
% timeit
t = cellfun(#timeit, fcns, 'UniformOutput',true);
% check results
v = cellfun(#feval, fcns, 'UniformOutput',false);
isequal(v{:})
%for i=2:numel(v), assert(norm(v{1}-v{2}) < 1e-9), end
end
% Amro
function B = func1_repmat(A,x)
B = repmat(x, size(A,1), 1);
B = bsxfun(#times, B(:), repmat(A,numel(x),1));
end
% Divakar
function B = func2_bsxfun_3rd_dim(A,x)
B = bsxfun(#times, A, permute(x, [3 1 2]));
B = reshape(permute(B, [1 3 2]), [], size(A,2));
end
% Vissenbot
function B = func2_forloop_3rd_dim(A,x)
B = zeros([size(A) numel(x)], 'like',A);
for i=1:numel(x)
B(:,:,i) = x(i) .* A;
end
B = reshape(permute(B, [1 3 2]), [], size(A,2));
end
% Luis Mendo
function B = func3_kron(A,x)
B = kron(x(:), A);
end
% SergioHaram & TheMinion
function B = func4_forloop_matrix(A,x)
[m,n] = size(A);
p = numel(x);
B = zeros(m*p,n, 'like',A);
for i=1:numel(x)
B((i-1)*m+1:i*m,:) = x(i) .* A;
end
end
% Amro
function B = func5_forloop_cell(A,x)
B = cell(numel(x),1);
for i=1:numel(x)
B{i} = x(i) .* A;
end
B = cell2mat(B);
%B = vertcat(B{:});
end
% Amro
function B = func6_arrayfun(A,x)
B = cell2mat(arrayfun(#(xx) xx.*A, x(:), 'UniformOutput',false));
end
The results on my machine:
>> t
t =
0.1650 %# repmat (Amro)
0.2915 %# bsxfun in the 3rd dimension (Divakar)
0.4200 %# for-loop in the 3rd dim (Vissenbot)
0.1284 %# kron (Luis Mendo)
0.2997 %# for-loop with indexing (SergioHaram & TheMinion)
0.5160 %# for-loop with cell array (Amro)
0.4854 %# arrayfun (Amro)
(Those timings can slightly change between different runs, but this should give us an idea how the methods compare)
Note that some of these methods are going to cause out-of-memory errors for larger inputs (for example my solution based on repmat can easily run out of memory). Others will get significantly slower for larger sizes but won't error due to exhausted memory (the kron solution for instance).
I think that the bsxfun method func2_bsxfun_3rd_dim or the straightforward for-loop func4_forloop_matrix (thanks to MATLAB JIT) are the best solutions in this case.
Of course you can change the above benchmark parameters (size of x and A) and draw your own conclusions :)
Just to add an alternative, you maybe can use cellfun to achieve what you want. Here's an example (slightly modified from yours):
x = randi(2, 5, 3)-1;
a = randi(3,3);
%// bsxfun 3D (As implemented in the accepted solution)
val = bsxfun(#and, a, permute(x', [3 1 2])); %//'
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]);
%// cellfun (My solution)
val2 = cellfun(#(z) bsxfun(#and, a, z), num2cell(x, 2), 'UniformOutput', false);
out2 = cell2mat(val2); % or use cat(3, val2{:}) to get a 3D matrix equivalent to val and then permute/reshape like for out
%// compare
disp(nnz(out ~= out2));
Both give the same exact result.
For more infos and tricks using cellfun, see: http://matlabgeeks.com/tips-tutorials/computation-using-cellfun/
And also this: https://stackoverflow.com/a/1746422/1121352
If your vector x is of lenght = 12 and your matrix of size 3x4, I don't think that using one or the other would change much in term of time. If you are working with higher size matrix and vector, now that might become an issue.
So first of all, we want to multiply a vector with a matrix. In the for-loop method, that would give something like that :
s = size(A);
new_matrix(s(1),s(2),numel(x)) = zeros; %This is for pre-allocating. If you have a big vector or matrix, this will help a lot time efficiently.
for i = 1:numel(x)
new_matrix(:,:,i)= A.*x(i)
end
This will give you 3D matrix, with each 3rd dimension being a result of your multiplication. If this is not what you are looking for, I'll be adding another solution which might be more time efficient with bigger matrixes and vectors.
I need to create a 3-dimensional array from raising all elements of the matrix to different power given by a vector. Is there a way to avoid a loop over the power?
For example, if A is a scalar, I could do
A = 2;
b = 1:10;
C = A.^b;
If A is a vector, I could do
A = [1, 2, 3];
b = 1:10;
C = bsxfun(#power, A, (0:5)');
What can I do if A is a matrix?
Use bsxfun again, but arrange the exponents (b) in a third dimension:
A = [1, 2 3; 4 5 6];
b = 1:10;
C = bsxfun(#power, A, permute(b(:), [2 3 1]));
This gives you a 3D array as result (2x3x10 in this case).
If exponents are consecutive values, the following code may be faster:
n = 10; %// compute powers with exponents 1, 2, ..., n
C = cumprod(repmat(A, [1 1 n]) ,3);
Try like this,
% m & n being the dimensions of matrix A
A = randi(9,[m n]);
P = cat(3,1*ones(m,n),2*ones(m,n),3*ones(m,n));
C = bsxfun(#power, A, P);
I'm trying to calculate the outer product of all rows in a matrix. So far I'm doing the following:
A = rand(10,8);
[N J] = size(A);
for i = 1:N,
B(((i-1)*J+1):J+((i-1)*J),:) = A(i,:)'*A(i,:)
end
I then take the mean of the same elements of the same row in each submatrix created above.
for j=1:J,
C(1:J,j) = accumarray(repmat((1:J)',N,1),B(:,j)).*(1/N);
end
Now this works, but my input matrix will eventually be a number of magnitudes larger, so a vectorized version would be nice. I assume there is some way to do this with permute and bsxfun but the solutions for outer product I have seen so far don't seem to apply here.
Sure. You can compute C directly as
C = mean(bsxfun(#times, permute(A, [2 3 1]), permute(A, [3 2 1])), 3);
Or, if you really need the B variable, you can do it this way:
B_3D = bsxfun(#times, A.', permute(A,[3 1 2])); %'// 3D array
B = reshape(B_3D, numel(A), []);
C = mean(permute(B_3D, [1 3 2]), 3);