Matlab matrix save 1 positions for large matrices - matlab

I have a sparse matrix in Matlab. I would like to save the positions of 1's in the matrix row-wise and column-wise.
For example consider the below matrix:
0 1 0 1 0
0 0 0 1 0
0 0 0 0 0
0 0 1 0 0
1 0 0 0 0
I would like two files written as:
row-wise.csv:
1,2
1,4
2,4
4,3
5,1
column-wise.csv:
5,1
1,2
4,3
1,4
2,4
I know I can run a loop row-wise or column-wise and save element by element using fprintf, but is there a better way?
I'm dealing with very large matrices and I'm wondering what an efficient way is to do this?

You're going to want to use find to perform this task. Then to write them out to a csv file, you can simply use dlmwrite.
For the column-wise, you can use the two outputs of find which are the row index and column index of each 1 (in column-major order).
data = [0 1 0 1 0
0 0 0 1 0
0 0 0 0 0
0 0 1 0 0
1 0 0 0 0];
[row, col] = find(data);
M = [row, col];
dlmwrite('column-wise.csv', M);
Then to obtain the row-wise result, you can just sort your column-wise result by rows and then columns using sortrows.
dlmwrite('row-wise.csv', sortrows(M))
The alternative to this, is to perform find again on the transpose of your data (to force row-major ordering) but I would think that the sortrows approach is faster.
[col, row] = find(data.');
dlmwrite('row-wise.csv', [row, col])

Related

Up-/Downsampling of a logical vector (not with zeros)

I hope you can help with a little problem I am having.
I want to upsample and downsample a vector with zeros and ones. We have the functions upsample and downsample for that, however, the upsample function in Matlab only adds zeros to the vector. I would like to repeat the value, instead of just putting in zeros.
Unfortunately the upsample function does not do that. Thus, I tried to use repmat (in the third dimension) and then reshape to get back to the old format. I know it must be possible with these functions, but if I simply use them, the vector just gets duplicated and added to the end.
An example:
The input vector is: [1 0 0 1 0 1 0 1 1 1 0 0] (these should be random).
Now I want to upsample (say) by a factor of 2. Then I want to get:
[1 1 0 0 0 0 1 1 0 0 1 1 0 0 1 1 1 1 1 1 0 0 0 0].
Thanks in advance for any help!
You can use repelem:
>> repelem([1 0 1],2)
ans =
1 1 0 0 1 1
Or using repmat and reshape when input is a column vector:
>> input = [1 0 1];
>> reshape(repmat(input, 2, 1), 1, [])
ans =
1 1 0 0 1 1

Vector to matrix with row sum 1

I have a logical 1-by-n vector with sum m. Now, I need to convert it into a matrix m-by-n in a way that the row sum is equal 1.
vector (1-by-8) with sum 4
[0 1 0 0 1 0 1 1]
matrix (4-by-8) with row sum 1
[0 1 0 0 0 0 0 0;
0 0 0 0 1 0 0 0;
0 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 1]
Is there a mathematically efficient way without calculating the sum, creating a empty matrix, loop through the vector and adding the 1s row by row?
I think that in that case, given your input, you don't even need to calculate the sum.
You can define an identity matrix of size n, then use your input vector to sample the required rows out of it:
I = eye(n);
y = I(x, :) ; % Output Matrix. x is the input vector
Here's another method, using sparse:
matrix = full(sparse(1:m, find(vector), 1, m, n));

gaussian elimination of permutation matrix

I have a binary sparse matrix H of size 600*1200 constructed by concatenating square permutation matrices of size 200, thus sparse matrix have 3 ones in each column and 6 ones in each row. Now am trying to transform the matrix into reduced echelon form.
This is my code:
[m,n]=size(H);
for i=1:m
ind=find(H(:,i),1,'last');
if ind<=i
continue;
end
if ind~=i
temp=H(ind,:);
H(ind,:)=H(i,:);
H(i,:)=temp;
end
I=find(H(:,i));
% Guassian elimination
for j=1:length(I)
if I(j)~=i
H(I(j),:)=mod(H(I(j),:)+H(i,:),2);
end
end
end
But whichever H matrix generated, I can't get rid of other entries at 400th column,
how can I fix this, help
Since Gaussian elimination does not involve rearrangement of columns, the first 600 columns of the resulting matrix will only form the identity matrix if the first 600 columns of the original matrix were linearly independent. Otherwise, you are going to have "short" columns with other entries in them, as the Wikipedia article shows.
The way your matrix is structured, the first 400 columns are guaranteed to be linearly dependent. Indeed, the sum of the first 200 columns is the all-1 vector, and so is the sum of the columns 201-400. This is why you are seeing these entries in the 400th column.
To create identity matrix on the left you need to rearrange columns. One way, which looks a bit redundant but is very easy to code, is to
run your algorithm
rearrange columns (it's easy to identify the desired columns after rref)
do rref again.
Here is the code that does steps 2-3.
for i = 1:m
j = find(H(i,:),1,'first');
[H(:,i), H(:,j)] = deal(H(:,j), H(:,i));
end
H = rref(H)
Sample input into rref:
1 0 1 0 1
0 1 0 0 1
1 0 1 1 0
0 0 0 0 1
Output of your code:
1 0 1 1 0
0 1 0 0 1
0 0 0 1 1
0 0 0 0 1
After the column swap and second rref:
1 0 0 0 1
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0

Trim Binary Matrix in MatLab

I have a binary matrix like this:
0 0 0 0 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 1 0 1 0
0 0 0 1 0 0
0 0 0 0 0 0
and I want to trim this matrix (in other words, remove zeroes at the boundaries) to be like:
0 0 1 0
1 0 0 0
0 1 0 1
0 0 1 0
How to do this the "Matlab" way? that's not to use conventional loops and conditions.
To be clearer, the matrix should be reduced to start from the first column which has at least one 1, and ends at the last column with the same condition, inclusive. Any column out of this range should be removed. Same rules apply for rows.
Thanks.
If you have the data in matrix M...
x = find(any(M,2),1,'first'):find(any(M,2),1,'last');
y = find(any(M),1,'first'):find(any(M),1,'last');
M(x, y)
Or, if you know that there will be a 1 in every row/col except the edges:
M(any(M,2), any(M))
Extension to higher dimensions:
Assuming a 3D matrix to be trimmed, this is more straightforward:
M=rand(3,3,3); % generating a random 3D matrix
M(2,:,:)=0; % just to make a check if it works in extreme case of having zeros in the middle
padded = padarray(M,[2 2 2]); % making some zero boundaries
[r,c,v]=ind2sub(size(padded),find(padded));
recoveredM=padded(min(r):max(r),min(c):max(c),min(v):max(v));
check=M==recoveredM % checking to see if M is successfully recovered
You could use the fact that find can return row and column indices:
[r1, c1] = find(x, 1, 'first')
[r2, c2] = find(x, 1, 'last')
x(r1:r2, c1:c2)

How can I rearrange the columns of this matrix?

Given a binary matrix in which every row and column contains exactly only one 1, I need to rearrange the matrix columnwise so that it will become an identity matrix. For example, given a binary matrix:
Binary = [ 0 1 0 0 0
0 0 1 0 0
1 0 0 0 0
0 0 0 0 1
0 0 0 1 0 ]
To get the identity matrix we rearrange the column as 2 3 1 5 4.
How can we optimally rearrange the columns for any given arbitrary square binary matrix?
A very simple way to do this is to use the function FIND like so:
[index,~] = find(Binary.'); %'# Transpose the matrix and find the row indices
%# of the non-zero entries
And you can test that it work as follows:
>> Binary(:,index)
ans =
1 0 0 0 0 %# Yup, that's an identity matrix alright!
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
OLD APPROACH:
This isn't as compact or efficient as the above solution, but you could also transpose the matrix and use SORTROWS to sort the columns (now transposed into the rows) and return the sort indices. This will actually sort values in ascending order, which will give you an anti-diagonal matrix, so you will want to flip the vector of indices using FLIPUD. Here's the code:
[~,index] = sortrows(Binary.'); %'# Transpose and sort the matrix
index = flipud(index); %# Flip the index vector
If you know the matrix can be manipulated into an identity matrix, why don't you just create an identity matrix with the same dimensions?
identity_matrix=eye(length(Binary))