Suppose I have a matrix A of dimension Nx(N-1) in MATLAB, e.g.
N=5;
A=[1 2 3 4;
5 6 7 8;
9 10 11 12;
13 14 15 16;
17 18 19 20 ];
I want to transform A into an NxN matrix B, just by adding a zero diagonal, i.e.,
B=[ 0 1 2 3 4;
5 0 6 7 8;
9 10 0 11 12;
13 14 15 0 16;
17 18 19 20 0];
This code does what I want:
B_temp = zeros(N,N);
B_temp(1,:) = [0 A(1,:)];
B_temp(N,:) = [A(N,:) 0];
for j=2:N-1
B_temp(j,:)= [A(j,1:j-1) 0 A(j,j:end)];
end
B = B_temp;
Could you suggest an efficient way to vectorise it?
You can do this with upper and lower triangular parts of the matrix (triu and tril).
Then it's a 1 line solution:
B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
Edit: benchmark
This is a comparison of the loop method, the 2 methods in Sardar's answer, and my method above.
Benchmark code, using timeit for timing and directly lifting code from question and answers:
function benchie()
N = 1e4; A = rand(N,N-1); % Initialise large matrix
% Set up anonymous functions for input to timeit
s1 = #() sardar1(A,N); s2 = #() sardar2(A,N);
w = #() wolfie(A,N); u = #() user3285148(A,N);
% timings
timeit(s1), timeit(s2), timeit(w), timeit(u)
end
function sardar1(A, N) % using eye as an indexing matrix
B=double(~eye(N)); B(find(B))=A.'; B=B.';
end
function sardar2(A,N) % similar to sardar1, but avoiding slow operations
B=1-eye(N); B(logical(B))=A.'; B=B.';
end
function wolfie(A,N) % using triangular parts of the matrix
B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
end
function user3285148(A, N) % original looping method
B = zeros(N,N); B(1,:) = [0 A(1,:)]; B(N,:) = [A(N,:) 0];
for j=2:N-1; B(j,:)= [A(j,1:j-1) 0 A(j,j:end)]; end
end
Results:
Sardar method 1: 2.83 secs
Sardar method 2: 1.82 secs
My method: 1.45 secs
Looping method: 3.80 secs (!)
Conclusions:
Your desire to vectorise this was well founded, looping is way slower than other methods.
Avoiding data conversions and find for large matrices is important, saving ~35% processing time between Sardar's methods.
By avoiding indexing all together you can save a further 20% processing time.
Generate a matrix with zeros at diagonal and ones at non-diagonal indices. Replace the non-diagonal elements with the transpose of A (since MATLAB is column major). Transpose again to get the correct order.
B = double(~eye(N)); %Converting to double since we want to replace with double entries
B(find(B)) = A.'; %Replacing the entries
B = B.'; %Transposing again to get the matrix in the correct order
Edit:
As suggested by Wolfie for the same algorithm, you can get rid of conversion to double and the use of find with:
B = 1-eye(N);
B(logical(B)) = A.';
B = B.';
If you want to insert any vector on a diagonal of a matrix, one can use plain indexing. The following snippet gives you the indices of the desired diagonal, given the size of the square matrix n (matrix is n by n), and the number of the diagonal k, where k=0 corresponds to the main diagonal, positive numbers of k to upper diagonals and negative numbers of k to lower diagonals. ixd finally gives you the 2D indices.
function [idx] = diagidx(n,k)
% n size of square matrix
% k number of diagonal
if k==0 % identity
idx = [(1:n).' (1:n).']; % [row col]
elseif k>0 % Upper diagonal
idx = [(1:n-k).' (1+k:n).'];
elseif k<0 % lower diagonal
idx = [(1+abs(k):n).' (1:n-abs(k)).'];
end
end
Usage:
n=10;
k=3;
A = rand(n);
idx = diagidx(n,k);
A(idx) = 1:(n-k);
Related
I am fairly new to Matlab and have been trying to solve this issue for some weeks.
I have several large matrices, which vary in their amount of rows, although all have 69 columns. Within these matrices are 23 xyz values, e.g. column 1,2,3 are the x,y,z values for point 1, column 4,5,6 the x,y,z values for point 2 and so on, up to column 69.
There are over 1000 rows for each matrix, with each row representing a point in time.
I am trying to use a for loop to calculate the difference between row 1 and 2, then row 2 and 3, then 3 and 4 etc, using pythagoras theorem.
Essentially, the end output should be a N*23 matrix of the distance values but I'm getting stuck on generating the for loop.
I've been trying to solve this using a smaller 4*3 array for the meantime, (n is the matrix) with no luck.
for i = 1:row
for j = 1:col
pythag(i,j) = sqrt((n(i,1)-n(j,1))^2 +((n(i,2)-n(j,2))^2 +((n(i,3)-n(j,3))^2)));
end
end
Any help would be appreciated.
You can actually solve the problem in a single line of code.
The end output should be (N-1)*23 and not N*23 matrix.
In your loop, the column index in n should be advanced by 3 for each advancement of j.
You also need to subtract row i+1 from row i.
I renamed your matrix n with A.
Here is a sample solution using a for loop (please read the comments):
%I have a large number of N*69 matrices
%Within these matrices are 23 xyz values, e.g. column 1,2,3 are the x,y,z values for point 1, column 4,5,6 the x,y,z values for point 2 and so on, up to column 69.
%One row:
%A = [x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4]; %For example take 4 xyz values (instead of 23)
%There are over 1000 rows for each matrix,
%Example include 4 rows:
% A = [x11, y11, z11, x12, y12, z12, x13, y13, z13, x14, y14, z14;...
% x21, y21, z21, x22, y22, z22, x23, y23, z23, x24, y24, z24;...
% x31, y31, z31, x32, y32, z32, x33, y33, z33, x34, y34, z34;...
% x41, y41, z41, x42, y42, z42, x43, y43, z43, x44, y44, z44];
%Initialize A with arbitrary values (I decided to name the matrix A instead of n).
A = [magic(4) magic(4) magic(4)];
% A = [16 2 3 13 16 2 3 13 16 2 3 13
% 5 11 10 8 5 11 10 8 5 11 10 8
% 9 7 6 12 9 7 6 12 9 7 6 12
% 4 14 15 1 4 14 15 1 4 14 15 1];
%Calculate the difference between row 1 and 2, then row 2 and 3, then 3 and 4
%Essentially, the end output should be a N*23 matrix. Wrong!!! it should be (N-1)*23 matrix
%Assume N is the number of rows (over 1000 rows).
N = size(A, 1);
%Size of pythag matrix is (N-1)x(69/3) and in the example size is 3x4
row = N-1;
col = size(A,2)/3;
%Initialize output matrix with zeros.
pythag = zeros(row, col);
%Solving using a nested for loops:
for i = 1:row
%k, k+1, k+2 are the x,y,z, columns indeces in matrix A
k = 1;
for j = 1:col
%pythag(i,j) = sqrt((n(i,1)-n(j,1))^2 +((n(i,2)-n(j,2))^2 +((n(i,3)-n(j,3))^2)));
%We want the to distance from row i+1 to row i (in matrix A).
pythag(i, j) = sqrt((A(i+1, k)-A(i, k))^2 +((A(i+1, k+1)-A(i, k+1))^2 +((A(i+1, k+2)-A(i, k+2))^2)));
% | | |
% x y z
%The column index in A must skip by 3 for each increment of j
k = k + 3;
end
end
More elegant: replacing the sqrt(x^2 + y^2 + z^2) with norm([x,y,z]):
for i = 1:row
%k, k+1, k+2 are the x,y,z, columns indices in matrix A
k = 1;
for j = 1:col
%We want the to distance from row i+1 to row i (in matrix A).
pythag(i, j) = norm([A(i+1, k) - A(i, k), A(i+1, k+1) - A(i, k+1), A(i+1, k+2) - A(i, k+2)]);
%The column index in A must skip by 3 for each increment of j
k = k + 3;
end
end
Vectorizing the inner loop (use vecnorm instead of norm):
for i = 1:row
pythag(i, 1:col) = vecnorm([A(i+1, 1:3:end) - A(i, 1:3:end); A(i+1, 2:3:end) - A(i, 2:3:end); A(i+1, 3:3:end) - A(i, 3:3:end)]);
end
Vectorizing the outer loop (too confusing with vecnorm - back to Pythagoras):
pythag = sqrt((A(2:end, 1:3:end)-A(1:end-1, 1:3:end)).^2 +((A(2:end, 2:3:end)-A(1:end-1, 2:3:end)).^2 +((A(2:end, 3:3:end)-A(1:end-1, 3:3:end)).^2)));
Make use of the full power of Matlab using vector-wise calculations: you can omit the inner loop and calculate the distance immediately for a vector information (note that you need to provide the direction of the sum()).
Matlab stores all data in the RAM consistency, i.e. it will sometimes have to copy the vector to a different location in the RAM as it grows. Therefore, allocate the full space right at the start e.g. with NaN().
% allocate memory
pythag = NaN(row,col);
for i = 1:row
pythag(i,:) = sqrt(sum( (n(i,1:3)-n(:,1:3)).^2,2 ));
end
If you provide a minimal working example, we can check your full code and walk you through the problem.
I have a sparse parity check matrix (consisting of ones and zeros) and I would need to replace each nonzero element (ones) from it by PM: a squared permutation matrix of dimension N (being N generally a large integer). In the case of the zero elements, these would be replaced by squared null matrices of the same dimension.
Let me share with you which the current state of my code is:
This is the base matrix in which I would like to replace its ones by permutation matrices:
B = zeros((L + ms) * dc, L * dv);
for i = 1 : 1 : L
for j = 1 : 1 : dv
B(dc*(i-1)+1 : dc*(ms+i), j+dv*(i-1)) = ones(dc*(ms+1), 1);
end
end
I have been told a way for doing so by using 'cell' objects, this is, initializing H as an array of empty cells that would contain the corresponding submatrices:
H=repmat({{}},size(B));
Mc = 500 % Dimension of the permutation matrix
MP=randi([1,5],Mc,Mc); % Definition of one permutation matrix
% It would be desirable that the permutation matrix is different for each replacement
[H{B==0}]=deal(zeros(Mp));
[H{B==1}]=deal(MP);
But there's one problem coming up -that I would need this matrix to be used as a parameter of a following function and it would be very much desirable that it were a simple matrix of ones and zeros (as I am not very familiar with 'cell' structures... however, as you can see, Mc is such a big integer that I don't know if that would be possible to be handled.
Do you have any other way of doing so to have a raw matrix of dimensions (L*ms)dcMc, LdvMc as output?
These are some parameters that could be used to have a try:
ms = 2;
Mc = 600; % any number (specially big ones) could serve for this purpose
dc = 3;
dv = 4;
L = 15;
Many thanks in advance for your attention, and may you have a nice day.
This is how it can be done with cells:
B = Randi([0,1], m, n); % m*n array of 1s and 0s
H = cell(size(B)); % Define cell array
Mc = 500; % Size of replacement matrices
MP = randi([1,5], Mc, Mc); % Permutation matrix
H(B==0) = {zeros(Mc, Mc)}; % Set elements of H where B==0 to matrix of zeros
H(B==1) = {MP}; % Set elements of H where B==1 to permutation matrix
% Convert to matrix
Hmat = cell2mat(H); % Hmat = Mc*m row by Mc*n column matrix
Each cell element holds a matrix of size Mc*Mc, at the end this can be converted to one large matrix. Take care which sorts of brackets you use with cells, the parentheses () are for logical indexing, whilst the curly braces {} are for assigning the sub-matrixes as cell elements.
Example:
B = [1 0; 1 1];
MP = [1 2; 3 4];
H(B==0) = {zeros(2, 2)};
H(B==1) = {MP};
Hmat = cell2mat(H);
% >> Hmat = [1 2 0 0
% 3 4 0 0
% 1 2 1 2
% 3 4 3 4];
If you want the replacement matrix MP to change, you will have to do this in a loop, changing MP on each iteration and using it to replace one element of H.
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 am trying to write code to get the 'N-dimensional product' of vectors. So for example, if I have 2 vectors of length L, x & y, then the '2-dimensional product' is simply the regular vector product, R=x*y', so that each entry of R, R(i,j) is the product of the i'th element of x and the j'th element of y, aka R(i,j)=x(i)*y(j).
The problem is how to elegantly generalize this in matlab for arbitrary dimensions. This is I had 3 vectors, x,y,z, I want the 3 dimensional array, R, such that R(i,j,k)=x(i)*y(j)*z(k).
Same thing for 4 vectors, x1,x2,x3,x4: R(i1,i2,i3,i4)=x1(i1)*x2(i2)*x3(i3)*x4(i4), etc...
Also, I do NOT know the number of dimensions beforehand. The code must be able to handle an arbitrary number of input vectors, and the number of input vectors corresponds to the dimensionality of the final answer.
Is there any easy matlab trick to do this and avoid going through each element of R specifically?
Thanks!
I think by "regular vector product" you mean outer product.
In any case, you can use the ndgrid function. I like this more than using bsxfun as it's a little more straightforward.
% make some vectors
w = 1:10;
x = w+1;
y = x+1;
z = y+1;
vecs = {w,x,y,z};
nvecs = length(vecs);
[grids{1:nvecs}] = ndgrid(vecs{:});
R = grids{1};
for i=2:nvecs
R = R .* grids{i};
end;
% Check results
for i=1:10
for j=1:10
for k=1:10
for l=1:10
V(i,j,k,l) = R(i,j,k,l) == w(i)*x(j)*y(k)*z(l);
end;
end;
end;
end;
all(V(:))
ans = 1
The built-in function bsxfun is a fast utility that should be able to help. It is designed to perform 2 input functions on a per-element basis for two inputs with mismatching dimensions. Singletons dimensions are expanded, and non-singleton dimensions need to match. (It sounds confusing, but once grok'd it useful in many ways.)
As I understand your problem, you can adjust the dimension shape of each vector to define the dimension that it should be defined across. Then use nested bsxfun calls to perform the multiplication.
Example code follows:
%Some inputs, N-by-1 vectors
x = [1; 3; 9];
y = [1; 2; 4];
z = [1; 5];
%The computation you describe, using nested BSXFUN calls
bsxfun(#times, bsxfun(#times, ... %Nested BSX fun calls, 1 per dimension
x, ... % First argument, in dimension 1
permute(y,2:-1:1) ) , ... % Second argument, permuited to dimension 2
permute(z,3:-1:1) ) % Third argument, permuted to dimension 3
%Result
% ans(:,:,1) =
% 1 2 4
% 3 6 12
% 9 18 36
% ans(:,:,2) =
% 5 10 20
% 15 30 60
% 45 90 180
To handle an arbitrary number of dimensions, this can be expanded using a recursive or loop construct. The loop would look something like this:
allInputs = {[1; 3; 9], [1; 2; 4], [1; 5]};
accumulatedResult = allInputs {1};
for ix = 2:length(allInputs)
accumulatedResult = bsxfun(#times, ...
accumulatedResult, ...
permute(allInputs{ix},ix:-1:1));
end