matlab - too many loops finding paths array from Adjacency - matlab

Like the title says I would like to make the code faster and easier to read.
I have an Adjacency matrix:
Ad=[ 0 1 0 0 1 0 0 0 0 0;
1 0 0 0 0 0 0 0 0 0;
1 0 0 1 1 0 0 0 0 0;
0 0 1 0 0 1 0 0 0 0;
1 0 1 0 0 1 0 0 0 0;
0 0 0 1 1 0 0 0 0 0;
0 0 0 0 0 0 0 1 1 0;
0 0 0 0 0 0 1 0 0 1;
0 0 0 0 0 0 1 0 0 1;
0 0 0 0 0 0 0 1 1 0];
and a Name={'a';'b';'c';'d';'E';'F';'a';'E';'d';'F'}; that I will use for describing a type of "planet".
After finding out some new words from past comments from deleted questions, I could come up with a start:
dig=digraph(Ad, Name);
[Num.Nodes,Num.Null]=size(dig.Nodes);
for j2=1:Num.Nodes
dfs{j2}=dfsearch(dig,(j2),'allevents');
Num.node2path=dfs{j2}.Node;
Num.tokeep = ~isnan(Num.node2path);
Num.node2path = Num.node2path(Num.tokeep);
Num.node2path(1)=[];
[Num.node2path2,Num.Null]=size(Num.node2path);
for i2=1:Num.node2path2-1
if Num.node2path(i2)==Num.node2path(i2+1)
path{j2,i2}=Num.node2path(1:i2);Num.node2path(i2)=1000;Num.node2path(i2+1)=1001;
if Num.node2path(i2-1)==Num.node2path(i2+2)
Num.node2path(i2-1)=1002;Num.node2path(i2+2)=1003;
end
end
end
end
path = path(~cellfun('isempty',path));
[Num.clear1000,Num.degeaba] = size(path);
for i3=1:Num.clear1000
Num.is1000 = find(path{i3}(:) == 1000);
path{i3}(Num.is1000)=[];
Num.is1000 = find(path{i3}(:) == 1001);
path{i3}(Num.is1000)=[];
Num.is1000 = find(path{i3}(:) == 1002);
path{i3}(Num.is1000)=[];
Num.is1000 = find(path{i3}(:) == 1003);
path{i3}(Num.is1000)=[];
end
The thing is I feel it is getting too complicated with too many loops and I haven't even got to having the result I wanted. For example the path between '2' and '6' would be [2;1;5;3;4;6] and could be found with some more loops looking for path{i4}(1); equal to 2 and path{i4}(end); equal to 6, i4 being 10.
So after finding all paths I would like to rename the paths using Name, since I assign the same name to the same kind of "planet". Next I will choose the shortest path to the "best planet".
The paths being now in the form of [a;E;d] are compared to paths of Ad2 and Name2. Paths with the same Name are going to be saved and compared if they have similar distances from the first "planet" to the last one, just like the one that started the search. I quote "planets" because they may be stars, asteroids, and even these are categorized so this is where Name is coming from.

Related

matlab's imfill function seems bugged?

I need to work with imfill in Matlab (Version 2010b, 7.11.0). I now think there is a bug in the program.
The most simple example that i found here is following: (Fills the Image background (0) beginning at the position [4 3])
BW = [ 0 0 0 0 0 0 0 0;
0 1 1 1 1 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 1 1 1 0 0 0;
0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0];
imfill(BW,[4 3])
According to the specifications this should work IMHO, but I always get following message. Can anyone tell me what I am doing wrong?
??? Error using ==> iptcheckconn at 56
Function IMFILL expected its second input argument, CONN,
to be a valid connectivity specifier.
A nonscalar connectivity specifier must be 3-by-3-by- ...
-by-3.
Error in ==> imfill>parse_inputs at 259
iptcheckconn(conn, mfilename, 'CONN', conn_position);
Error in ==> imfill at 124
[I,locations,conn,do_fillholes] = parse_inputs(varargin{:});
Error in ==> test at 9
imfill(BW,[4 3])
That does not explain the problem but converting BW to a logical array does work. I'm not sure as to why it's like this though:
clear
close all
clc
BW = [ 0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0];
BW2 = imfill(logical(BW),[4 3])
BW2 =
0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
As you have already seen in the other solution by #Benoit_11, that most probably that input wasn't of logical class, which was throwing an error at you. So, you are set there!
Now, I would like to put forth a tiny bit of bonus suggestion here.
Let's suppose you have a set of seed points with their row and column IDs and you would like to fill an image with those seed points in one go. For that case,
you need to use those IDs as column vectors. Thus, if you have the row and column IDs as -
row_id = [4 3];
col_id = [3 7];
You can fill image with this -
BW = imfill(BW,[row_id(:) col_id(:)])
But, the following code would throw error at you -
BW = imfill(BW,[row_id col_id])

To print the n nodes of maximum degree with Matlab

I need a matlab script that is going to return the n nodes of maximum degree in a graph.
For exemple:
N = maxnodes(Graph,n)
Graph is a matrix
n the number of nodes that we need
N is a vector that conatains the n nodes.
Here is my source code (script). But it doesn't work well.
M = [0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0;
1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0;
0 0 1 1 0 1 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;
1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0;
0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1;
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0;
0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0;
0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0;
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1;
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0;];
n = 5; % The number of nodes that we want
G=[]; % I'll store here the n nodes of maximum degree
for i=1:size(M)
G1(1,i)=sum(M(i,:)); % I'm storing each node with its degree in G1
G1(2,i)=i;
C(1,i)=G1(1,i); %I store only degree of nodes
end
C1 = sort(C,'descend'); % I sort "descendly" the degrees of nodes
for i=1:n %We want to take only the n nodes that we need and save it in C2
C2(1,i) = C1(1,i);
end
C2; % This vector stores the n descend maximum degrees that I need.
%My actual problem is here. How could I find the node that correspond to each degree?
%I tried to do it with the following loop:
for j=1:n
for i=1:size(M)
if C2(1,j) == G1(1,i)
G2(1,j)=G1(2,i);
end
end
end %But this loop doesn't store well the nodes in G2 because it repeats nodes.
G2
You have absolutely shown no effort so you actually shouldn't be getting any help from anyone.... but I love graph problems, so I'll throw you a bone.
I'm going to assume that Graph is an adjacency matrix, where each element (i,j) in the matrix corresponds to an edge connected between the two nodes i and j. I also am assuming that you have an undirected graph as input. If you examine the nature of the adjacency matrix (that Wikipedia article has a great example), it's not hard to see that the degree of a node i is simply the sum over all of the columns of row i in the adjacency matrix. Recall that the degree is defined as the total number of edges connected to a particular node. As such, all you have to do is sum over all of the columns for each row, and determine the rows that have the largest degree in your graph. Once we do this, we simply return the nodes that have this largest degree, which is up to n.
However, we will put in a safeguard where if we specify n to be larger than number of nodes having this maximum degree, we will cap it so that we only show up to this many nodes rather than n.
Therefore:
function [N] = maxnodes(Graph, n)
%// Find degrees of each node
degs = sum(Graph, 2);
%// Find those nodes that have the largest degree
locs = find(degs == max(degs));
%// If n is larger than the total number of nodes
%// having this maximum degree, then cap it
if n > numel(locs)
n = numel(locs);
end
%// Return those nodes that have this maximum degree
N = locs(1:n);
Here is a script that works very well and solves my problem. Otherwise, I would have liked well that my source code above would be debug.
function N = maxnodes(M,n)
nb1_rows= sum(M,2);
[nbs,is] = sort(nb1_rows,'descend');
N = transpose(is(1:n));

Measure how spread out the data in an array is

I have an array of zeros and ones and I need to know if the data is spread out across the columns or concentrated in clumps.
For example:
If I have array x and it has these values:
Column 1 values: 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
Column 2 values: 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 1
if we counted the number of ones we can know that it is the same number but the ones are more well spread out and distributed in column 2 compared with column 1.
I am trying to make a score that gives me a high value if the spreading is good and low value if the spreading is bad... any ideas??
Sample of Data:
1 0 0 0 5 0 -2 -3 0 0 1
1 0 0 0 0 0 0 0 0 0 1
2 0 0 0 0 0 0 3 -3 1 0
1 2 3 0 5 0 2 13 4 5 1
1 0 0 0 0 0 -4 34 0 0 1
I think what you're trying to measure is the variance of the distribution of the number of 0s between the 1s, i.e:
f = #(x)std(diff(find(x)))
So for you data:
a = [1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1]
b = [1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 1]
f(a)
= 8.0498
f(b)
= 2.0736
But I still think you're essentially trying to measure the disorder of the system which is what I imagine entropy measures but I don't know how
Note that this gives a low value if the "spreading" is good and a high value if it is bad (i.e. the opposite of your request).
Also if you want it per column then it becomes a little more complicated:
f = #(x)arrayfun(#(y)std(diff(find(x(:,y)))), 1:size(x,2))
data = [a', b'];
f(data)
WARNING: This method pretty much does not consider trailing and leading 0s. I don't know if that's a problem or not. but basically f([0; 0; 0; 1; 1; 1; 0; 0; 0]) returns 0 where as f([1; 0; 0; 1; 0; 1; 0; 0; 0]) returns a positive indicating (incorrectly) that first case is more distributed. One possible fix might be to prepend and append a row of ones to the matrix...
I think you would need an interval to find the "spreadness" locally, otherwise the sample 1 (which is named as Column 1 in the question) would appear as spread too between the 2nd and 3rd ones.
So, following that theory and assuming input_array to be the input array, you can try this approach -
intv = 10; %// Interval
diff_loc = diff(find(input_array))
spread_factor = sum(diff_loc(diff_loc<=intv)) %// desired output/score
For sample 1, spread_factor gives 4 and for sample 2 it is 23.
Another theory that you can employ would be if you assume an interval such that distance between consecutive ones must be greater than or equal to that interval. This theory would lead us to a code like this -
intv = 3; %// Interval
diff_loc = diff(find(input_array))
spread_factor = sum(diff_loc>=intv)
With this new approach - For sample 1, spread_factor is 1 and for sample 2 it is 5.

a command to view result on matlab for the tarjan algorithm

I'm working on an implementation of the Tarjan algorithm in Matlab.
I use this source code to determine the strongly connected components.
This is the result I got, how can I view the result with Matlab (a figure that determines the colored strongly connected components)?
What is the appropriate command?
G=[0 0 1 1 0 0 0;
1 0 0 0 0 0 0;
0 0 0 0 0 1 0;
0 0 0 0 1 0 0;
0 0 0 0 0 0 1;
0 0 0 1 0 0 0;
0 0 0 0 0 1 0];
tarjan(G)
ans =
7 5 4 6 0 0 0
3 0 0 0 0 0 0
1 0 0 0 0 0 0
2 0 0 0 0 0 0
There is already an examle using coloring, all nodes listed in the first row are colored with the first color, all nodes listed in the second row are colored with the second color etc...

Matlab: sort an array to ascending order in terms of binary interpretation

The array contains binary numbers per line: one row means one binary number. They are in no order so I am trying to find a command by which I can sort them to ascending order, how to do it?
Input
>> [1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0]
ans =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
Goal: by which command I can get by the input the below output?
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
You can do it by converting to strings (num2str) and then from binary string to number (bin2dec):
[vv ii] = sort(bin2dec(num2str(data)));
data_sorted = data(ii,:);
Based on my suggestion in the comments, "you should be able to do a radix sort using sortrows on columns n down to 1.", the OP got the following code working:
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1];sortrows(A)
ans =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
And has now included Luis' cool idea for indexing.
Beaker answered in the comment "you should be able to do a radix sort using sortrows on columns n down to 1." -- and it works! Then Luis Mendo had a method to store the original positioning so putting the ideas together, vuola!
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1]
[vv ii]=sortrows(A)
A =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
vv =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
ii =
4
2
1
3