Efficient method to compute inverse of R stacked matrices - matlab

I have the following input:
R matrices S_1,...,S_R all of which are n-by-n and invertible. These are stored in the cell-array S{r}, r=1,...,R.
R matricesx_1,...,x_R all of which are n-by-k. These are stored in the cell-array x{r}, r=1,...,R
I require the following output:
A (n*R)-by-k matrix B with entries B = (S_1\x_1,...,S_R\x_R).
One way to compute this is via a forloop:
% Preallocate resources
B = zeros(n*R,k);
% Loop:
for rr= 1:R
B( (rr-1)*n + 1: (rr-1)*n + n,:) = S{rr}\x{rr};
end
This there a more efficient way of carrying out this computation. In particular, is there a way to avoid the forloop?

Related

Block matrix inner products in Matlab

I have been using the following custom function to perform the multiplication of a vector by a matrix, in which each element of the vector multiplies a 3x3 block within a (3xN)x(3) matrix:
function [B] = BlockScalar(v,A)
N=size(v,2);
B=zeros(3*N,3);
for i=1:N
B(3*i-2:3*i,:) = v(i).*A(3*i-2:3*i,:);
end
end
Similarly, when I want to multiply a collection of 3x3 matrices by a collection of 3x3 vectors, I use the following
function [B] = BlockMatrix(A,u)
N=size(u,2);
B=zeros(N,3);
for i=1:N
B(i,:) = A(3*i-2:3*i,:)*u(:,i);
end
end
Since I call them very often, these unfortunately, slow down the running of my code significantly. I was wondering if there was a more efficient (perhaps vectorised) version of the above operations.
In both instance, you are able to do away with the for-loops (although without testing, I cannot confirm if this will necessarily speed up your computation).
For the first function, you can do it as follows:
function [B] = BlockScalar(v,A)
% We create a vector N = [1,1,1,2,2,2,3,3,3,...,N,N,N]
N=ceil((1:size(A,1))/3);
% Use N to index v, and let matlab do the expansion
B = v(N).*A;
end
For the second function, we can make a block-diagonal matrix.
function [B] = BlockMatrix(A,u)
N=size(u,2)*3;
% We use a little meshgrid+sparse magic to convert A to a block matrix
[X,Y] = meshgrid(1:N,1:3);
% Use sparse matrices to speed up multiplication and save space
B = reshape(sparse(Y+(ceil((1:N)/3)-1)*3,X,A) * (u(:)),3,size(u,2))';
end
Note that if you are able to access the individual 3x3 matrices, you can potentially make this faster/simpler by using the native blkdiag:
function [B] = BlockMatrix(a,b,c,d,...,u)
% Where A = [a;b;c;d;...];
% We make one of the input matrices sparse to make the whole block matrix sparse
% This saves memory and potentially speeds up multiplication by a lot
% For small enough values of N, however, using sparse may slow things down.
reshape(blkdiag(sparse(a),b,c,d,...) * (u(:)),3,size(u,2))';
end
Here are vectorized solutions:
function [B] = BlockScalar(v,A)
N = size(v,2);
B = reshape(reshape(A,3,N,3) .* v, 3*N, 3);
end
function [B] = BlockMatrix(A,u)
N = size(u,2);
A_r = reshape(A,3,N,3);
B = (A_r(:,:,1) .* u(1,:) + A_r(:,:,2) .* u(2,:) + A_r(:,:,3) .* u(3,:)).';
end
function [B] = BlockMatrix(A,u)
N = size(u,2);
B = sum(reshape(A,3,N,3) .* permute(u, [3 2 1]) ,3).';
end

Perform element wise multiplication of vectors efficiently?

I have to perform matrix updating by M = M + c*a*a' large number of times, where c is a constant and a is a column vector. If the size of matrix is larger than 1000, this simple updating will cost most of the time of my function, typically more than 1 min counted by profile.
Main codes are:
for i = 1:N
_do something..._
for k = 1:n
a(1:k) = M(1:k,1:k)*p(1:k);
M(1:k,1:k) = M(1:k,1:k)+c*a(1:k)*a(1:k)';
M(1:k, k+1) = b(1:k);
M(k+1, 1:k) = b(1:k)';
M(k+1, k+1) = x;
......
end
end
I have preallocated all variables, column vectors p and b are known, and x is another constant.
As I have large number of data to process by this function, does there exist more efficient alternative to this matrix updating?
You can concatenate a vectors to create a matrix A then apply multiplication just one time.
A =[a1 a2 a3];
M = c * A * A.';
consider the example
A = rand(5,5);
M = 0;
c=4;
for n = 1:5
M = M + c * A(:,n) * A(:,n).';
end
and this one
M1 = c * A * A.'
both M and M1 are equal
Have you tried using bsxfun?
In any case, bsxfun is much faster than regular multiplication, but the vectors/matrices have to be of equal length (which they are for you, aren't they?), and it's operating elementwise (i.e. a Nx1 vector bsx-multiplied with itself yields a Nx1 vector, multiplied with the transpose however yields a NxN matrix).
see https://mathworks.com/help/matlab/ref/bsxfun.html
use as
bsxfun(#times, a, a')

How to efficiently get all elements along 3rd direction at specified locations in a matrix?

A is an M*N*S matrix of values and B is a P*1 vector of indices of locations in an M*N matrix. I want to get the P*S matrix, C, that is all values along 3rd direction form A, at locations specified by B (on the A(:, :, 1)).
This is my current code:
%% sample inputs
M = 2; N = 3; S = 3;
A = reshape(1:M*N*S, M, N, S)
B = (1:3:M*N)'
P = numel(B);
%% solution
B2 = repmat(B, 1, S)+repmat((0:S-1)*M*N, P, 1);
C = A(B2)
But it calls repmat twice, and I need this in a for loop that P changes in every iteration. So how can I make it more efficient?
First of all, I would strongly discourage the use of O as a variable name. It looks like a zero. Similarly, avoid a lower-case l as it looks like a 1. Below I will use S in place of your O.
You can simply reshape your initial matrix into an [M*N, S] matrix and then user the indices on the first column.
% Collapse the first two dimensions into rows
data = reshape(A, [], size(A, 3));
% Grab the rows that correspond to the indices in B
C = data(B, :);
The use of reshape is very efficient here because MATLAB doesn't need to make a copy of the underlying data, just alter how it is accessed.

How to do a fast matrix multiplication for each column of two matrices without for loops?

I have two matrices A and B for which I want to do a multiplication for each of their columns to produce a new matrix. The first thing cross my mind is
A = rand(4,3);
B = rand(4,3);
for J=1:SIZE(A,2)
for jj=1:size(B,2)
C(:,:,m) = A(:,j)*B(:,jj)' ;
m = m+1 ;
end
end
But I don't want to use for loops which makes it slow. Is there any way?
I am going to use the matrices of third dimension of C, the ones which are built by multiplication of columns of A and B, Is it better to first build the C and then use its 3rd dimension matrices in each loop or just do the multiplication in each loop?
One approach with bsxfun -
N1 = size(A,1);
N2 = size(B,1);
C = reshape(bsxfun(#times,permute(A,[1 4 3 2]),permute(B,[4 1 2 3])),N1,N2,[])
You could avoid going to the 4th dimension as listed next, but it's still marginally slower than the earlier 4D approach -
C = reshape(bsxfun(#times,permute(A,[1 3 2]),B(:).'),N1,N2,[])
As an alternative to Divakar's answer, you can generate all 4-fold combinations of row and column indices of the two matrices (with ndgrid) and then compute the products:
[m, p] = size(A);
[n, q] = size(B);
[mm, nn, qq, pp] = ndgrid(1:m, 1:n, 1:q, 1:p);
C = reshape(A(mm+(pp-1)*m).*B(nn+(qq-1)*n), m, n, p*q);

splitting a matrix row-wise and and finding a linear regression coeff

A= [1 1
2 2
3 3
. .
. .
. .
N N]
I have an [N,2] matrix and I need to split it row-wise into some number of [N/4,2] submatrices. Then for each submatrix I need to find linear regression where the first column of each submatrix is my x data and the second column is my y data. The output should be a struct with fields a,b,c,d.... and values of linear regression for each submatrix
First I tried splitting the matrix with mat2cell where k = length(N)/4 and mat = mat2cell(A, [k k k k], [1 1]).
Next I tried converting mat into struct with out = cell2struct(mat,fields,1) where fields = {'col1','col2'} and use
new = structfun(#(x)polyfit(x.col1, x.col2,1), out,'UniformOutput', false)
But I get the error:
Inputs to STRUCTFUN must be scalar structures.
Does anyone know how to do it? Many thanks
The most straightforawrd way (and probably the fastest) to do this is with a good old for loop:
A = [1:64;1:64]'; % Demo data
m = 4;
N = size(A,1);
k = N/m; % Assumes that length is evenly divisible by 4
c = zeros(m,2); % Coefficients
for i = 1:m
c(i,:) = polyfit(A((i-1)*k+1:i*k,1),A(i-1)*k+1:i*k,2),1);
end
Or rather than using cell2struct and structfun you can use cellfun:
A = [1:64;1:64]'; % Demo data
m = 4;
N = size(A,1);
k = N/m; % Assumes that length is evenly divisible by 4
c = cellfun(#(x)polyfit(x(:,1),x(:,2),1).',mat2cell(A,k+zeros(1,m),2),'UniformOutput',false)
or alternatively
Ac = mat2cell(A,k+zeros(1,m),[1 1])
c = cellfun(#(x1,x2)polyfit(x1,x2,1).',Ac(:,1),Ac(:,2),'UniformOutput',false)
You can convert the output of cellfun to a matrix with:
c = [c{:}].'
As for why you're getting the error, your variable out is a 4-by-1 struct array (array of structures) rather than a simple (scalar) structure of arrays. The documentation for structfun points out this requirement in the description of the short function: "Apply function to each field of scalar structure." This video from The MathWorks tries to explain the difference.