I know that writing a for loop in Matlab is typically not efficient.
Now I am trying to replace a nested for loop with a better option.
Here is the nested loop,
for i = 1: size(A,1)
for j = 1: size(B,1)
S(i,j, :) = c*(A(i,:)*a - B(j,:)*b);
end
end
What operation should I use? (I was thinking about Cartesian product implementation)
Try the following
AA = permute(A * a, [1, 3, 2]);
BB = permute(B * b, [3, 1, 2]);
CC = c * bsxfun(#minus, AA, BB);
nA = size(A,1);
nB = size(B,1);
Ar = repmat(A, nB, 1); %// repeat A along rows
Br = B(ceil(1/nA:1/nA:nB), :); %// stretch B along rows
S = c*(Ar*a-Br*b); %// do the computations
S = reshape(permute(S, [1 3 2]), nA, nB, []); %// put into shape
A=(1:20)'*ones(1,10);
size(A) % 20,10
a=ones(10,1)*(1:5);
size(a) %10,5
B=ones(3,1)*(1:20);
size(B) %3,20
b=ones(20,1)*(1:5);
size(b) %20,5
c=1;
Aa=A*a;
size(Aa) %20,5
Bb=B*b;
size(Bb) %3,5
na=size(Aa,1);
nb=size(Bb,1);
Ia=(1:na)'* ones(1,nb);
%Ia=1;2;3..nb;1;2;3..nb na times
Ia=reshape(Ia,na*nb,1);
%Ib=1;1;natimes;2;2;2 natimes...nb;nb;nb...natimes
Ib=ones(na,1)*(1:nb);
Ib=reshape(Ib,na*nb,1);
S=(Aa(Ia,:)-Bb(Ib,:))*c;
S=reshape(S,[na nb size(Aa,2)]);
Related
I have a NxNx4 matrix(A) and a 4x4 matrix (B). I need to multiply the vector a composed by the four elements of the first matrix A, let's say
a = A(1,1,1)
A(1,1,2)
A(1,1,3)
A(1,1,4)
by the 4x4 matrix B but I'm not sure if there is a faster and clever solution than using a for loop to build the vector a. Does exist a way to do this computation with few lines of code?
I built A like
A(:,:,1) = rand(20);
A(:,:,2) = rand(20);
A(:,:,3) = rand(20);
A(:,:,4) = rand(20);
and the matrix B
B = rand(4);
now I want to multiply B with
B*[A(1,1,1);A(1,1,2);A(1,1,3);A(1,1,4)]
This, for each element of A
B*[A(1,2,1);A(1,2,2);A(1,2,3);A(1,2,4)]
B*[A(1,3,1);A(1,3,2);A(1,3,3);A(1,3,4)]
...
You can do this with a simple loop, note loops aren't necessarily slow in newer MATLAB versions. Mileage may vary.
Loops have the advantage of improving code readability, it's extremely clear what's happening here:
% For matrix A of size N*N*4
C = zeros( size( A ) );
for ii = 1:N
for jj = 1:N
C( ii, jj, : ) = B * reshape( A( ii, jj, : ), [], 1 );
end
end
A loop solution that has good performance specially when N is large:
s = size(A, 3);
C = A(:,:,1) .* reshape(B(:,1),1,1,[]);
for k = 2:s
C = C + A(:,:,k) .* reshape(B(:,k),1,1,[]);
end
I think this does what you want:
C = permute(sum(bsxfun(#times, permute(B, [3 4 2 1]), A), 3), [1 2 4 3]);
Check:
>> C(1,2,:)
ans(:,:,1) =
1.501739582138850
ans(:,:,2) =
1.399465238902816
ans(:,:,3) =
0.715531734553844
ans(:,:,4) =
1.617019921519029
>> B*[A(1,2,1);A(1,2,2);A(1,2,3);A(1,2,4)]
ans =
1.501739582138850
1.399465238902816
0.715531734553844
1.617019921519029
Here is what I want, a 3-D matrix:
K = 2:2.5:10;
den = zeros(1,4,4);
for i = 1:1:4
den(:,:,i) = [1, 5, K(i)-6, K(i)];
end
Or, a cell array is also acceptable:
K = 2:2.5:10;
for i = 1:1:4
den{i} = [1, 5, K(i)-6, K(i)];
end
But I want to know if there is a more efficient way of doing this using vectorized code like:
K = 2:2.5:10;
den = [1, 5, K-6, K];
I know the last code will not get what I wanted. But, like I can use:
v = [1 2 3];
v2 = v.^2;
instead of:
v = [1 2 3];
for i = 1:length(v)
v(i) = v(i)^2;
end
to get the matrix I want. Is there a similar way of doing this so that I can get the 3-D matrix or cell array I mentioned at the beginning more efficiently?
You need to "broadcast" the scalar values in columns so they are of the same length as your K vector. MATLAB does not do this broadcasting automatically, so you need to repeat the scalars and create vectors of the appropriate size. You can use repmat() for this.
K = 2:2.5:10;
%% // transpose K to a column vector:
K = transpose(K);
%% // helper function that calls repmat:
f = #(v) repmat(v, length(K), 1);
%% // your matrix:
den = [f(1) f(5) K-6 K];
This should be more optimized for speed but requires a bit more intermediary memory than the loop does.
Just use reshape with a 1*3 size:
den = reshape([ones(1,length(K));ones(1,length(K))*5; K-6; K],[1 4 length(K)]);
I think the used extra memory by reshape should be low and constant (dependent only on the length of the vector of new sizes).
You can use the classic line equation y=a*x+b, extended to the matrix form:
k = 2:2.5:10 ;
fa = [0 0 1 1].' ; %' // "a" coefficients
fb = [1 5 -6 0].' ; %' // "b" coefficients
d(1,:,:) = fa*k + fb*ones(1,4) ;
The above is better for clarity, but if you're not bothered you can also pack everything in one line:
d(1,:,:) = [0 0 1 1].' * (2:2.5:10) + [1 5 -6 0].' * ones(1,4) ;
If you need to re-use the principle for many different values of k, then you can use an anonymous function to help:
fden = #(k) [0 0 1 1].' * k + [1 5 -6 0].' * ones(1,4) ; %// define anonymous function
k = 2:2.5:10 ;
d(1,:,:) = fden(k) ; %// use it for any value of "k"
Assuming
A=[32512199.30 5401000.29 347.33
32512199.69 5401000.45 347.39
32512199.67 5401001.32 353.58
32512199.96 5401001.50 346.99
32512196.71 5401001.69 346.62 ]
and
B=[32512199.30 5401000.29 347.33
32512199.69 5401000.45 347.39
32512199.67 5401001.32 347.00
32512198.85 5401000.91 347.25
32512196.71 5401001.69 346.87 ]
I want using ismember extract the rows that have same X and Y and different Z. X is first column, Y is the second and Z is third.
in A and B I want extract from A 32512199.67 5401001.32 353.58 and 32512196.71 5401001.69 346.62 OR from B 32512199.67 5401001.32 347.00 and 32512196.71 5401001.69 346.87
How can I do it?
inds = find(~ismember(A, B, 'rows'));
new_inds = find(ismember(A(inds, 1:2), B(:, 1:2), 'rows'));
inds(new_inds)
First find the row indices of desired match using ismember and find. Then extract those rows from A/B to XA/XB
row_idx = find ( ismember( ismember(A,B), [1 1 0], 'rows') )
XA = A(row_idx,:)
XB = B(row_idx,:)
Output:
row_idx =
3
5
XA =
3.2512e+07 5.4010e+06 3.5358e+02
3.2512e+07 5.4010e+06 3.4662e+02
XB =
3.2512e+07 5.4010e+06 3.4700e+02
3.2512e+07 5.4010e+06 3.4687e+02
I am having trouble with the following task:
Suppose a 3x6 matrix:
A =
0.2787 0.2948 0.4635 0.8388 0.0627 0.0435
0.6917 0.1185 0.3660 0.1867 0.2383 0.7577
0.6179 0.7425 0.0448 0.4009 0.9377 0.4821
What I would like to do is to divide the matrix into blocks, like this:
A =
0.2787 0.2948 | 0.4635 0.8388 | 0.0627 0.0435
0.6917 0.1185 | 0.3660 0.1867 | 0.2383 0.7577
0.6179 0.7425 | 0.0448 0.4009 | 0.9377 0.4821
and vertically concatenate these blocks to get the final result:
0.2787 0.2948
0.6917 0.1185
0.6179 0.7425
0.4635 0.8388
0.3660 0.1867
0.0448 0.4009
0.0627 0.0435
0.2383 0.7577
0.9377 0.4821
I think if I can get help with this, then I can perhaps
do it for arbitrary matrices A. I can solve the above
problem using for-loops, but I am looking for a vectorised solution.
Thanks in advance!
N.
Consider the following:
A = rand(3,6);
blkSz = 2;
C = mat2cell(A, size(A,1), blkSz*ones(1,size(A,2)/blkSz));
C = cat(1,C{:})
This assumes that size(A,2) is evenly divisible by blkSz
This works where your matrix is A and what you want is D
C = mat2cell(A,[3],[2 2 2])
D = cat(1,C{:})
It's possible to do it without cell2mat, (only with reshapes and permute) and thus a lot faster!
You need to use the "3rd dimension". It's similar to what is described in
split long 2D matrix into the third dimension.
Here is the solution for the above matrix:
A1 = reshape(A, 3, 2, []); % 3rd dimension is numel(A)/2/3
A2 = permute(A1, [2 1 3]); % transpose 1st and 2nd dimension
Ans= reshape(A2, 2, [])' ; % note the transpose
For a matrix of this size, the difference in running time is negligible. However, for a large matrix, the difference is more than an order of magnitude:
A=rand(3, 2*10000);
%% good method
tic
A1 = reshape(A, 3, 2, []); %3rd dimension is numel(A)/2/3
A2 = permute(A1, [2 1 3]);
A3 = reshape(A2, 2, [])' ; %note the transpose'
toc
%% mat2cell method
tic
blkSz = 2;
C = mat2cell(A, size(A,1), blkSz*ones(1,size(A,2)/blkSz));
B3 = cat(1,C{:});
toc
%% make sure the answer is the same:
assert(max(A3(:)-B3(:))==0)
output:
>> Elapsed time is 0.001202 seconds.
>> Elapsed time is 0.043115 seconds.
How about this:
width = 2;
m = length(A(:))/width;
fn = #(i) reshape(A(:, i:width:end), m, 1);
B = cell2mat(arrayfun(fn, 1:width, 'UniformOutput', false));
Just specify how many columns you want at a time in the width variable.
By concatenating vertically, matrix width divisible by 3 assumed:
B = [ A(:,1:(size(A,2)/3)); A(:,size(A,2)/3+1:size(A,2)/3*2); A(:,size(A,2)/3*2+1:end) ];
I know this is a simple question but difficult to formulate in one sentence to google the answer.So, I have a 3d matrix with size 2x2x3 like this
A(:,:,1) =[1 1; 1 1];
A(:,:,2) =[2 2; 2 2];
A(:,:,3) =[4 4; 4 4];
and matrix B with size 2x2
B = [ 1 2; 2 3];
What i need is to chose from each third dimension in A just one number using matrix B:
for i=1:2,
for j=1:2,
C(i,j) = A(i,j,B(i,j));
end
end
How to that in one line without a loop?
Not really a single line, but without a loop:
[I J] = ind2sub (size(B), 1:numel(B));
linInd = sub2ind (size (A), I, J, B(:)');
C = reshape (A(linInd), size(B));
Here is another variation:
[r,c,~] = size(A);
[J,I] = meshgrid(1:size(B,1), 1:size(B,2));
idx = reshape(I(:) + r*(J(:)-1) + r*c*(B(:)-1), size(B));
C = A(idx)