I have a quick graph theory question.
I have a 13 x 13 adjacency matrix in Matlab. I've already taken just the lower diagonal (this is an undirected graph) and subtracted off the identity matrix (so there aren't edges joining a node to itself). I then added a column on the left and a row on the top with the ID numbers of the four nodes. The resulting 14 x 14 adjacency matrix looks like this:
A =
0 1 1 1 1 2 2 2 3 3 3 4 4 4
1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0
2 1 0 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 0 0 0
3 0 0 1 0 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0 0 0 0 0
3 0 1 0 0 0 0 0 0 0 0 0 0 0
4 1 0 0 0 1 0 0 0 0 0 0 0 0
4 0 0 0 1 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 1 0 0 0 0 0 0
How can I create the coordinate array from this? I know the result should have 7 rows (one for each unique node pair).
Please let me know if you can help. Thanks in advance!
We can use the node IDs that are provided at the first row and first column to help us create a node adjacency list. What we need to do is split up the variables so that we separate out the first row, called rowList and the first column colList. We will denote these the row and column lists respectively. We will also extract the adjacency matrix which is the rest of the matrix. The basic algorithm is the following:
Find those rows and columns that are non-zero in the adjacency matrix.
Use these rows and columns to index the corresponding rows and columns lists and spit out a co-ordinate array.
Without further ado:
rowList = A(2:end,1);
colList = A(1,2:end).';
AdjMatr = A(2:end,2:end);
[nonZeroRows, nonZeroCols] = find(AdjMatr);
nodeList = [rowList(nonZeroRows) colList(nonZeroCols)];
The output thus gives:
nodeList =
2 1
4 1
3 1
3 1
4 1
4 2
4 2
This answer does not give unique rows of course, and produces duplicates. If you wish to have unique rows, consider doing:
nodeListUnique = unique(nodeList, 'rows');
The output is:
nodeListUnique =
2 1
3 1
4 1
4 2
It appears that what you want is:
[ii, jj] = find(A(2:end,2:end)); %// row and col indices of ones in inner matrix
result = [ A(ii+1,1) A(1,jj+1).' ]; %'// node numbers corresponding to ii and jj
In your example, this gives
result =
2 1
4 1
3 1
3 1
4 1
4 2
4 2
If you need unique rows:
result = unique(result, 'rows');
which gives
result =
2 1
3 1
4 1
4 2
Related
I have a column vector x made up of 4 elements, how can i generate all the possible combinations of the values that x can take such that x*x' is less than or equal to a certain value?
note that the values of x are positive and integers.
To be more clear:
the input is the number of elements of the column vector x and the threshold, the output are the different possible combinations of the values of x respecting the fact that x*x' <=threshold
Example: threshold is 4 and x is a 4*1 column vector.....the output is x=[0 0 0 0].[0 0 0 1],[1 1 1 1]......
See if this works for you -
threshold = 4;
A = 0:threshold
A1 = allcomb(A,A,A,A)
%// Or use: A1 = combvec(A,A,A,A).' from Neural Network Toolbox
combs = A1(sum(A1.^2,2)<=threshold,:)
Please note that the code listed above uses allcomb from MATLAB File-exchange.
Output -
combs =
0 0 0 0
0 0 0 1
0 0 0 2
0 0 1 0
0 0 1 1
0 0 2 0
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
0 2 0 0
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
2 0 0 0
I want to access multiple indices of a matrix as shown below. So what I want is indices (1,3),(2,6),(3,7) to be set to one. However, as you can see the entire column is set to one. I can see what it is doing but is there a way to do what I want it to (in an elegant way - no loops).
a=zeros(3,10)
a(1:3,[3 6 7])=1
a =
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
I realise that you can do something along the lines of
x_idx=1:3, y_idx=[3 6 7];
idx=x_idx*size(a,2)+y_idx;
a(idx)=1;
but just wondering if there was a better, or proper way of doing this in Matlab
You can use sub2ind, which essentially is doing what you have mentioned in your post, but MATLAB has this built-in:
a = zeros(3,10);
a(sub2ind(size(a), 1:3, [3 6 7])) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
Another way would be to create a logical sparse matrix, then use this to index into a:
a = zeros(3,10);
ind = logical(sparse(1:3, [3 6 7], true, size(a,1), size(a,2)));
a(ind) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
This question already has answers here:
Creating Indicator Matrix
(6 answers)
Closed 8 years ago.
I have a 1118x1 vector of values from 0 to 10 as such:
5
5
3
4
7
4
1
.
.
I need to encode each value into a 11x1118 Matrix of zeros where the k+1th values is a 1.
For example the first value is a 5 so the 5+1=6 value in the first column with be 1
0
0
0
0
0
1
0
0
0
0
0
I need to do this for all values up to 1118.
I assume I just need a for loop but am completely lost as to how to do it
You can use for example sub2ind. Try the following code:
x = [4;3;1;1;4;7];
y = zeros(11,numel(x));
y(sub2ind(size(y),x+1,(1:numel(x))')) = 1
y =
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 1 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Or a direct approach using loop:
v = [5 5 3 4 7 4 1...]; # your vector
M = zeros(11, length(v)); # the final matrix
for i = 1:length(v)
e = v(i);
M(e + 1, i) = 1;
end
A=[1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0;
0 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 1 2 3 4 5 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5;
0 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0;
0 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0];
What is code to count number "1" in the column which only has elements which have value greater than 1 and less than 4.
note: zeros is ignored.
Thus, My expected output is res = 1 which is in second column only.
Here is what I tried:
res = sum( sum(A(2 :end,all(A>1&A<4))==1, 2),1 );
but zeros are still being counted in my code.
If I understand it correctly, you could do it this way:
Start by finding all columns that violate the first rule that elements of A my not be greater than 4
[~, del, ~] = find(A>=4)
Remove those columns:
A(:, unique(del)) = []
Which gives:
A =
1 2 3 0 0 0 0 0
0 1 2 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 2 3
0 0 0 2 3 0 0 0
0 0 0 2 3 0 0 0
Now we find all remaining columns that have a 1:
[~, c1, ~] = find(A == 1);
And all columns that have at least one value greater than 1 following the second requirement:
[~, c2, ~] = find(A > 1)
These vectors c1 and c2 with the column numbers we then simply intersect and count:
numel(intersect(c1, c2))
Now there are plenty of Matlab wizards on this forum, and my instinct tells me there is a better answer, so perhaps you should wait a bit.
I have matrix A
A= [0 0 2 2 2 2 0 0 1 1 1 0 3 3;
2 2 2 2 0 0 1 1 1 0 0 3 3 0;
As you can see, there are consecutive numbers in it; notice for example the 2 2 2 2 on the first and second row.
For each number occuring in this matrix (or at least for every number from 1 to the maximum number in my matrix) I want to have an output matrix that indicates sequences of this number and this number only in the original matrix.
So for example, for 1: there are three consecutive numbers on the first row and three on the second row: I want to indicate this in the first output matrix as follows:
Matrix 1 = [ 0 0 0 0 0 0 0 0 1 2 3 0 0 0;
0 0 0 0 0 0 0 1 2 3 0 0 0 0]
Same for number 2:
Matrix 2 = [ 0 0 1 2 3 4 0 0 0 0 0 0 0 0;
1 2 3 4 0 0 0 0 0 0 0 0 0 0]
and 3:
Matrix 3 = [ 0 0 0 0 0 0 0 0 0 0 0 0 1 2;
0 0 0 0 0 0 0 0 0 0 0 1 2 0]
As you can see, each output matrix shows counting forward for the consecutive occurrences of a number.
So in this case, I have 3 output matrices because matrix A has 3 as the biggest value there.
You can try this:
A= [0 0 2 2 2 2 0 0 1 1 1 0 3 3;
2 2 2 2 0 0 1 1 1 0 0 3 3 0];
result = arrayfun(#(b) (A == b).*cumsum((A == b),2),nonzeros(unique(A)), 'UniformOutput', false);
For this example, there will be 3 submatrices in the variable result.
result =
[2x14 double]
[2x14 double]
[2x14 double]
To access them, use the following syntax:
result{1}
result{2}
result{3}
Then you get:
ans =
0 0 0 0 0 0 0 0 1 2 3 0 0 0
0 0 0 0 0 0 1 2 3 0 0 0 0 0
ans =
0 0 1 2 3 4 0 0 0 0 0 0 0 0
1 2 3 4 0 0 0 0 0 0 0 0 0 0
ans =
0 0 0 0 0 0 0 0 0 0 0 0 1 2
0 0 0 0 0 0 0 0 0 0 0 1 2 0
~edit~
If, as asked in the comments, A is a 3D matrix, this code works just the same, but the structure of result is a bit different:
result =
[2x14x2 double]
[2x14x2 double]
[2x14x2 double]
To access these matrices, use for instance
result{1}(:,:,1) % for the results of comparing A(:,:,1) with value 1
result{1}(:,:,2) % for the results of comparing A(:,:,2) with value 1
Edited because the question changed
This is nowhere near to optimal but will do what you want
V = 1;
C = A' == V;
D = cumsum(C).*C
E = D'
now E will be Matrix1 in your example. Change V to 2 and 3 to obtain Matrix2 and Matrix3. If you have something like
A = [2 2 2 0 0 0 0 0 2 2 2]
then you will get
[1 2 3 0 0 0 0 0 4 5 6]
so it may not be what you want. It is not clear from your question if this is the case or not, but if not tell me and I will delete the answer
This is a loop-based solution to get you started:
A = [
0 0 2 2 2 2 0 0 1 1 1 0 3 3;
2 2 2 2 0 0 1 1 1 0 0 3 3 0
];
mx = max(A(:));
AA = cell(mx,1);
for num=1:mx
AA{num} = zeros(size(A));
for r=1:size(A,1)
idx = ( A(r,:) == num );
AA{num}(r,idx) = sum(idx):-1:1;
end
end
The result:
>> AA{1}
ans =
0 0 0 0 0 0 0 0 3 2 1 0 0 0
0 0 0 0 0 0 3 2 1 0 0 0 0 0
>> AA{2}
ans =
0 0 4 3 2 1 0 0 0 0 0 0 0 0
4 3 2 1 0 0 0 0 0 0 0 0 0 0
>> AA{3}
ans =
0 0 0 0 0 0 0 0 0 0 0 0 2 1
0 0 0 0 0 0 0 0 0 0 0 2 1 0
EDIT:
Updated code to work on matrix with three dimensions:
A = zeros(2,7,2);
A(:,:,1) = [2 2 2 0 0 1 1 ; 0 0 2 2 2 1 1];
A(:,:,2) = [1 1 2 2 2 0 0 ; 0 1 1 0 2 2 2];
mx = max(A(:));
AA = cell(mx,1);
for num=1:mx
AA{num} = zeros(size(A));
for p=1:size(A,3)
for r=1:size(A,1)
idx = ( A(r,:,p) == num );
AA{num}(r,idx,p) = 1:sum(idx);
end
end
end
The result:
%# contains consecutive numbers corresponding to number 1 in all slices
>> AA{1}
ans(:,:,1) =
0 0 0 0 0 1 2
0 0 0 0 0 1 2
ans(:,:,2) =
1 2 0 0 0 0 0
0 1 2 0 0 0 0
%# contains consecutive numbers corresponding to number 2 in all slices
>> AA{2}
ans(:,:,1) =
1 2 3 0 0 0 0
0 0 1 2 3 0 0
ans(:,:,2) =
0 0 1 2 3 0 0
0 0 0 0 1 2 3