Block matrix inner products in Matlab - 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

Related

Efficient method to compute inverse of R stacked matrices

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?

create matrix function of vector input variable (Matlab)

I'm having trouble creating a function that does what I want. I'm trying to create an anonymous function that, on accepting a vector of length N produces an NxN matrix. I'd like to populate each element of the matrix (ie, with a loop). A short example to be more specific:
N = 2;
Qjk = #(x,y) x * y;
for j = 1:N
for k = 1:N
Q(j,k) =#(x) Qjk(x(k),rand);
end
end
In the end this should produce, eg.:
Q = #(x) [.23*x(1), .16*x(2); .95*x(1), .62*x(2)]
I can write the final expression above by hand and it works as required, but I'm unable to automate this process with a loop/vectorization. Thanks.
So it is my understanding that you want to create a N x N matrix of elements where the input is a vector of length N?... and more specifically, you wish to take each element in the input vector x and generate a new 1 x N vector where each element in x gets scaled by this new 1 x N vector?
You can avoid loops by using bsxfun:
Q = bsxfun(#times, x(:).', rand(numel(x)));
I'm not sure what shape x is, whether it's a row or column vector but I'm not going to make any assumptions. x(:).' will ensure that your vector becomes a row vector. However, if you want to get your code working as it, get rid of the anonymous function declaration within the actual loop itself. Also, you'll probably want to call Qjk as that is the function you declared, not Q as that is the matrix you are trying to populate.
Simply do:
N = 2;
Q = zeros(N); % New - Allocate to be more efficient
Qjk = #(x,y) x * y;
for j = 1:N
for k = 1:N
Q(j,k) = Qjk(x(k),rand); % Change
end
end

Filling in a Cell of Matrices in MATLAB

In Matlab I am trying to create a cell of size 16 x1 where each entry of this cell is a matrix. I have the following equation
$$W_g = exp^{\frac{j{2\pi m}{N}(n+\frac{g}{G}))} \,\,\,\,\,\,\, m,n=0,1,.....(N-1)$$
for this work assume $N=4$ and the index $g$ is the index that refers to the cell element i.e g=0:1:15
W=cell(16,1);
for g=1:16
for m=1:3
for n=1:3
W{g,m,n}= exp((2*pi*j*m/4)* n+(g-1)/16));
end
end
end
How can I make this work? I have two problems with this, you see g starts from 0 and MATLAB doesnt accept index of zero and how to actually define the matrices within the cell.
Thanks
So if I understand you have this equation:
And you just want the following code:
W=cell(16,1);
n = 1:3;
m = 1:3;
N = 4;
for g=1:16
W{g}= exp((2*pi*j.*m/4*N).*n+(g-1)/16);
end
%or the 1 line version:
W = cellfun(#(g) exp((2*pi*j.*m/4*N).*n+(g-1)/16),num2cell([1:16]),'UniformOutput',0);
With matlab you can use the Element-wise multiplication symbol .*
For example:
%A matrix multiplication
A = [2,3]
B = [1,3]';
result = A * B %result = 11
%An element wise multiplication
A = [2,3]
B = [1,3];
result = A .* B %result = [2,9]
First of all, i is the complex number in matlab (sqrt(-1)) not j, and you are correct, matlab is indexed in 1, so simply start counting g at 1, until 16.
Next, create a zero matrix, and calculate all indices accordingly. Something like this should work just fine :
clc
clear all
W=cell(16,1);
for g=1:16;
temp = zeros(3,3);
for m=1:3
for n=1:3
temp (m,n) = exp((2*pi*1i*m/4)* n+g/16);
end
end
W{g} = temp;
end
if you are considering doing much larger operations, consider using linspace to create your m and n indices and using matrix operations

Matlab: Efficient storage of n 2x2 matrices

I have a recursive procedure that generates a 2x2 matrix each time the loop iterates. I want to be able to call upon each of these matrices at a later point but I'm not sure how to store them all together efficiently.
If the procedure iterates n times, should I store them in a 2nx2 matrix? But then how would I call upon say the jth matrix (rows 2j-1 and 2j) within this long matrix?
Thanks!
You can use cell arrays:
matrices = cell(n,1);
for ii = 1:n
% generate your matrix
matrix_ii = rand(2);
% store it for later
matrices{ii} = matrix_ii;
% [do your stuff]
end
Recalling the jth matrix is then as simple as
matrix_j = matrices{j}
(note the curly braces).
You could also store it in a large 2D array (as you suggested),
matrices = zeros(2*n,2);
for ii = 1:n
% generate your 2x2 matrix
matrix_ii = rand(2);
% store it for later
matrices(2*(ii-1)+[0 1]+1,:) = matrix_ii;
% [do your stuff]
end
recalling values later like so:
matrix_j = matrices(2*(j-1)+[0 1]+1,:)
or in a 3D array like so,
matrices = zeros(2,2,n);
for ii = 1:n
% generate your 2x2 matrix
matrix_ii = rand(2);
% store it for later
matrices(:,:,ii) = matrix_ii;
% [do your stuff]
end
recalling values later like so:
matrix_j = matrices(:,:,j);
Comparing the methods for n = 1e5:
Elapsed time is 0.282959 seconds. % cell arrays
Elapsed time is 0.856801 seconds. % 2*n x 2 matrix
Elapsed time is 0.293186 seconds. % 2x2xn array
Memory: 9200000 bytes % Cell arrays
Memory: 3200000 bytes % 2*n x 2 matrix
Memory: 3200000 bytes % 2x2xn array
You might want to test these things on your own computer, but it appears the large 3D array is the best way to go here.
Rody Oldenhuis gave three great alternatives to store the matrices in his answer (which I already upvoted). I just wanted to improve upon the slowest of the three.
MATLAB matrices are indexed faster by columns rather than by rows, so I'm building a big wide matrix (2-by-2*n) rather than a tall matrix (2*n-by-2). Also building the index in the iterations can be simplified.
Here is the result of that, with a slightly more convenient benchmark (you will need the TIMEIT function from the File Exchange)
function [t,b] = test_2d_matrices_container()
N = 1e5;
f = {#()func_cell(N), #()func_wide_2d_mat(N), #()func_3d_mat(N)};
t = cellfun(#timeit, f);
b = cellfun(#get_mem, f);
end
function b = get_mem(f)
x = feval(f); %#ok<NASGU>
S = whos('x');
b = S.bytes;
end
function M = func_cell(N)
M = cell(N,1);
for i=1:N
M{i} = rand(2);
end
end
function M = func_wide_2d_mat(N)
M = zeros(2,2*N);
for i=1:2:2*N
M(:,[i i+1]) = rand(2);
end
end
function M = func_3d_mat(N)
M = zeros(2,2,N);
for i=1:N
M(:,:,i) = rand(2);
end
end
The results I get on my machine:
>> [t,b] = test_2d_matrices_container
t =
0.13963 0.22997 0.23434
b =
9200000 3200000 3200000
Now the "wide" 2D matrix case is as fast as the 3D "slices" method (even lightly faster, but the difference is really negligible)

Gaussian Elimination in Matlab

I am using the matlab code from this book: http://books.google.com/books/about/Probability_Markov_chains_queues_and_sim.html?id=HdAQdzAjl60C
Here is the Code:
function [pi] = GE(Q)
A = Q';
n = size(A);
for i=1:n-1
for j=i+1:n
A(j,i) = -A(j,i)/A(i,i);
end
for j =i+1:n
for k=i+1:n
A(j,k) = A(j,k)+ A(j,i) * A(i,k);
end
end
end
x(n) = 1;
for i = n-1:-1:1
for j= i+1:n
x(i) = x(i) + A(i,j)*x(j);
end
x(i) = -x(i)/A(i,i);
end
pi = x/norm(x,1);
Is there a faster code that I am not aware of? I am calling this functions millions of times, and it takes too much time.
MATLAB has a whole set of built-in linear algebra routines - type help slash, help lu or help chol to get started with a few of the common ways to efficiently solve linear equations in MATLAB.
Under the hood these functions are generally calling optimised LAPACK/BLAS library routines, which are generally the fastest way to do linear algebra in any programming language. Compared with a "slow" language like MATLAB it would not be unexpected if they were orders of magnitude faster than an m-file implementation.
Hope this helps.
Unless you are specifically looking to implement your own, you should use Matlab's backslash operator (mldivide) or, if you want the factors, lu. Note that mldivide can do more than Gaussian elimination (e.g., it does linear least squares, when appropriate).
The algorithms used by mldivide and lu are from C and Fortran libraries, and your own implementation in Matlab will never be as fast. If, however, you are determined to use your own implementation and want it to be faster, one option is to look for ways to vectorize your implementation (maybe start here).
One other thing to note: the implementation from the question does not do any pivoting, so its numerical stability will generally be worse than an implementation that does pivoting, and it will even fail for some nonsingular matrices.
Different variants of Gaussian elimination exist, but they are all O(n3) algorithms. If any one approach is better than another depends on your particular situation and is something you would need to investigate more.
function x = naiv_gauss(A,b);
n = length(b); x = zeros(n,1);
for k=1:n-1 % forward elimination
for i=k+1:n
xmult = A(i,k)/A(k,k);
for j=k+1:n
A(i,j) = A(i,j)-xmult*A(k,j);
end
b(i) = b(i)-xmult*b(k);
end
end
% back substitution
x(n) = b(n)/A(n,n);
for i=n-1:-1:1
sum = b(i);
for j=i+1:n
sum = sum-A(i,j)*x(j);
end
x(i) = sum/A(i,i);
end
end
Let's assume Ax=d
Where A and d are known matrices.
We want to represent "A" as "LU" using "LU decomposition" function embedded in matlab thus:
LUx = d
This can be done in matlab following:
[L,U] = lu(A)
which in terms returns an upper triangular matrix in U and a permuted lower triangular matrix in L such that A = LU. Return value L is a product of lower triangular and permutation matrices. (https://www.mathworks.com/help/matlab/ref/lu.html)
Then if we assume Ly = d where y=Ux.
Since x is Unknown, thus y is unknown too, by knowing y we find x as follows:
y=L\d;
x=U\y
and the solution is stored in x.
This is the simplest way to solve system of linear equations providing that the matrices are not singular (i.e. the determinant of matrix A and d is not zero), otherwise, the quality of the solution would not be as good as expected and might yield wrong results.
if the matrices are singular thus cannot be inversed, another method should be used to solve the system of the linear equations.
For the naive approach (aka without row swapping) for an n by n matrix:
function A = naiveGauss(A)
% find's the size
n = size(A);
n = n(1);
B = zeros(n,1);
% We have 3 steps for a 4x4 matrix so we have
% n-1 steps for an nxn matrix
for k = 1 : n-1
for i = k+1 : n
% step 1: Create multiples that would make the top left 1
% printf("multi = %d / %d\n", A(i,k), A(k,k), A(i,k)/A(k,k) )
for j = k : n
A(i,j) = A(i,j) - (A(i,k)/A(k,k)) * A(k,j);
end
B(i) = B(i) - (A(i,k)/A(k,k)) * B(k);
end
end
function Sol = GaussianElimination(A,b)
[i,j] = size(A);
for j = 1:i-1
for i = j+1:i
Sol(i,j) = Sol(i,:) -( Sol(i,j)/(Sol(j,j)*Sol(j,:)));
end
end
disp(Sol);
end
I think you can use the matlab function rref:
[R,jb] = rref(A,tol)
It produces a matrix in reduced row echelon form.
In my case it wasn't the fastest solution.
The solution below was faster in my case by about 30 percent.
function C = gauss_elimination(A,B)
i = 1; % loop variable
X = [ A B ];
[ nX mX ] = size( X); % determining the size of matrix
while i <= nX % start of loop
if X(i,i) == 0 % checking if the diagonal elements are zero or not
disp('Diagonal element zero') % displaying the result if there exists zero
return
end
X = elimination(X,i,i); % proceeding forward if diagonal elements are non-zero
i = i +1;
end
C = X(:,mX);
function X = elimination(X,i,j)
% Pivoting (i,j) element of matrix X and eliminating other column
% elements to zero
[ nX mX ] = size( X);
a = X(i,j);
X(i,:) = X(i,:)/a;
for k = 1:nX % loop to find triangular form
if k == i
continue
end
X(k,:) = X(k,:) - X(i,:)*X(k,j);
end