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); .
Related
I am using Matlab function round(rand(256)) to create a square matrix of size 256x256 with random distribution of 0s and 1s.
What I specifically want to do is that I want to somehow specify number of 1s that rand() (or any other relevant function for that matter) to generate and distribute throughout the matrix randomly
Magdrop’s answer is the most straight-forward method, it computes the percentile of the random values to determine the threshold.
Another two options involve randperm:
Randomly permute all indices into the matrix, then threshold:
sz = [256,256]; % matrix size
n = 256; % number of zeros
M = randperm(prod(sz)) <= n;
M = reshape(M,sz);
Randomly permute indices and select n as the locations of the ones:
indx = randperm(prod(sz),n);
M = zeros(sz);
M(indx) = 1;
You could also generate the random value the usual way, but before you round them, sort them as a vector. The number of 1s will the index in the sorted vector you want to cut for 1s or 0s. For example, let say we want 50 1s:
matrix = rand(256,256);
vec = sort(reshape(matrix,[],1));
thresh = vec(50);
matrix(matrix <= thresh) = 1;
matrix(matrix > thresh) = 0;
You could use the randi function to determine the locations of where to insert the ones, and then place those ones into your matrix. For example for n ones:
matrix = zeros(256,256);
onesIndices = randi([0 256*256],1,n);
matrix(onesIndices) = 1;
One problem with this approach is that randi can generate repeat values, though for this example, where the size of the matrix is large and the number of ones is low, this is pretty unlikely. You could test if this is the case and "reroll:" so if sum(sum(matrix)) is less than n you know you had a repeat value.
Edit: a better approach is to use randperm instead of randi and only take the first n elements. This should prevent there from being repeats and having to re-roll.
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.
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,[]);
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.
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))