To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / _FullBNT / BNT / CPDs / @boolean_CPD / boolean_CPD.m @ 8:b5b38998ef3b

History | View | Annotate | Download (4.74 KB)

1
function CPD = boolean_CPD(bnet, self, ftype, fname, pfail)
2
% BOOLEAN_CPD Make a tabular CPD representing a (noisy) boolean function
3
%
4
% CPD = boolean_cpd(bnet, self, 'inline', f) uses the inline function f
5
% to specify the CPT.
6
% e.g., suppose X4 = X2 AND (NOT X3). Then we can write
7
%    bnet.CPD{4} = boolean_CPD(bnet, 4, 'inline', inline('(x(1) & ~x(2)'));  
8
% Note that x(1) refers pvals(1) = X2, and x(2) refers to pvals(2)=X3.
9
%
10
% CPD = boolean_cpd(bnet, self, 'named', f) assumes f is a function name.
11
% f can be built-in to matlab, or a file.
12
% e.g., If X4 = X2 AND X3, we can write
13
%    bnet.CPD{4} = boolean_CPD(bnet, 4, 'named', 'and');
14
% e.g., If X4 = X2 OR X3, we can write
15
%    bnet.CPD{4} = boolean_CPD(bnet, 4, 'named', 'any');
16
%
17
% CPD = boolean_cpd(bnet, self, 'rnd') makes a random non-redundant bool fn.
18
%
19
% CPD = boolean_CPD(bnet, self, 'inline'/'named', f, pfail)
20
% will put probability mass 1-pfail on f(parents), and put pfail on the other value.
21
% This is useful for simulating noisy boolean functions.
22
% If pfail is omitted, it is set to 0.
23
% (Note that adding noise to a random (non-redundant) boolean function just creates a different
24
% (potentially redundant) random boolean function.)
25
%
26
% Note: This cannot be used to simulate a noisy-OR gate.
27
% Example: suppose C has parents A and B, and the
28
% link of A->C fails with prob pA and the link B->C fails with pB.
29
% Then the noisy-OR gate defines the following distribution
30
%
31
%  A  B  P(C=0)
32
%  0  0  1.0
33
%  1  0  pA
34
%  0  1  pB
35
%  1  1  pA * PB
36
% 
37
% By contrast, boolean_CPD(bnet, C, 'any', p) would define
38
%
39
%  A  B  P(C=0) 
40
%  0  0  1-p    
41
%  1  0  p      
42
%  0  1  p
43
%  1  1  p
44

    
45

    
46
if nargin==0
47
  % This occurs if we are trying to load an object from a file.
48
  CPD = tabular_CPD(bnet, self);
49
  return;
50
elseif isa(bnet, 'boolean_CPD')
51
  % This might occur if we are copying an object.
52
  CPD = bnet;
53
  return;
54
end
55

    
56
if nargin < 5, pfail = 0; end
57

    
58
ps = parents(bnet.dag, self);
59
ns = bnet.node_sizes;
60
psizes = ns(ps);
61
self_size = ns(self);
62

    
63
psucc = 1-pfail;
64

    
65
k = length(ps);
66
switch ftype
67
 case 'inline', f = eval_bool_fn(fname, k);
68
 case 'named',  f = eval_bool_fn(fname, k);
69
 case 'rnd',    f = mk_rnd_bool_fn(k);
70
 otherwise,     error(['unknown function type ' ftype]);
71
end
72

    
73
CPT = zeros(prod(psizes), self_size);
74
ndx = find(f==0);
75
CPT(ndx, 1) = psucc;
76
CPT(ndx, 2) = pfail;
77
ndx = find(f==1);
78
CPT(ndx, 2) = psucc;
79
CPT(ndx, 1) = pfail;
80
if k > 0
81
  CPT = reshape(CPT, [psizes self_size]);  
82
end
83

    
84
clamp = 1;
85
CPD = tabular_CPD(bnet, self, CPT, [], clamp);
86

    
87

    
88

    
89
%%%%%%%%%%%%
90

    
91
function f = eval_bool_fn(fname, n)
92
% EVAL_BOOL_FN Evaluate a boolean function on all bit vectors of length n
93
% f = eval_bool_fn(fname, n)
94
%
95
% e.g. f = eval_bool_fn(inline('x(1) & x(3)'), 3)
96
% returns   0     0     0     0     0     1     0     1
97

    
98
ns = 2*ones(1, n);
99
f = zeros(1, 2^n);
100
bits = ind2subv(ns, 1:2^n);
101
for i=1:2^n
102
  f(i) = feval(fname, bits(i,:)-1);
103
end
104

    
105
%%%%%%%%%%%%%%%
106

    
107
function f = mk_rnd_bool_fn(n)
108
% MK_RND_BOOL_FN Make a random bit vector of length n that encodes a non-redundant boolean function
109
% f = mk_rnd_bool_fn(n)
110

    
111
red = 1;
112
while red
113
  f = sample_discrete([0.5 0.5], 2^n, 1)-1;
114
  red = redundant_bool_fn(f);
115
end
116

    
117
%%%%%%%%
118

    
119

    
120
function red = redundant_bool_fn(f)
121
% REDUNDANT_BOOL_FN Does a boolean function depend on all its input values?
122
% r = redundant_bool_fn(f)
123
%
124
% f is a vector of length 2^n, representing the output for each bit vector.
125
% An input is redundant if there is no assignment to the other bits
126
% which changes the output e.g., input 1 is redundant if u(2:n) s.t.,
127
% f([0 u(2:n)]) <> f([1 u(2:n)]). 
128
% A function is redundant it it has any redundant inputs.
129

    
130
n = log2(length(f));
131
ns = 2*ones(1,n);
132
red = 0;
133
for i=1:n
134
  ens = ns;
135
  ens(i) = 1;
136
  U = ind2subv(ens, 1:2^(n-1));
137
  U(:,i) = 1;
138
  f1 = f(subv2ind(ns, U));
139
  U(:,i) = 2;
140
  f2 = f(subv2ind(ns, U));
141
  if isequal(f1, f2)
142
    red = 1;
143
    return;
144
  end
145
end
146

    
147

    
148
%%%%%%%%%%
149

    
150
function [b, iter] = rnd_truth_table(N)
151
% RND_TRUTH_TABLE Construct the output of a random truth table s.t. each input is non-redundant
152
% b = rnd_truth_table(N)
153
%
154
% N is the number of inputs. 
155
% b is a random bit string of length N, representing the output of the truth table.
156
% Non-redundant means that, for each input position k,
157
% there are at least two bit patterns, u and v, that differ only in the k'th position,
158
% s.t., f(u) ~= f(v), where f is the function represented by b.
159
% We use rejection sampling to ensure non-redundancy.
160
%
161
% Example: b = [0 0 0 1  0 0 0 1] is indep of 3rd input (AND of inputs 1 and 2)
162

    
163
bits = ind2subv(2*ones(1,N), 1:2^N)-1;
164
redundant = 1;
165
iter = 0;
166
while redundant & (iter < 4)
167
  iter = iter + 1;
168
  b = sample_discrete([0.5 0.5], 1, 2^N)-1;
169
  redundant = 0;
170
  for i=1:N
171
    on = find(bits(:,i)==1);
172
    off = find(bits(:,i)==0);
173
    if isequal(b(on), b(off))
174
      redundant = 1;
175
      break;
176
    end
177
  end
178
end
179