wolffd@0
|
1 function [jtree, root, cliques, B, w] = mk_strong_jtree(cliques, ns, elim_order, MTG)
|
wolffd@0
|
2 % MK_SRONG_JTREE Make a strong junction tree.
|
wolffd@0
|
3 % [jtree, root, cliques, B, w] = mk_strong_jtree(cliques, ns, elim_order, MTG)
|
wolffd@0
|
4 %
|
wolffd@0
|
5 % Here is a definition of a strong jtree from Jensen et al. 1994:
|
wolffd@0
|
6 % "A junction tree is said to be strong if it has at least one distinguished clique R,
|
wolffd@0
|
7 % called a strong root, s.t. for each pair (C1,C2) of adjacent cliques in the tree,
|
wolffd@0
|
8 % with C1 closer to R than C2, there exists and ordering of [the nodes below] C2
|
wolffd@0
|
9 % that respects [the partial order] and with the vertices of the separator C1 intersect C2
|
wolffd@0
|
10 % preceeding the vertices [below C2] of C2 \ C1."
|
wolffd@0
|
11 %
|
wolffd@0
|
12 % For details, see
|
wolffd@0
|
13 % - Jensen, Jensen and Dittmer, "From influence diagrams to junction trees", UAI 94.
|
wolffd@0
|
14 %
|
wolffd@0
|
15 % MTG is the moralized, triangulated graph.
|
wolffd@0
|
16 % elim_order is the elimination ordering used to compute MTG.
|
wolffd@0
|
17
|
wolffd@0
|
18
|
wolffd@0
|
19 % Warning: this is a very naive implementation of the algorithm in Jensen et al.
|
wolffd@0
|
20
|
wolffd@0
|
21 n = length(elim_order);
|
wolffd@0
|
22 alpha(elim_order) = n:-1:1;
|
wolffd@0
|
23 % alpha(u) = i if we eliminate u at step n-i+1
|
wolffd@0
|
24 % i.e., vertices with higher alpha numbers are eliminated before vertices with lower numbers.
|
wolffd@0
|
25 % e.g., from the Jensen et al paper
|
wolffd@0
|
26 % node a=1 eliminated at step 6, so alpha(a)=16-6+1=11.
|
wolffd@0
|
27 % alpha = [11 1 2 10 9 3 4 7 5 8 13 12 6 16 15 14]
|
wolffd@0
|
28
|
wolffd@0
|
29
|
wolffd@0
|
30 % We sort the cliques in order of increasing index. The index of a clique C is defined as follows.
|
wolffd@0
|
31 % Let lower = {u | alpha(u) < alpha(v)}, and
|
wolffd@0
|
32 % let v in C be the highest-numbered vertex s.t. the vertices in W = lower intersect C
|
wolffd@0
|
33 % have a common neighbor u in U, where U = lower \ C.
|
wolffd@0
|
34 % If such a v exists, define index(C) = alpha(v), otherwise, index(C) = 1.
|
wolffd@0
|
35 % Intuitively, index(C) is the step in the elimination process at which C disappears.
|
wolffd@0
|
36
|
wolffd@0
|
37 num_cliques = length(cliques);
|
wolffd@0
|
38 index = zeros(1, num_cliques);
|
wolffd@0
|
39 for c = 1:num_cliques
|
wolffd@0
|
40 C = cliques{c};
|
wolffd@0
|
41 highest_num = -inf;
|
wolffd@0
|
42 for vi = 1:length(C)
|
wolffd@0
|
43 v = C(vi);
|
wolffd@0
|
44 lower = find(alpha < alpha(v));
|
wolffd@0
|
45 W = myintersect(lower, C);
|
wolffd@0
|
46 U = mysetdiff(lower, C);
|
wolffd@0
|
47 found = 0;
|
wolffd@0
|
48 for ui=1:length(U)
|
wolffd@0
|
49 u = U(ui);
|
wolffd@0
|
50 if mysubset(W, neighbors(MTG, u))
|
wolffd@0
|
51 found = 1;
|
wolffd@0
|
52 break;
|
wolffd@0
|
53 end
|
wolffd@0
|
54 end
|
wolffd@0
|
55 if found
|
wolffd@0
|
56 if alpha(v) > highest_num
|
wolffd@0
|
57 highest_num = alpha(v);
|
wolffd@0
|
58 end
|
wolffd@0
|
59 end
|
wolffd@0
|
60 end
|
wolffd@0
|
61 if highest_num == -inf
|
wolffd@0
|
62 index(c) = 1;
|
wolffd@0
|
63 else
|
wolffd@0
|
64 index(c) = highest_num;
|
wolffd@0
|
65 end
|
wolffd@0
|
66 end
|
wolffd@0
|
67
|
wolffd@0
|
68
|
wolffd@0
|
69 % Permute the cliques so that they are ordered according to index
|
wolffd@0
|
70 [dummy, clique_order] = sort(index);
|
wolffd@0
|
71 cliques = cliques(clique_order);
|
wolffd@0
|
72
|
wolffd@0
|
73 w = zeros(num_cliques, 1);
|
wolffd@0
|
74 B = sparse(num_cliques, 1);
|
wolffd@0
|
75 for i=1:num_cliques
|
wolffd@0
|
76 B(i, cliques{i}) = 1;
|
wolffd@0
|
77 w(i) = prod(ns(cliques{i}));
|
wolffd@0
|
78 end
|
wolffd@0
|
79
|
wolffd@0
|
80 % Pearl p113 suggests ordering the cliques by rank of the highest vertex in each clique.
|
wolffd@0
|
81 % However, this will only work if we use maximum cardinality search.
|
wolffd@0
|
82
|
wolffd@0
|
83
|
wolffd@0
|
84 % Join up the cliques so that they satisfy the Running Intersection Property.
|
wolffd@0
|
85 % This states that, for all k > 1, S(k) subseteq C(j) for some j < k, where
|
wolffd@0
|
86 % S(k) = C(k) intersect (union_{i=1}^{k-1} C(i))
|
wolffd@0
|
87 jtree = sparse(num_cliques, num_cliques);
|
wolffd@0
|
88 for k=2:num_cliques
|
wolffd@0
|
89 S = [];
|
wolffd@0
|
90 for i=1:k-1
|
wolffd@0
|
91 S = myunion(S, cliques{i});
|
wolffd@0
|
92 end
|
wolffd@0
|
93 S = myintersect(S, cliques{k});
|
wolffd@0
|
94 found = 0;
|
wolffd@0
|
95 for j=1:k-1
|
wolffd@0
|
96 if mysubset(S, cliques{j})
|
wolffd@0
|
97 found = 1;
|
wolffd@0
|
98 break;
|
wolffd@0
|
99 end
|
wolffd@0
|
100 end
|
wolffd@0
|
101 if ~found
|
wolffd@0
|
102 disp(['RIP is violated for clique ' num2str(k)]);
|
wolffd@0
|
103 end
|
wolffd@0
|
104 jtree(k,j)=1;
|
wolffd@0
|
105 jtree(j,k)=1;
|
wolffd@0
|
106 end
|
wolffd@0
|
107
|
wolffd@0
|
108 % Pearl p113 suggests connecting Ci to a predecessor Cj (j < i) sharing
|
wolffd@0
|
109 % the highest number of vertices with Ci (i.e., the heaviest i-j edge
|
wolffd@0
|
110 % in the jgraph). However, this will only work if we use maximum cardinality search.
|
wolffd@0
|
111
|
wolffd@0
|
112 root = 1;
|
wolffd@0
|
113
|
wolffd@0
|
114
|