Generating a matrix containing 3 numbers - matlab

I am trying to create an 8x8 matrix containing 0s, 1s and 2s. Each row and each column should contain two 0s, three 1s and three 2s.
Previously I have used the below to generate an example containing only 1s and 0s.
output = zeros(8, 8);
for i=1:8
tmp = (1:8) + (i);
tmp = rem(tmp, 4);
output(i,:) = tmp;
output(i,:) = tmp > 0;
end
output =
1 1 0 1 1 1 0 1
1 0 1 1 1 0 1 1
0 1 1 1 0 1 1 1
1 1 1 0 1 1 1 0
1 1 0 1 1 1 0 1
1 0 1 1 1 0 1 1
0 1 1 1 0 1 1 1
1 1 1 0 1 1 1 0
However I would now like something similar to the following:
output =
1 1 0 1 2 2 0 2
1 0 1 2 2 0 2 1
0 1 2 2 0 2 1 1
1 2 2 0 2 1 1 0
2 2 0 2 1 1 0 1
2 0 2 1 1 0 1 2
0 2 1 1 0 1 2 2
2 1 1 0 1 2 2 0
Thanks for your help.

What you have in your example is a Hankel matrix so you could use the hankel function
c = [1 1 0 1 2 2 0 2];
k = [2 1 1 0 1 2 2 0];
A = hankel(c,k)
where c is the first column of the output matrix and k is the last row.
Making your output matrix a Hankel matrix is a good idea (based on your requirements) as it will enforce the row and column frequency counts for each value. You would not necessarily get this just by creating rows that are random permutations of a base row (using randperm for example) as duplicate rows would be possible which would break your column requirements.
As an example, if you want random c with fixed numbers of specific elements, you can randomly permute a base vector containing the required values and frequencies - as per your requirement this would be
c = [0 0 1 1 1 2 2 2];
index = randperm(numel(c));
c = c(index);
c =
0 2 0 2 2 1 1 1
To get the square Hankel structure then choose k to be the next cyclic permutation of c
k = circshift(c',1)'
k =
1 0 2 0 2 2 1 1
and just call hankel with these as mentioned above
A = hankel(c,k)
A =
0 2 0 2 2 1 1 1
2 0 2 2 1 1 1 0
0 2 2 1 1 1 0 2
2 2 1 1 1 0 2 0
2 1 1 1 0 2 0 2
1 1 1 0 2 0 2 2
1 1 0 2 0 2 2 1
1 0 2 0 2 2 1 1
The above output is based on what I got on my machine based on the output from randperm.
Any output matrix generated using the above will meet your requirements specified in the question.

Related

MATLAB - Inserting zero rows and columns into matrix

I have written some code that compresses a matrix to remove zero columns and rows, but I can't work out how to reconstruct the original matrix.
Say I have a matrix:
A = [ 0 3 0 2 1 0 6
3 0 0 4 8 0 5
0 0 0 0 0 0 0
2 4 0 0 2 0 1
1 8 0 2 0 0 7
0 0 0 0 0 0 0
6 5 0 1 7 0 0 ]
Here rows/columns 3 and 6 are empty, so my compression function will give the output:
A_dash = [ 0 3 2 1 6
3 0 4 8 5
2 4 0 2 1
1 8 2 0 7
6 5 1 7 0 ]
A_map = [ 1 2 4 5 7]
Where A_map is a vector mapping the indicies of the rows/columns of A_dash to A. This means that if A_map(3) = 4, then row/column 4 of A is the same as row/column 3 of A_dash - ie. a row/column of zeroes must be inserted between columns/rows 2 and 3 in A_dash
What is the easiest way people can suggest for me to recreate matrix A from A_dash, using the information in A_map?
Here is what I have got so far:
% orig_size is original number of columns/rows
c_count = size(A_dash,1);
A = zeros(c_count, orig_size); % c_count rows to avoid dimension mismatch
for ii = 1:c_count
A(:,A_map(ii)) == A_dash(:,ii);
end
This gives me the right result column-wise:
A = [ 0 3 0 2 1 0 6
3 0 0 4 8 0 5
2 4 0 0 2 0 1
1 8 0 2 0 0 7
6 5 0 1 7 0 0 ]
However, I'm not sure how i should go about inserting the rows, i suppose i could copy the first 1:i rows into one matrix, i:end rows to a second matrix and concatenate those with a zero row in between, but that feels like a bit of a
clunky solution, and probably not very efficient for large sized matrices..
Otherwise, is there a better way that people can suggest I store the map information? I was thinking instead of storing the mapping between column/row indices, that I just store the indices of the zero columns/rows and then insert columns/rows of zeros where appropriate. Would this be a better way?
You've got the indices of the valid rows/columns. Now all you've got to do is put them in a new matrix of zeros the same size as A:
B=zeros(size(A));
B(A_map,A_map)=A_dash
B =
0 3 0 2 1 0 6
3 0 0 4 8 0 5
0 0 0 0 0 0 0
2 4 0 0 2 0 1
1 8 0 2 0 0 7
0 0 0 0 0 0 0
6 5 0 1 7 0 0
Just to check...
>> A==B
ans =
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
A and B are equal everywhere, so we've reconstructed A.

Convert adjacency matrix to specific edge list in MATLAB

If I have the matrix
1 0 0
0 0 1
0 0 0
and I want this form in MATLAB
1 2 3 1 2 3 1 2 3
1 1 1 2 2 2 3 3 3
1 0 0 0 0 0 0 1 0
also I want the values of third row in result. i.e. ans= [1 0 0 0 0 0 0 1 0]
Here you go -
[X,Y] = ndgrid(1:size(A,1),1:size(A,2));
out = [X(:).' ; Y(:).' ; A(:).']
For the last part of your question, use the last row of out : out(end,:) or A(:).'.
Sample run -
>> A
A =
1 0 0
0 0 1
0 0 0
>> [X,Y] = ndgrid(1:size(A,1),1:size(A,2));
>> out = [X(:).' ; Y(:).' ; A(:).']
out =
1 2 3 1 2 3 1 2 3
1 1 1 2 2 2 3 3 3
1 0 0 0 0 0 0 1 0

Assign values w/ multiple conditions

Let's have a M = [10 x 4 x 12] matrix. As example I take the M(:,:,4):
val(:,:,4) =
0 0 1 0
0 1 1 1
0 0 0 1
1 1 1 1
1 1 0 1
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
How can I obtain this:
val(:,:,4) =
0 0 3 0
0 2 2 2
0 0 0 4
1 1 1 1
1 1 0 1
0 2 2 2
1 1 1 1
1 1 1 1
0 0 3 3
0 0 3 3
If I have 1 in the first column then all the subsequent 1's should be 1.
If I have 0 in the first column but 1 in the second, all the subsequent 1's should be 2.
If I have 0 in the first and second column but 1 in the third then all the subsequent 1's should be 3.
If I have 0 in the first 3 columns but 1 in the forth then this one should be four.
Note: The logical matrix M is constructed:
Tab = [reshape(Avg_1step.',10,1,[]) reshape(Avg_2step.',10,1,[]) ...
reshape(Avg_4step.',10,1,[]) reshape(Avg_6step.',10,1,[])];
M = Tab>=repmat([20 40 60 80],10,1,size(Tab,3));
This is a very simple approach that works for both 2D and 3D matrices.
%// Find the column index of the first element in each "slice".
[~, idx] = max(val,[],2);
%// Multiply the column index with each row of the initial matrix
bsxfun(#times, val, idx);
This could be one approach -
%// Concatenate input array along dim3 to create a 2D array for easy work ahead
M2d = reshape(permute(M,[1 3 2]),size(M,1)*size(M,3),[]);
%// Find matches for each case, index into each matching row and
%// elementwise multiply all elements with the corresponding multiplying
%// factor of 2 or 3 or 4 and thus obtain the desired output but as 2D array
%// NOTE: Case 1 would not change any value, so it was skipped.
case2m = all(bsxfun(#eq,M2d(:,1:2),[0 1]),2);
M2d(case2m,:) = bsxfun(#times,M2d(case2m,:),2);
case3m = all(bsxfun(#eq,M2d(:,1:3),[0 0 1]),2);
M2d(case3m,:) = bsxfun(#times,M2d(case3m,:),3);
case4m = all(bsxfun(#eq,M2d(:,1:4),[0 0 0 1]),2);
M2d(case4m,:) = bsxfun(#times,M2d(case4m,:),4);
%// Cut the 2D array thus obtained at every size(a,1) to give us back a 3D
%// array version of the expected values
Mout = permute(reshape(M2d,size(M,1),size(M,3),[]),[1 3 2])
Code run with a random 6 x 4 x 2 sized input array -
M(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 1 1
1 0 0 0
1 0 1 1
M(:,:,2) =
0 1 0 1
1 1 0 0
1 1 0 0
0 0 1 1
0 0 0 1
0 0 1 0
Mout(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 3 3
1 0 0 0
1 0 1 1
Mout(:,:,2) =
0 2 0 2
1 1 0 0
1 1 0 0
0 0 3 3
0 0 0 4
0 0 3 0

count node degree in matlab from a adjacency matrix

this is my matrix that displays a sample network graph
matrix =
0 1 1 1
1 0 1 0
0 0 0 1
1 1 1 0
where its a 4x4 matrix
1) 2) 3) 4)
1) 0 1 1 1
2) 1 0 1 0
3) 0 0 0 1
4) 1 1 1 0
i want to count this 4x4 matrix like
row 1 counts how many 1s i have and adds column 1 number of 1's to it and returns 1)=5 as total 1's in row 1 and col 1 = 5
i want my output to be like
1=5
2=4
3=4
4=5
This must be it -
out = sum([matrix matrix'],2)
Example run -
matrix =
1 1 1 1
1 0 0 0
0 1 0 1
0 0 1 1
out =
6
3
4
5
The above code would count 1s twice when they appear on the diagonal, which if you don't want, use this -
out1 = sum([matrix matrix'],2) - diag(matrix)
Example run -
matrix =
1 1 1 1
1 0 0 0
0 1 0 1
0 0 1 1
out1 =
5
3
4
4
I agree with the answer of Divakar, but once your graph gets larger and larger, you might not want to transpose the entire matrix. I suggest doing the sum first and then transposing afterwards:
sum(matrix,1)'+sum(matrix,2)-diag(matrix);
matrix =
0 1 1 1
1 0 1 0
0 0 0 1
1 1 1 0
degree=sum(matrix,1)'+sum(matrix,2)-diag(matrix)
degree =
5
4
4
5

how to keep zero at last without using sort [duplicate]

This question already has an answer here:
Sort in ascending order, but keep zeros at last
(1 answer)
Closed 9 years ago.
I have a matrix like below-
x=[1 1 1 1 1;
2 1 1 1 0;
3 3 1 0 0;
3 2 2 0 0];
But i want to make this matrix like-
x=[2 2 3 0 0;
1 3 3 0 0;
1 1 1 2 0;
1 1 1 1 1];
I have already tried with "sort ascending" but then '0' will come first but i want to keep "0" on last and make one matrix where the number of '1's' will be from low to high throughout the matrix.I am trying but cannot do so.
I need Matlab experts help.
To get the zeros at the end, set them to infinity (inf), sort and then set them back to zero
x=[1 1 1 1 1;
2 1 1 1 0;
3 3 1 0 0;
3 2 2 0 0]
x(x == 0) = inf;
y = sort(x, 2, 'ascend');
y(y==inf) = 0;
Now count the number of 1s per row and reorder from least to most
[~, I] = sort(sum(y==1,2));
y(I, :)
ans =
2 2 3 0 0
1 3 3 0 0
1 1 1 2 0
1 1 1 1 1
EDIT:
The example data is ambiguous. Take this as the input:
x=[1 1 1 1 1;
2 1 1 1 0;
7 1 0 1 0;
3 3 1 0 0;
3 2 2 0 0];
Now the answers by Moshen (i.e. to just sort each column after sorting the rows) return
x =
2 3 7 0 0
1 2 3 0 0
1 1 3 0 0
1 1 1 2 0
1 1 1 1 1
Whereas mine returns
ans =
2 2 3 0 0
1 3 3 0 0
1 1 7 0 0
1 1 1 2 0
1 1 1 1 1
Mine preserves the row integrity. But it is not clear which answer the OP is after.