annotate toolboxes/FullBNT-1.0.7/bnt/CPDs/@boolean_CPD/boolean_CPD.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 function CPD = boolean_CPD(bnet, self, ftype, fname, pfail)
wolffd@0 2 % BOOLEAN_CPD Make a tabular CPD representing a (noisy) boolean function
wolffd@0 3 %
wolffd@0 4 % CPD = boolean_cpd(bnet, self, 'inline', f) uses the inline function f
wolffd@0 5 % to specify the CPT.
wolffd@0 6 % e.g., suppose X4 = X2 AND (NOT X3). Then we can write
wolffd@0 7 % bnet.CPD{4} = boolean_CPD(bnet, 4, 'inline', inline('(x(1) & ~x(2)'));
wolffd@0 8 % Note that x(1) refers pvals(1) = X2, and x(2) refers to pvals(2)=X3.
wolffd@0 9 %
wolffd@0 10 % CPD = boolean_cpd(bnet, self, 'named', f) assumes f is a function name.
wolffd@0 11 % f can be built-in to matlab, or a file.
wolffd@0 12 % e.g., If X4 = X2 AND X3, we can write
wolffd@0 13 % bnet.CPD{4} = boolean_CPD(bnet, 4, 'named', 'and');
wolffd@0 14 % e.g., If X4 = X2 OR X3, we can write
wolffd@0 15 % bnet.CPD{4} = boolean_CPD(bnet, 4, 'named', 'any');
wolffd@0 16 %
wolffd@0 17 % CPD = boolean_cpd(bnet, self, 'rnd') makes a random non-redundant bool fn.
wolffd@0 18 %
wolffd@0 19 % CPD = boolean_CPD(bnet, self, 'inline'/'named', f, pfail)
wolffd@0 20 % will put probability mass 1-pfail on f(parents), and put pfail on the other value.
wolffd@0 21 % This is useful for simulating noisy boolean functions.
wolffd@0 22 % If pfail is omitted, it is set to 0.
wolffd@0 23 % (Note that adding noise to a random (non-redundant) boolean function just creates a different
wolffd@0 24 % (potentially redundant) random boolean function.)
wolffd@0 25 %
wolffd@0 26 % Note: This cannot be used to simulate a noisy-OR gate.
wolffd@0 27 % Example: suppose C has parents A and B, and the
wolffd@0 28 % link of A->C fails with prob pA and the link B->C fails with pB.
wolffd@0 29 % Then the noisy-OR gate defines the following distribution
wolffd@0 30 %
wolffd@0 31 % A B P(C=0)
wolffd@0 32 % 0 0 1.0
wolffd@0 33 % 1 0 pA
wolffd@0 34 % 0 1 pB
wolffd@0 35 % 1 1 pA * PB
wolffd@0 36 %
wolffd@0 37 % By contrast, boolean_CPD(bnet, C, 'any', p) would define
wolffd@0 38 %
wolffd@0 39 % A B P(C=0)
wolffd@0 40 % 0 0 1-p
wolffd@0 41 % 1 0 p
wolffd@0 42 % 0 1 p
wolffd@0 43 % 1 1 p
wolffd@0 44
wolffd@0 45
wolffd@0 46 if nargin==0
wolffd@0 47 % This occurs if we are trying to load an object from a file.
wolffd@0 48 CPD = tabular_CPD(bnet, self);
wolffd@0 49 return;
wolffd@0 50 elseif isa(bnet, 'boolean_CPD')
wolffd@0 51 % This might occur if we are copying an object.
wolffd@0 52 CPD = bnet;
wolffd@0 53 return;
wolffd@0 54 end
wolffd@0 55
wolffd@0 56 if nargin < 5, pfail = 0; end
wolffd@0 57
wolffd@0 58 ps = parents(bnet.dag, self);
wolffd@0 59 ns = bnet.node_sizes;
wolffd@0 60 psizes = ns(ps);
wolffd@0 61 self_size = ns(self);
wolffd@0 62
wolffd@0 63 psucc = 1-pfail;
wolffd@0 64
wolffd@0 65 k = length(ps);
wolffd@0 66 switch ftype
wolffd@0 67 case 'inline', f = eval_bool_fn(fname, k);
wolffd@0 68 case 'named', f = eval_bool_fn(fname, k);
wolffd@0 69 case 'rnd', f = mk_rnd_bool_fn(k);
wolffd@0 70 otherwise, error(['unknown function type ' ftype]);
wolffd@0 71 end
wolffd@0 72
wolffd@0 73 CPT = zeros(prod(psizes), self_size);
wolffd@0 74 ndx = find(f==0);
wolffd@0 75 CPT(ndx, 1) = psucc;
wolffd@0 76 CPT(ndx, 2) = pfail;
wolffd@0 77 ndx = find(f==1);
wolffd@0 78 CPT(ndx, 2) = psucc;
wolffd@0 79 CPT(ndx, 1) = pfail;
wolffd@0 80 if k > 0
wolffd@0 81 CPT = reshape(CPT, [psizes self_size]);
wolffd@0 82 end
wolffd@0 83
wolffd@0 84 clamp = 1;
wolffd@0 85 CPD = tabular_CPD(bnet, self, CPT, [], clamp);
wolffd@0 86
wolffd@0 87
wolffd@0 88
wolffd@0 89 %%%%%%%%%%%%
wolffd@0 90
wolffd@0 91 function f = eval_bool_fn(fname, n)
wolffd@0 92 % EVAL_BOOL_FN Evaluate a boolean function on all bit vectors of length n
wolffd@0 93 % f = eval_bool_fn(fname, n)
wolffd@0 94 %
wolffd@0 95 % e.g. f = eval_bool_fn(inline('x(1) & x(3)'), 3)
wolffd@0 96 % returns 0 0 0 0 0 1 0 1
wolffd@0 97
wolffd@0 98 ns = 2*ones(1, n);
wolffd@0 99 f = zeros(1, 2^n);
wolffd@0 100 bits = ind2subv(ns, 1:2^n);
wolffd@0 101 for i=1:2^n
wolffd@0 102 f(i) = feval(fname, bits(i,:)-1);
wolffd@0 103 end
wolffd@0 104
wolffd@0 105 %%%%%%%%%%%%%%%
wolffd@0 106
wolffd@0 107 function f = mk_rnd_bool_fn(n)
wolffd@0 108 % MK_RND_BOOL_FN Make a random bit vector of length n that encodes a non-redundant boolean function
wolffd@0 109 % f = mk_rnd_bool_fn(n)
wolffd@0 110
wolffd@0 111 red = 1;
wolffd@0 112 while red
wolffd@0 113 f = sample_discrete([0.5 0.5], 2^n, 1)-1;
wolffd@0 114 red = redundant_bool_fn(f);
wolffd@0 115 end
wolffd@0 116
wolffd@0 117 %%%%%%%%
wolffd@0 118
wolffd@0 119
wolffd@0 120 function red = redundant_bool_fn(f)
wolffd@0 121 % REDUNDANT_BOOL_FN Does a boolean function depend on all its input values?
wolffd@0 122 % r = redundant_bool_fn(f)
wolffd@0 123 %
wolffd@0 124 % f is a vector of length 2^n, representing the output for each bit vector.
wolffd@0 125 % An input is redundant if there is no assignment to the other bits
wolffd@0 126 % which changes the output e.g., input 1 is redundant if u(2:n) s.t.,
wolffd@0 127 % f([0 u(2:n)]) <> f([1 u(2:n)]).
wolffd@0 128 % A function is redundant it it has any redundant inputs.
wolffd@0 129
wolffd@0 130 n = log2(length(f));
wolffd@0 131 ns = 2*ones(1,n);
wolffd@0 132 red = 0;
wolffd@0 133 for i=1:n
wolffd@0 134 ens = ns;
wolffd@0 135 ens(i) = 1;
wolffd@0 136 U = ind2subv(ens, 1:2^(n-1));
wolffd@0 137 U(:,i) = 1;
wolffd@0 138 f1 = f(subv2ind(ns, U));
wolffd@0 139 U(:,i) = 2;
wolffd@0 140 f2 = f(subv2ind(ns, U));
wolffd@0 141 if isequal(f1, f2)
wolffd@0 142 red = 1;
wolffd@0 143 return;
wolffd@0 144 end
wolffd@0 145 end
wolffd@0 146
wolffd@0 147
wolffd@0 148 %%%%%%%%%%
wolffd@0 149
wolffd@0 150 function [b, iter] = rnd_truth_table(N)
wolffd@0 151 % RND_TRUTH_TABLE Construct the output of a random truth table s.t. each input is non-redundant
wolffd@0 152 % b = rnd_truth_table(N)
wolffd@0 153 %
wolffd@0 154 % N is the number of inputs.
wolffd@0 155 % b is a random bit string of length N, representing the output of the truth table.
wolffd@0 156 % Non-redundant means that, for each input position k,
wolffd@0 157 % there are at least two bit patterns, u and v, that differ only in the k'th position,
wolffd@0 158 % s.t., f(u) ~= f(v), where f is the function represented by b.
wolffd@0 159 % We use rejection sampling to ensure non-redundancy.
wolffd@0 160 %
wolffd@0 161 % Example: b = [0 0 0 1 0 0 0 1] is indep of 3rd input (AND of inputs 1 and 2)
wolffd@0 162
wolffd@0 163 bits = ind2subv(2*ones(1,N), 1:2^N)-1;
wolffd@0 164 redundant = 1;
wolffd@0 165 iter = 0;
wolffd@0 166 while redundant & (iter < 4)
wolffd@0 167 iter = iter + 1;
wolffd@0 168 b = sample_discrete([0.5 0.5], 1, 2^N)-1;
wolffd@0 169 redundant = 0;
wolffd@0 170 for i=1:N
wolffd@0 171 on = find(bits(:,i)==1);
wolffd@0 172 off = find(bits(:,i)==0);
wolffd@0 173 if isequal(b(on), b(off))
wolffd@0 174 redundant = 1;
wolffd@0 175 break;
wolffd@0 176 end
wolffd@0 177 end
wolffd@0 178 end
wolffd@0 179