Is it possible to use mldivide "\" on a 3D matrix in Matlab - matlab

Is it possible to use mldivide (\) on a 3D matrix in MATLAB? I would like to avoid using a for loop?
Sample:
A = rand(4, 100, 5);
B = rand(4,4);
I need to perform:
C = B\A;
What I'm doing now:
Apply the mldivide on a for loop for each "slice" i:
for i = 1:size(A, 3)
C(:,:,i) = B \ A(:,:,i);
end

You can reshape A into a 2D matrix to perform the division and then back to the expected size afterwards. The reshape operations should be relatively quick due to the fact that MATLAB doesn't alter the underlying data.
C = reshape(B \ reshape(A, size(A, 1), []), size(B, 1), size(A, 2), []);
And if we break that down:
%// Reshape A to be 4 x 500
Anew = reshape(A, size(A, 1), []);
%// Perform left division
C = B \ Anew;
%// Reshape C to be the expected size (4 x 100 x 5)
C = reshape(C, size(B, 1), size(A, 2), []);
This should work for any valid (size(A, 1) == size(B, 2)) matrices A and B of any size.

Related

Multiply n vectors of length p by n matrices of size pxp

I have n complex vectors of length p that I want to multiply by n complex matrices of size p-by-p. I am looking for the most efficient way to do this in MATLAB. If it matters, I am imagining that n is large and p is small.
An example using a loop (which I would like to avoid) is shown below.
N = 1e4;
p = 5;
A = randn(p, N); % N vectors of length p
B = randn(p, p, N); % N matrices of size pxp
C = zeros(p, N);
for k = 1:N
C(:, k) = B(:, :, k) * A(:, k);
end
It's been suggested that I might be able to achieve this efficiently using tensor functions, but I haven't been able to figure that out.
Here's a way using implicit expansion:
C = permute(sum(B.*permute(A, [3 1 2]), 2), [1 3 2]);
For old Matlab versions (before R2016b) you need to rewrite it with bsxfun:
C = permute(sum(bsxfun(#times, B, permute(A, [3 1 2])), 2), [1 3 2]);
You can accomplish that in various ways:
A = rand(3, 3, 1e6);
B = rand(3, 1);
tic, C = zeros(3, size(A, 3));
for i = 1:size(A, 3)
C(:,i) = A(:,:,i)*B ;
end, toc
tic; C = reshape(reshape(permute(A,[2,1,3]),3,[]).'*B,3,[]); toc
tic; C = squeeze(sum(bsxfun(#times, A, reshape(B, 1, 3)), 2)); toc
In my system:
Elapsed time is 2.067629 seconds. % Loop
Elapsed time is 0.064164 seconds. % permute
Elapsed time is 0.145738 seconds % sum(times())

Multidimensional Matrix Multiplication

I'm wondering if it is possible to perform a multidimensional matrix multiplication without resorting to a for-loop. Given the N-by-P matrix A and the N-by-M-by-P matrix B, I want to compute the M-dimensional vector y, defined element-wise as
y(j) = sum_(i = 1,...,N) sum_(k = 1,...,P) A(i,k)*B(i,j,k)
You can linearize A into a row vector, then reshape and permute the array B as a matrix, so that the desired result is just matrix multiplication:
M = 5;
N = 6;
P = 8;
A = rand(N,P);
B = rand(N,M,P);
result = A(:).'*reshape(permute(B, [1 3 2]), [], M);
Or reshape matrix A so that its dimensions are aligned with those of B, use bsxfun to multiply with singleton-expansion, and sum over the two desired dimensions:
result = sum(sum(bsxfun(#times, reshape(A, N, 1, P), B), 1), 3);

Creating array from raising matrix to power in matlab

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);

Matlab - Multiplying a matrix with every matrix of a 3d matrix

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);

Row-normalize matrix

Is there any efficient (speed of computation + amount of keystrokes) way to perform row-normalization in MATLAB, using the built in functions?
This is what I've came up with so far
A = rand(m, n); % m rows, n cols
v = pdist2(zeros(1, size(A, 2)), A);
normA = diag(1./v) * A;
Assuming you want row sums to be 1:
bsxfun(#times, A, 1./(sum(A, 2)))
Edit
If you're looking for the l2 norm as #Oli suggests below, then
bsxfun(#times, A, 1./sqrt(sum(A.^2, 2)))
In that case, you can semi-gracefully handle zero row sums by doing
bsxfun(#times, A, 1./(max(sum(A, 2), eps)))