about summary refs log tree commit diff
path: root/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/find_mpe.m
blob: 63be5625ad04992a126a64aaf4a744f7d7cb2b86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
function mpe = find_mpe(engine, new_evidence, max_over)
% FIND_MPE Find the most probable explanation of the data (assignment to the hidden nodes)
% function mpe = find_mpe(engine, evidence, order)
%
% PURPOSE:
%       CALC_MPE Computes the most probable explanation to the network nodes
%       given the evidence.
%       
%       [mpe, ll] = calc_mpe(engine, new_evidence, max_over)
%
% INPUT:
%       bnet  - the bayesian network
%       new_evidence - optional, if specified - evidence to be incorporated [cell(1,n)]
%       max_over - optional, if specified determines the variable elimination order [1:n]
%
% OUTPUT:
%       mpe - the MPE assignmet for the net variables (or [] if no satisfying assignment)
%       ll - log assignment probability.
%
% Notes:
% 1. Adapted from '@var_elim_inf_engine\marginal_nodes' for MPE by Ron Zohar, 8/7/01
% 2. Only discrete potentials are supported at this time.
% 3. Complexity: O(nw*) where n is the number of nodes and w* is the induced tree width.
% 4. Implementation based on:
%  - R. Dechter, "Bucket Elimination: A Unifying Framework for Probabilistic Inference", 
%                 UA1 96, pp. 211-219.

bnet = bnet_from_engine(engine);
ns = bnet.node_sizes;
n = length(bnet.dag);
evidence = cell(1,n);
if (nargin<2)
    new_evidence = evidence;
end

onodes = find(~isemptycell(new_evidence));  % observed nodes
hnodes = find(isemptycell(new_evidence));  % hidden nodes
pot_type = determine_pot_type(bnet, onodes);

if pot_type ~= 'd'
  error('only disrete potentials supported at this time')    
end

for i=1:n
  fam = family(bnet.dag, i);
  CPT{i} = convert_to_pot(bnet.CPD{bnet.equiv_class(i)}, pot_type, fam(:), evidence);        
end 

% handle observed nodes: set impossible cases' probability to zero
% rather than prun matrix (this makes backtracking easier)

for ii=onodes
  lIdx = 1:ns(ii);
  lIdx = setdiff(lIdx, new_evidence{ii});
  
  sCPT=struct(CPT{ii});  % violate object privacy
  
  sargs = '';
  for jj=1:(length(sCPT.domain)-1)
    sargs = [sargs, ':,']; 
  end        
  for jj=lIdx
    eval(['sCPT.T(', sargs, num2str(jj), ')=0;']);
  end
  CPT{ii}=dpot(sCPT.domain, sCPT.sizes, sCPT.T);        
end

B = cell(1,n); 
for b=1:n
  B{b} = mk_initial_pot(pot_type, [], [], [], []);
end

if (nargin<3)
  max_over = (1:n);
end   
order = max_over; % no attempt to optimize this


% Initialize the buckets with the CPDs assigned to them
for i=1:n
  b = bucket_num(domain_pot(CPT{i}), order);
  B{b} = multiply_pots(B{b}, CPT{i});
end

% Do backward phase
max_over = max_over(length(max_over):-1:1); % reverse
maximize = 1;
for i=max_over(1:end-1)        
  % max-ing over variable i which occurs in bucket j
  j = bucket_num(i, order);
  rest = mysetdiff(domain_pot(B{j}), i);
  %temp = marginalize_pot_max(B{j}, rest);
  temp = marginalize_pot(B{j}, rest, maximize);
  b = bucket_num(domain_pot(temp), order);
  %        fprintf('maxing over bucket %d (var %d), putting result into bucket %d\n', j, i, b);
  sB=struct(B{b});  % violate object privacy
  if ~isempty(sB.domain)
    B{b} = multiply_pots(B{b}, temp);
  else
    B{b} = temp;
  end
end
result = B{1};
marginal = pot_to_marginal(result);
[prob, mpe] = max(marginal.T);

% handle impossible cases
if ~(prob>0)
  mpe = [];    
  ll = -inf;
  %warning('evidence has zero probability')
  return
end

ll = log(prob);

% Do forward phase    
for ii=2:n
  marginal = pot_to_marginal(B{ii});
  mpeidx = [];
  for jj=order(1:length(mpe))
    %assert(ismember(jj, marginal.domain)) %%% bug
    temp = find_equiv_posns(jj, marginal.domain);
    mpeidx = [mpeidx, temp] ;
    if isempty(temp)
      mpeidx = [mpeidx, Inf] ;
    end
  end
  [mpeidxsorted sortedtompe] = sort(mpeidx) ;
  
  % maximize the matrix obtained from assigning values from previous buckets.
  % this is done by building a string and using eval.
  
  kk=1;
  sargs = '(';
  for jj=1:length(marginal.domain)
    if (jj~=1)
      sargs = [sargs, ','];
    end
    if (mpeidxsorted(kk)==jj)
      sargs = [sargs, num2str(mpe(sortedtompe(kk)))];
      if (kk<length(mpe))
	kk = kk+1 ;
      end
    else
      sargs = [sargs, ':'];
    end
  end
  sargs = [sargs, ')'] ;   
  eval(['[val, loc] = max(marginal.T', sargs, ');'])        
  mpe = [mpe loc];
end     
[I,J] = sort(order);
mpe = mpe(J);

mpe = num2cell(mpe);

%%%%%%%%%

function b = bucket_num(domain, order)

b = max(find_equiv_posns(domain, order));