gaussian elimination of permutation matrix - matlab

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

Related

How do I populate matrix with a vector, considering Matrix as chart and vector as line

Consider following values
result=zeros(11,11);
line=(4:0.4:8);
Imagine result as a 11x11 X-Y chart paper. So initially we have a blank chart paper. As in a chart plot, I want to populate values of line in result matrix so that we get an upward sloping line when we display matrix.
Consider following figure which I want as result.
Here, result matrix can be visualized as chart paper with origin at bottom left corner. Now, for X=1, line(1)=4; for X=2, line(2)=4.4,.. and so on.
I have written following code which serves the purpose.
result=zeros(11,11);
line=(4:0.4:8);
for i=1:length(line)
temp=floor(line(i));
result(length(line)-temp+1,i)=line(i);
end
Is there a more efficient way to implement this solution? (I shall be working with 20000x20000 matrix, so method needs to be fast)
As suggested in comments, Problem Description is as follows:
I have lets say 1000 lines. All of these lines have different slopes and intercept. I know the x range of the lines and y range of the lines. There is not much I can infer from data if I plot these lines simultaneously on a single plot. The resulting image will be something like this:
Not much can be inferred about this plot. However, if I can get this information saved in a big matrix, then I can analyse where maximum lines are passing through at a particular X index and make further analysis accordingly.
Further Details
I am discretinizing Y axis into 1000 equally spaced interval:
sample code as follows:
range=max(data)-min(data);
percent=0.20;
outerRange= max(data)+range*percent - (min(data)-range*percent);
outerRangeValues=min(data)-range*percent:outerRange/1000:max(data)+range*percent;
Even though it is entirely possible that a particularly steep line will pass through 2 or more rows in a single column, I'll only select only one of the rows to be filled by line in a single column. This can be done by taking average of rows values for a particular column and assigning single row to be its value for that column
You can use sub2ind to keep things vectorized and avoid loops.
The idea is to find all the row and column indices which will have to be modified.
For X axis it is easy, it is simply one per column so the X indices will be 1,2,3,...,np.
For the Y axis, you have to bin the line values into the Y grid. Since indices have to be integers, you have to convert your floating point values into integers. For that you can choose between round, floor and ceil. Each will place some values slightly differently, it is up to you to define which rounding method makes sense for your problem.
Once you have your indices [row_indices,column_indices], you convert them to linear indices into the matrix by using sub2ind, then you assign the values of line into these linear indices.
In code:
line=(4:0.4:8); % your input (line vector)
np = numel(line) ; % determine size of matrix/chart
% identify column and row indices to modify
idCol = 1:np ;
idRow = fliplr( round( line ) ) ; % choose "round", "floor" or "ceil"
% build the result
result = zeros(np);
linearInd = sub2ind( [np,np], idRow, idCol ) ;
result(linearInd) = line ;
Gives you:
>> result
result =
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 7.2 7.6 8
0 0 0 0 0 0 6.4 6.8 0 0 0
0 0 0 5.2 5.6 6 0 0 0 0 0
0 4.4 4.8 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

Matlab matrix save 1 positions for large matrices

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])

Convert digit to vector octave/matlab [duplicate]

This question already has answers here:
Construct this matrix based on two vectors MATLAB
(3 answers)
Closed 8 years ago.
I have a vector y = [0; 2; 4]
I want to convert each element of it into vector, where all elements are zero but element with index equal to digit is 1.
I'd like to do it without loops.
For example [0; 2; 4] should be converted to
[1 0 0 0 0 0 0 0 0 0;
0 0 1 0 0 0 0 0 0 0;
0 0 0 0 1 0 0 0 0 0]
(in this example vector first index is 0)
The usual trick with sparse can be used to simplify the process. Let n denote the desired number of columns. Then
result = full(sparse(1:numel(y), y+1, 1, numel(y), n));
For example, y = [0;2;4] and 10 produce
result =
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
First you need to decide how many digits you want to represent each number. In your case, you have 10 digits per number, so let's keep that in mind.
Once you do this, it's just a matter of indexing each element in your matrix. In your case, you have 10 digits per number. As such, do something like this:
y = [0; 2; 4]; %// Your digits array
out = zeros(numel(y), 10); %// 10 digits per number
ind = sub2ind(size(out), [1:numel(y)].', y+1);
out(ind) = 1;
The output should look like this:
out =
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
Let's go through this code slowly. y defines the digits you want per row of the output matrix. out allocates a matrix of zeroes where the number of rows is defined by how many digits you want in y. out will thus store your resulting matrix that you have shown us in your post.
The number of columns is 10, but you change this to be whatever you want. ind uses a command called sub2ind. This allows to completely vectorize the assignment of values in your out matrix and avoids a for loop. The first parameter is an array of values that defines how many rows and columns are in your matrix that you are trying to assign things to. In this case, it's just the size of out. The second and third parameters are the rows and columns you want to access in your matrix. In this case, the rows vary from 1 to as many elements as there are in y. In our case, this is 3. We want to generate one number per row, which is why it goes from 1 to 3. The columns denote where we want to set the digit to one for each row. As MATLAB indexes starting at 1, we have to make sure that we take y and add by 1. ind thus creates the column-major indices in order to access our matrix. The last statement finally accesses these locations and assigns a 1 to each location, thus producing our matrix.
Hope this helps!

How to replace non-zero elements randomly with zero?

I have a matrix including 1 and 0 elements like below which is used as a network adjacency matrix.
A =
0 1 1 1
1 1 0 1
1 1 0 1
1 1 1 0
I want to simulate an attack on the network, so I must replace some specific percent of 1 elements randomly with 0. How can I do this in MATLAB?
I know how to replace a percentage of elements randomly with zeros, but I must be sure that the element that is replaced randomly, is one of the 1 elements of matrix not zeros.
If you want to change each 1 with a certain probability:
p = 0.1%; % desired probability of change
A_ones = find(A); % linear index of ones in A
A_ones_change = A_ones(rand(size(A_ones))<=p); % entries to be changed
A(A_ones_change) = 0; % apply changes in those entries
If you want to randomly change a fixed fraction of the 1 entries:
f = 0.1; % desired fraction
A_ones = find(A);
n = round(f*length(A_ones));
A_ones_change = randsample(A_ones,n);
A(A_ones_change) = 0;
Note that in this case the resulting fraction may be different to that intended, because of the need to round to an integer number of entries.
#horchler's point is a good one. However, if we keep it simple, then you can just multiple your input matrix to a mask matrix.
>> a1=randint(5,5,[0 1]) #before replacing 1->0
a1 =
1 1 1 0 1
0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
1 0 1 0 1
>> a2=random('unif',0,1,5,5) #Assuming frequency distribution is uniform ('unif')
a2 =
0.7889 0.3200 0.2679 0.8392 0.6299
0.4387 0.9601 0.4399 0.6288 0.3705
0.4983 0.7266 0.9334 0.1338 0.5751
0.2140 0.4120 0.6833 0.2071 0.4514
0.6435 0.7446 0.2126 0.6072 0.0439
>> a1.*(a2>0.1) #And the replacement prob. is 0.1
ans =
1 1 1 0 1
0 1 1 1 0
0 1 0 0 1
0 0 1 0 1
1 0 1 0 0
And other trick can be added to the mask matrix (a2). Such as a different freq. distribution, or a structure (e.g. once a cell is replaced, the adjacent cells become less likely to be replaced and so on.)
Cheers.
The function find is your friend:
indices = find(A);
This will return an array of the indices of 1 elements in your matrix A and you can use your method of replacing a percent of elements with zero on a subset of this array. Then,
A(subsetIndices) = 0;
will replace the remaining indices of A with zero.

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))