Vectorizing eigen value calculation of 3*3*N matrix in Matlab - matlab

Currently I am using the following code to obtain eigen values:
A = randi(100,3,3,4000000);
eig_vals = zeros(4000000,1);
for i =1:4000000
eig_vals(i) = max(eig(A(:,:,i))) ;
end
I need help to vectorize my eigen value calculations without using a for loop.
Thanks,
Prithivi

You can can calculate eigenvalues of a block-diagonal matrix composed of smaller [3 x 3] matrices:
C=mat2cell(A,3,3,ones(1,size(A,3)));
B=blkdiag(sparse(C{1}),C{2:end}); % A sparse block diagonal matrix
eig_vals = max(reshape(eig(B),3,[]),[],1);
But this may not be the most efficient one. So you can process the data part by part to reduce the time for creation of the sparse matrix:
s = 4000;
f = find(kron(speye(s),ones(3))); % indices for matrix blocks
B = spalloc(s*3,s*3,s*3*3); % preallocate the sparse matrix composed of 4000 matrices of size [3 x 3]
eig_vals = zeros(4000000,1);
for k = 0: 4000000/s-1
B(f)= A(:,:,k*s+1:k*s+s);
eig_vals(k*s+1:k*s+s) = max(reshape(eig(B),3,[]),[],1);
end
Here s=4000 is not the best chunk size. You can tune it for the best performance.

Related

Extracting block diagonal from matrix

I have an njxnj matrix made up of nxn matrices. I want to extract the diagonal j blocks of nxn matrices. i.e. I want to extract the diagonal (for n = 2, j = 4):
What would be the most efficient way of doing this?
To index the elements you can use blkdiag to create a corresponding mask.
%your parameters
n=2
j=4
%some example matrix
M=magic(n*j);
%create the input for blkdiag, j matrices of size n
h=repmat({true(n)},j,1)
%use blkdiag to select the elements
M(logical(blkdiag(h{:})))
For large j, this answer of #Daniel becomes slow. I would instead recommend using linear indices of block diagonal.
n=2;
j=4;
%some example matrix
M=magic(n*j);
linIndices = (0:n*((n*j)+1):n*((n*j)+1)*(j-1))+reshape((1:n)'+n*j*(0:n-1),[],1);
newM = reshape(M(linIndices),n,n,[]);

how to vectorze this kind of loop for array

I'm newbie to Matlab. I have some questions.
How can I vectorise this loop:
epsilon = 0.45;
t = -3.033;
n = 100;
I = ones(n,n);
%// diagonal block 1
DB1 = gallery('tridiag',ones(1,n-1),ones(1,n),ones(1,n-1));
for k = 1:n
DB1(k,k) = epsilon;
end
for k = 1:n-1
DB1(k,k+1) = t*heaviside((-1)^(k+1));
end
for k = 2:n
DB1(k,k-1) = t*heaviside((-1)^k);
and this loop with LRG, R2, R1 are 3D arrays
for k = 2:N
LRG(:,:,k) = inv(R(:,:,k) - R2(:,:,k-1)*LRG(:,:,k-1)*R1(:,:,k-1));
end
Is there any way to handle the third dimension of an array (page) without writing (:,:,...) many times?
You don't need to call gallery: this will just initialize DB1 to a specific sparse tridiagonal matrix, which you manually overwrite afterwards. With n=100, I suspect that you don't actually want to work on sparse matrices. Here's the solution:
epsilon = 0.45; t = -3.033;
n = 100;
DB1 = zeros(n); %initialize to 0
%diagonal indices
inds=sub2ind([n n],1:n,1:n);
DB1(inds) = epsilon;
%superdiagonal
inds=sub2ind([n n],1:n-1,2:n);
DB1(inds) = t*heaviside((-1).^(2:n));
%subdiagonal
inds=sub2ind([n n],2:n,1:n-1);
DB1(inds) = t*heaviside((-1).^(2:n));
Here sub2ind lets you compute linear indices from your matrix indices, allowing you to access "subvectors" in your matrix. Watch out for the exponentialization in the heaviside: you need .^ instead of ^ to perform an element-wise operation using the vector 2:n.
If you insist on getting a sparse matrix, you could either convert this matrix to sparse by calling
DB1=sparse(DB1);
which is the easiest option if your matrix is small. If n was larger and you would really need sparse matrices, then you could set up the sparse matrix itself by
DB1new=sparse([1:n 1:n-1 2:n],[1:n 2:n 1:n-1],...
[epsilon*ones(1,n) t*heaviside((-1).^(2:n)) t*heaviside((-1).^(2:n))],n,n);
This call sets the elements of DB1new one-by-one according to its vector arguments: it takes the first index from the first input argument, the seconf index from the second, and the corresponding element from the third vector (see help sparse in MATLAB).
As for your second question: I'm not sure I understand correctly. Like in my example, sub2ind can be used to transform the multidimensional indices into linear ones, see help sub2ind. But personally, I think using the array notation is far more transparent and less prone to typos. And I think you can't vectorize that loop: you have to explicitly calculate the inverse matrix for each k.

Matlab code for generating a particular class of matrices

I need to generate all square matrices of order n with given properties.
Matrices are symmetric.
Entries are 0 and 1.
Diagonal elements are zeros.
I am using Matlab2012b. Can you help me with the code?
I was trying to write it down. It needs a long sequences of for loops. Any simpler technique?
Try this:
N = 4; %// matrix size
M = (N^2-N)/2; %// number of values to fill in each matrix
P = 2^M; %// number of matrices
x = dec2bin(0:P-1)-'0'; %// each row contains the values of a matrix, "packed" in a vector
result = NaN(N,N,P); %// preallocate
for k = 1:P
result(:,:,k) = squareform(x(k,:)); %// unpack values
end
The matrices are result(:,:,1), result(:,:,2) etc.

Extracting a banded matrix from a dense matrix in MATLAB

I have a large dense matrix, say matrix A of size 10000 by 10000 and I need to extract a banded matrix of bandwidth say 10 from it, i.e.,
B(i,j) = A(i,j) if |i-j| <=10
B(i,j) = 0 otherwise
What is the most efficient way to go about doing this in MATLAB?
I don't know that this is the most efficient way, but here is a way to create a matrix banded about the main diagonal via masking using the toeplitz() function:
r = zeros(1,size(A,2));
r(1 : ceil(bandwidth/2)) = 1;
bandedMask = toeplitz(r); %Create a banded toeplitz matrix of 1s and 0s
bandedMat = bandedMask.*A;
Note: This method assumes your bandwidth is odd.
As it is a huge matrix it might be a useful option not to copy it a second time to the memory. In that case
N = 10;
M = ...
for lin = 1:size(M,1)
M(lin, lin+N:end) = 0;
M(lin, 1:lin-N) = 0;
end
could be useful (depends whether you need the original matrix or not afterwards).
In the case you have to keep the original matrix you could think about representing your matrix diagonal by diagonal or as sparse matrix. In the case you have to copy the matrix you shouldn't touch all the elements that you don't need.
You should evaluate the different ways and tell us your results :-)
Suppose you have a matrix B and bandwidth n:
B = rand(16,7);
n = 4;
% Index main diagonal
szB = size(B);
idx = abs(bsxfun(#minus, (1:szB(1))',1:szB(2))) <= n;
% Build sparse
[r,c] = find(idx);
sparse(r,c,B(idx))

Random permutation matrix

Is there an easy way to simulate a random permutation matrix (say of size 1000 by 1000) in Matlab? I would like to study the eigenvalue distribution of independent sum of such matrices.
Thanks in advance!
You can generate a random permutation matrix like so:
Create a unity matrix:
A = eye( N ); %// N is the size of your matrix
For large values of N it is better to use sparse matrices:
A = speye( N ); % create sparse identity matrix
Generate a random permutation:
idx = randperm(1:N);
Use vector indexing to rearrange the rows accordingly
A = A(idx, :);
Voila!
In Matlab (used R2012a) idx = randperm(1:N) gives a warning that input should be scalar. So: idx = randperm(N); .