wolffd@0
|
1
|
wolffd@0
|
2 % make undirected adjacency matrix of graph/tree
|
wolffd@0
|
3 % e.g.,
|
wolffd@0
|
4 % 1
|
wolffd@0
|
5 % / \
|
wolffd@0
|
6 % 2 3
|
wolffd@0
|
7 T = zeros(3,3);
|
wolffd@0
|
8 T(1,2) = 1; T(2,1)=1;
|
wolffd@0
|
9 T(1,3)=1; T(3,1) = 1;
|
wolffd@0
|
10
|
wolffd@0
|
11 root = 1;
|
wolffd@0
|
12 [T, preorder, postorder] = mk_rooted_tree(T, root);
|
wolffd@0
|
13
|
wolffd@0
|
14 % bottom up message passing leaves to root
|
wolffd@0
|
15 for n=postorder(:)'
|
wolffd@0
|
16 for p = parents(T, n)
|
wolffd@0
|
17 % p is parent of n
|
wolffd@0
|
18 end
|
wolffd@0
|
19 end
|
wolffd@0
|
20
|
wolffd@0
|
21 % top down, root to leaves
|
wolffd@0
|
22 for n=preorder(:)'
|
wolffd@0
|
23 for c= children(T,n)
|
wolffd@0
|
24 % c is child of n
|
wolffd@0
|
25 end
|
wolffd@0
|
26 end
|
wolffd@0
|
27
|
wolffd@0
|
28
|
wolffd@0
|
29 %%%%%%%%%%%%%
|
wolffd@0
|
30
|
wolffd@0
|
31 function ps = parents(adj_mat, i)
|
wolffd@0
|
32 % PARENTS Return the list of parents of node i
|
wolffd@0
|
33 % ps = parents(adj_mat, i)
|
wolffd@0
|
34
|
wolffd@0
|
35 ps = find(adj_mat(:,i))';
|
wolffd@0
|
36
|
wolffd@0
|
37
|
wolffd@0
|
38 %%%%%%%%%%%%
|
wolffd@0
|
39
|
wolffd@0
|
40 function cs = children(adj_mat, i, t)
|
wolffd@0
|
41 % CHILDREN Return the indices of a node's children in sorted order
|
wolffd@0
|
42 % c = children(adj_mat, i, t)
|
wolffd@0
|
43 %
|
wolffd@0
|
44 % t is an optional argument: if present, dag is assumed to be a 2-slice DBN
|
wolffd@0
|
45
|
wolffd@0
|
46 if nargin < 3
|
wolffd@0
|
47 cs = find(adj_mat(i,:));
|
wolffd@0
|
48 else
|
wolffd@0
|
49 if t==1
|
wolffd@0
|
50 cs = find(adj_mat(i,:));
|
wolffd@0
|
51 else
|
wolffd@0
|
52 ss = length(adj_mat)/2;
|
wolffd@0
|
53 j = i+ss;
|
wolffd@0
|
54 cs = find(adj_mat(j,:)) + (t-2)*ss;
|
wolffd@0
|
55 end
|
wolffd@0
|
56 end
|
wolffd@0
|
57
|
wolffd@0
|
58 %%%%%%%%%%%
|
wolffd@0
|
59
|
wolffd@0
|
60 function [T, pre, post, cycle] = mk_rooted_tree(G, root)
|
wolffd@0
|
61 % MK_ROOTED_TREE Make a directed, rooted tree out of an undirected tree.
|
wolffd@0
|
62 % [T, pre, post, cycle] = mk_rooted_tree(G, root)
|
wolffd@0
|
63
|
wolffd@0
|
64 n = length(G);
|
wolffd@0
|
65 T = sparse(n,n); % not the same as T = sparse(n) !
|
wolffd@0
|
66 directed = 0;
|
wolffd@0
|
67 [d, pre, post, cycle, f, pred] = dfs(G, root, directed);
|
wolffd@0
|
68 for i=1:length(pred)
|
wolffd@0
|
69 if pred(i)>0
|
wolffd@0
|
70 T(pred(i),i)=1;
|
wolffd@0
|
71 end
|
wolffd@0
|
72 end
|
wolffd@0
|
73
|
wolffd@0
|
74
|
wolffd@0
|
75 %%%%%%%%%%%
|
wolffd@0
|
76
|
wolffd@0
|
77 function [d, pre, post, cycle, f, pred] = dfs(adj_mat, start, directed)
|
wolffd@0
|
78 % DFS Perform a depth-first search of the graph starting from 'start'.
|
wolffd@0
|
79 % [d, pre, post, cycle, f, pred] = dfs(adj_mat, start, directed)
|
wolffd@0
|
80 %
|
wolffd@0
|
81 % Input:
|
wolffd@0
|
82 % adj_mat(i,j)=1 iff i is connected to j.
|
wolffd@0
|
83 % start is the root vertex of the dfs tree; if [], all nodes are searched
|
wolffd@0
|
84 % directed = 1 if the graph is directed
|
wolffd@0
|
85 %
|
wolffd@0
|
86 % Output:
|
wolffd@0
|
87 % d(i) is the time at which node i is first discovered.
|
wolffd@0
|
88 % pre is a list of the nodes in the order in which they are first encountered (opened).
|
wolffd@0
|
89 % post is a list of the nodes in the order in which they are last encountered (closed).
|
wolffd@0
|
90 % 'cycle' is true iff a (directed) cycle is found.
|
wolffd@0
|
91 % f(i) is the time at which node i is finished.
|
wolffd@0
|
92 % pred(i) is the predecessor of i in the dfs tree.
|
wolffd@0
|
93 %
|
wolffd@0
|
94 % If the graph is a tree, preorder is parents before children,
|
wolffd@0
|
95 % and postorder is children before parents.
|
wolffd@0
|
96 % For a DAG, topological order = reverse(postorder).
|
wolffd@0
|
97 %
|
wolffd@0
|
98 % See Cormen, Leiserson and Rivest, "An intro. to algorithms" 1994, p478.
|
wolffd@0
|
99
|
wolffd@0
|
100 n = length(adj_mat);
|
wolffd@0
|
101
|
wolffd@0
|
102 global white gray black color
|
wolffd@0
|
103 white = 0; gray = 1; black = 2;
|
wolffd@0
|
104 color = white*ones(1,n);
|
wolffd@0
|
105
|
wolffd@0
|
106 global time_stamp
|
wolffd@0
|
107 time_stamp = 0;
|
wolffd@0
|
108
|
wolffd@0
|
109 global d f
|
wolffd@0
|
110 d = zeros(1,n);
|
wolffd@0
|
111 f = zeros(1,n);
|
wolffd@0
|
112
|
wolffd@0
|
113 global pred
|
wolffd@0
|
114 pred = zeros(1,n);
|
wolffd@0
|
115
|
wolffd@0
|
116 global cycle
|
wolffd@0
|
117 cycle = 0;
|
wolffd@0
|
118
|
wolffd@0
|
119 global pre post
|
wolffd@0
|
120 pre = [];
|
wolffd@0
|
121 post = [];
|
wolffd@0
|
122
|
wolffd@0
|
123 if ~isempty(start)
|
wolffd@0
|
124 dfs_visit(start, adj_mat, directed);
|
wolffd@0
|
125 else
|
wolffd@0
|
126 for u=1:n
|
wolffd@0
|
127 if color(u)==white
|
wolffd@0
|
128 dfs_visit(u, adj_mat, directed);
|
wolffd@0
|
129 end
|
wolffd@0
|
130 end
|
wolffd@0
|
131 end
|
wolffd@0
|
132
|
wolffd@0
|
133
|
wolffd@0
|
134 %%%%%%%%%%
|
wolffd@0
|
135
|
wolffd@0
|
136 function dfs_visit(u, adj_mat, directed)
|
wolffd@0
|
137
|
wolffd@0
|
138 global white gray black color time_stamp d f pred cycle pre post
|
wolffd@0
|
139
|
wolffd@0
|
140 pre = [pre u];
|
wolffd@0
|
141 color(u) = gray;
|
wolffd@0
|
142 time_stamp = time_stamp + 1;
|
wolffd@0
|
143 d(u) = time_stamp;
|
wolffd@0
|
144 if directed
|
wolffd@0
|
145 ns = children(adj_mat, u);
|
wolffd@0
|
146 else
|
wolffd@0
|
147 ns = neighbors(adj_mat, u);
|
wolffd@0
|
148 ns = mysetdiff(ns, pred(u)); % don't go back to visit the guy who called you!
|
wolffd@0
|
149 end
|
wolffd@0
|
150 for v=ns(:)'
|
wolffd@0
|
151 %fprintf('u=%d, v=%d, color(v)=%d\n', u, v, color(v))
|
wolffd@0
|
152 switch color(v)
|
wolffd@0
|
153 case white, % not visited v before (tree edge)
|
wolffd@0
|
154 pred(v)=u;
|
wolffd@0
|
155 dfs_visit(v, adj_mat, directed);
|
wolffd@0
|
156 case gray, % back edge - v has been visited, but is still open
|
wolffd@0
|
157 cycle = 1;
|
wolffd@0
|
158 %fprintf('cycle: back edge from v=%d to u=%d\n', v, u);
|
wolffd@0
|
159 case black, % v has been visited, but is closed
|
wolffd@0
|
160 % no-op
|
wolffd@0
|
161 end
|
wolffd@0
|
162 end
|
wolffd@0
|
163 color(u) = black;
|
wolffd@0
|
164 post = [post u];
|
wolffd@0
|
165 time_stamp = time_stamp + 1;
|
wolffd@0
|
166 f(u) = time_stamp;
|
wolffd@0
|
167
|
wolffd@0
|
168
|