I have two matlab questions that seem closely related.
I want to find the most efficient way (no loop?) to multiply a (A x A) matrix with every single matrix of a 3d matrix (A x A x N). Also, I would like to take the trace of each of those products.
http://en.wikipedia.org/wiki/Matrix_multiplication#Frobenius_product
This is the inner frobenius product. On the crappy code I have below I'm using its secondary definition which is more efficient.
I want to multiply each element of a vector (N x 1) with its "corresponding" matrix of a 3d matrix (A x A x N).
function Y_returned = problem_1(X_matrix, weight_matrix)
% X_matrix is the randn(50, 50, 2000) matrix
% weight_matrix is the randn(50, 50) matrix
[~, ~, number_of_matries] = size(X_matrix);
Y_returned = zeros(number_of_matries, 1);
for i = 1:number_of_matries
% Y_returned(i) = trace(X_matrix(:,:,i) * weight_matrix');
temp1 = X_matrix(:,:,i)';
temp2 = weight_matrix';
Y_returned(i) = temp1(:)' * temp2(:);
end
end
function output = problem_2(vector, matrix)
% matrix is the randn(50, 50, 2000) matrix
% vector is the randn(2000, 1) vector
[n1, n2, number_of_matries] = size(matrix);
output = zeros(n1, n2, number_of_matries);
for i = 1:number_of_matries
output(:, :, i) = vector(i) .* matrix(:, :, i);
end
output = sum(output, 3);
end
I assume you mean element-wise multiplication:
Use bsxfun:
A = 10;
N = 4;
mat1 = randn(A,A);
mat2 = randn(A,A,N);
result = bsxfun(#times, mat1, mat2);
Use bsxfun with permute to align dimensions:
A = 10;
N = 4;
vec1 = rand(N,1);
mat2 = randn(A,A,N);
result = bsxfun(#times, permute(vec1,[2 3 1]), mat2);
Related
Assuming a matrix W of dimensions n-by-n which is known, and its elements are positive numbers between 0 and 1.
Assuming also a symbolic vector
k = [a b c d];
I need to randomly multiply each all the non-zero component of W with one at a time of the components of k(randomly), such as e.g.:
What I tried:
k = sym('a', [1 4]);
msize = numel(k);
k(randperm(msize, 1))
for i = 1:length(W)
for j = 1:length(W)
W(i,j) = W(i,j)*(k);
end
end
and the error was the following:
The following error occurred converting from sym to double:
Error using maplemex
Error, (in MTM:-double) cannot handle unevaluated name `a1` in evalhf
First we define the inputs:
% PARAMETERS
% k: symbolic vector of length m
m = 4;
k = sym('a', [1, m]);
% W: n-by-n matrix of doubles
n = 5;
W = rand(n);
Here is the calculation:
% CALCULATION
% random assignment of elements of k to the shape of W
I = randi(m, n);
K = k(I);
% result: element-wise multiplication of K and W
result = K .* W;
Suppose we have a 2D meshgrid with N points (that is N = Nx*Ny, where Nx is the number of grid points in the x axis and Ny is the number of grid points in the y axis) on the grid and we have a 1D domain embedded in our meshgrid which we discretise to have M points.
Now, let A = F(ij)m be a system matrix (for some function F, with a two dimensional parameter), where the i indexes from 1 to Nx, j indexes from 1 to Ny and m indexes from 1 to M.
A is an M x N matrix. So it has M column and N rows. Clearly, implementing the M columns shouldn't be very difficult but I am having trouble envisaging how we'd implement the N rows.
In particular, we would have something like
[F^(11)_1 , F^(11)_2 - F^(11)_1 , .... , F^(11) _M - F^(11) _(M-1)]
[F^(12)_1 , F^(12)_2 - F^(12)_1 , .... , F^(12) _M - F^(12) _(M-1)]
....
[F^(1Ny)_1 , F^(1Ny)_2 - F^(1Ny)_1 , .... , F^(1Ny) _M - F^(1Ny) _(M-1)]
[F^(21)_1 , F^(21)_2 - F^(21)_1 , .... , F^(21) _M - F^(21) _(M-1)]
....
[F^(NxNy)_1 , F^(NxNy)_2 - F^(NxNy)_1 , .... , F^(NxNy) _M - F^(NxNy) _(M-1)]
Thus M columns and N=Nx*Ny rows.
I am trying to implement this on Matlab and I guess it should begin something like:
x = 1:.5:10;
y = 1:.5:10;
[X Y] = meshgrid(x,y); % create mesh grid
Nx = length(x);
Ny = length(y);
N = Nx*Ny; % number of points in our mesh grid
M = 20; % arbitrary choice
Y0 = 5; % fixed y vector
F = besselh(0,2,norm([X Y]-[X(:,m),Y0])); % a 2D function we want to sum over the loop
A = zeros(M,N); % preallocate the memory
for i = 1:Nx
for j = 1:Ny
for m =1:M
A = F(i,j,m);
...
But I don't really have too much of an idea. Maybe a loop isn't even the way to go
Note that for those commenting about the readability I provide a snippet of the mathematical problem I am dealing with (although not all details are important, of course):
Note that rho is a vector on the Euclidean plane and the i and j subscripts represent the x and y component respectively. rho_{x_s,y_s} is just a fixed point in the Euclidean plane and lambda > 0 is a constant.
Here's an example. Your F isn't valid matlab code, so I've replaced it here with a 'toy' function, just to show you the method.
% Parameters
x = 1:.5:10; y = 1:.5:10; [X Y] = meshgrid(x,y); % create mesh grid
Nx = length(x); Ny = length(y); N = Nx * Ny;
M = 20; % arbitrary choice
% Example 'F' Function (here in the form of an 'anonymous function' handle);
F = #(i,j,m) (10*i - 5*j) * m;
% Evaluate F at each i,j,m index and collect as a 3D array.
A = zeros(M, Nx, Ny); % preallocation
for i = 1:Nx, for j = 1:Ny, for m =1:M
A(m, i, j) = F(i, j, m);
end, end, end
A = reshape(A, [M, N]);
A = A.' % transpose to place 'M' dimension as columns and rest as rows.
I have a large matrix of 250-by-200. Inside it are 50-by-50 smaller 5-by-4 matrices.
What is the best way to reshape the matrix so that the 2500 5-by-4 smaller matrices are aligned horizontally to each other? So the large matrix's end dimension should be 5-by-10000.
Matlab's reshape function is pretty handy (and fast), but always reads and writes complete columns. So for your problem, some additional steps are necessary.
Here is how you can do it:
m = 5 % columns of submatrix
n = 4 % rows of submatrix
k = 50 % num submatrixes in matrix column
l = 50 % num submatrixes in matrix row
A = rand(m*k,n*l); % rand(250,200)
Reshape the matrix into a four dimensional matrix (dimensions x1,x2,x3,x4), where each submatrix is located in the x1-x3 plane. The submatrix columns from the original matrix are then in x2 direction, and the submatrix rows in x4 direction.
B = reshape(A,[m,k,n,l]); % [4,50,5,50]
Permute ('transpose') the 4D matrix, so that each submatrix is located in the x1-x2 plane. (reshape first reads columns, then rows, then 3rd dimension, etc.)
C = permute(B,[1,3,4,2]); % For column-wise reshaping, use [1,3,2,4]
Reshape the 4D matrix into the desired 2D output matrix.
D = reshape(C,m,[]);
You can use mat2cell, then reshape and finally get the matrix back with cell2mat. For demonstration purposes, I used variables n and m. They would both be 50 for your matrix.
The following code does it row-wise as you clarified in your comment:
n = 3; % rows
m = 2; % columns
A = reshape(1:20,[5,4]); % generate some data
M = repmat(A,n,m); % create the large matrix
X = mat2cell(M,repmat(5,1,n),repmat(4,1,m))
X = reshape(X.',1,[])
X = cell2mat(X)
Note: reshape operates column-wise. Therefore we need to transpose X with .' or transpose before using reshape as shown in the code above.
Thought I'd add another approach that uses indices and one built-in function zeros. Maybe this way won't have any unnecessary error checks or reshaping operations. Turns out it's more efficient (see below).
%submatrix size
m = 5;
n = 4;
%repeated submatrix rows and cols
rep_rows = 50;
rep_cols = 50;
% big matrix
A = rand(m * rep_rows, n * rep_cols);
% create new matrix
C = zeros(m, (n * rep_cols) * rep_rows);
for k = 1:rep_rows
ind_cols = (n * rep_cols) * (k - 1) + 1: (n * rep_cols) * k;
ind_rows = m * (k - 1) + 1: m * k;
C(:, ind_cols) = A(ind_rows, :);
end
I decided to time the three answers here and found this approach to be significantly faster. Here is the test code:
% Bastian's approach
m = 5; % columns of submatrix
n = 4; % rows of submatrix
k = 50; % num submatrixes in matrix column
l = 50; % num submatrixes in matrix row
A = rand(m*k,n*l); % rand(250,200)
% start timing
tic
B = reshape(A,[m,k,n,l]); % [4,50,5,50]
C = permute(B,[1,3,4,2]); % For column-wise reshaping, use [1,3,2,4]
D = reshape(C,m,[]);
toc
% stop timing
disp(' ^^^ Bastian');
% Matt's approach
n = 50; % rows
m = 50; % columns
% start timing
tic
X = mat2cell(A,repmat(5,1,n),repmat(4,1,m));
X = reshape(X.',1,[]);
X = cell2mat(X);
toc
% stop timing
disp(' ^^^ Matt');
% ChisholmKyle
m = 5;
n = 4;
rep_rows = 50;
rep_cols = 50;
% start timing
tic
C = zeros(m, (n * rep_cols) * rep_rows);
for k = 1:rep_rows
ind_cols = (n * rep_cols) * (k - 1) + 1: (n * rep_cols) * k;
ind_rows = m * (k - 1) + 1: m * k;
C(:,ind_cols) = A(ind_rows, :);
end
toc
% stop timing
disp(' ^^^ this approach');
Here is the output on my machine:
Elapsed time is 0.004038 seconds.
^^^ Bastian
Elapsed time is 0.020217 seconds.
^^^ Matt
Elapsed time is 0.000604 seconds.
^^^ this approach
I have a vector y of length n. y(i) is an integer in 1..m. Is there a simpler way to convert y into an n x m logical matrix yy, where yy(i, j) = 1 if y(i) = j, but 0 otherwise? Here's how I've been doing it:
% If m is known (m = 3 here), you could write it out all at once
yy = [y == 1; y== 2; y == 3];
yy = reshape(yy, n, 3);
or
% if m is not known ahead of time
yy = [ y == 1 ];
for i = 2:m;
yy = [ yy; y == i ];
end
yy = reshape(yy, n, m);
You can use bsxfun for this
yy = bsxfun(#eq,y(:),[1,2,3])
y is transformed (if necessary) to a column-vector, while the other vector is a row vector. bsxfun implicitly expands the m-by-1 and 1-by-n arrays so that the result becomes m-by-n.
If n*m is sufficiently large (and m is, by itself, sufficiently large), it is a good idea to create yy as a sparse matrix. Your y vector is really a special type of sparse matrix format, but we can translate it into the built-in sparse matrix format by doing the following.
yy = sparse(1:length(y), y, 1);
This will keep your storage to O(n). It is not going to be doing you a lot of favors if you are using yy for a lot of indexing. If that is the case you are better off using your original sparse structure (i.e., y).
A slight modification to your method:
% A n-dimensional vector y, with values in some range 1..m
m = 4;
n = 7;
y = randi([1 m], n, 1);
% Preallocating a n by m matrix of zeros
nXm = zeros(n, m);
% In each pass of this loop a single column of nXm is updated, where
% for each column index j in nXm, if y(i) = j then nXm(i,j) = 1
for j = 1:m;
nXm(:,j) = (y == j);
end
From Machine Learning on Coursera:
yy = eye(m)(y, :)
This requires that the list be a range 1:m (as OP stated). For an irregular list, like [2 3 5], do this
yy = eye(m)(:, [2 3 5])(y, :)
Note: not tested on MATLAB.
In octave you can write:
yy = y' == (1:m); % or y == (1:m)' for transposed
[1 2 1 3 2] == [1 2 3]' % = [1 0 1 0 0; 0 1 0 0 1; 0 0 0 1 0]
I have double summation over m = 1:M and n = 1:N for polar point with coordinates rho, phi, z:
I have written vectorized notation of it:
N = 10;
M = 10;
n = 1:N;
m = 1:M;
rho = 1;
phi = 1;
z = 1;
summ = cos (n*z) * besselj(m'-1, n*rho) * cos(m*phi)';
Now I need to rewrite this function for accepting vectors (columns) of coordinates rho, phi, z. I tried arrayfun, cellfun, simple for loop - they work too slow for me. I know about "MATLAB array manipulation tips and tricks", but as MATLAB beginner I can't understand repmat and other functions.
Can anybody suggest vectorized solution?
I think your code is already well vectorized (for n and m). If you want this function to also accept an array of rho/phi/z values, I suggest you simply process the values in a for-loop, as I doubt any further vectorization will bring significant improvements (plus the code will be harder to read).
Having said that, in the code below, I tried to vectorize the part where you compute the various components being multiplied {row N} * { matrix N*M } * {col M} = {scalar}, by making a single call to the BESSELJ and COS functions (I place each of the row/matrix/column in the third dimension). Their multiplication is still done in a loop (ARRAYFUN to be exact):
%# parameters
N = 10; M = 10;
n = 1:N; m = 1:M;
num = 50;
rho = 1:num; phi = 1:num; z = 1:num;
%# straightforward FOR-loop
tic
result1 = zeros(1,num);
for i=1:num
result1(i) = cos(n*z(i)) * besselj(m'-1, n*rho(i)) * cos(m*phi(i))';
end
toc
%# vectorized computation of the components
tic
a = cos( bsxfun(#times, n, permute(z(:),[3 2 1])) );
b = besselj(m'-1, reshape(bsxfun(#times,n,rho(:))',[],1)'); %'
b = permute(reshape(b',[length(m) length(n) length(rho)]), [2 1 3]); %'
c = cos( bsxfun(#times, m, permute(phi(:),[3 2 1])) );
result2 = arrayfun(#(i) a(:,:,i)*b(:,:,i)*c(:,:,i)', 1:num); %'
toc
%# make sure the two results are the same
assert( isequal(result1,result2) )
I did another benchmark test using the TIMEIT function (gives more fair timings). The result agrees with the previous:
0.0062407 # elapsed time (seconds) for the my solution
0.015677 # elapsed time (seconds) for the FOR-loop solution
Note that as you increase the size of the input vectors, the two methods will start to have similar timings (the FOR-loop even wins on some occasions)
You need to create two matrices, say m_ and n_ so that by selecting element i,j of each matrix you get the desired index for both m and n.
Most MATLAB functions accept matrices and vectors and compute their results element by element. So to produce a double sum, you compute all elements of the sum in parallel by f(m_, n_) and sum them.
In your case (note that the .* operator performs element-wise multiplication of matrices)
N = 10;
M = 10;
n = 1:N;
m = 1:M;
rho = 1;
phi = 1;
z = 1;
% N rows x M columns for each matrix
% n_ - all columns are identical
% m_ - all rows are identical
n_ = repmat(n', 1, M);
m_ = repmat(m , N, 1);
element_nm = cos (n_*z) .* besselj(m_-1, n_*rho) .* cos(m_*phi);
sum_all = sum( element_nm(:) );