annotate toolboxes/FullBNT-1.0.7/bnt/CPDs/@tabular_CPD/tabular_CPD.m @ 0:cc4b1211e677 tip

initial commit to HG from Changeset: 646 (e263d8a21543) added further path and more save "camirversion.m"
author Daniel Wolff
date Fri, 19 Aug 2016 13:07:06 +0200
parents
children
rev   line source
Daniel@0 1 function CPD = tabular_CPD(bnet, self, varargin)
Daniel@0 2 % TABULAR_CPD Make a multinomial conditional prob. distrib. (CPT)
Daniel@0 3 %
Daniel@0 4 % CPD = tabular_CPD(bnet, node) creates a random CPT.
Daniel@0 5 %
Daniel@0 6 % The following arguments can be specified [default in brackets]
Daniel@0 7 %
Daniel@0 8 % CPT - specifies the params ['rnd']
Daniel@0 9 % - T means use table T; it will be reshaped to the size of node's family.
Daniel@0 10 % - 'rnd' creates rnd params (drawn from uniform)
Daniel@0 11 % - 'unif' creates a uniform distribution
Daniel@0 12 % adjustable - 0 means don't adjust the parameters during learning [1]
Daniel@0 13 % prior_type - defines type of prior ['none']
Daniel@0 14 % - 'none' means do ML estimation
Daniel@0 15 % - 'dirichlet' means add pseudo-counts to every cell
Daniel@0 16 % - 'entropic' means use a prior P(theta) propto exp(-H(theta)) (see Brand)
Daniel@0 17 % dirichlet_weight - equivalent sample size (ess) of the dirichlet prior [1]
Daniel@0 18 % dirichlet_type - defines the type of Dirichlet prior ['BDeu']
Daniel@0 19 % - 'unif' means put dirichlet_weight in every cell
Daniel@0 20 % - 'BDeu' means we put 'dirichlet_weight/(r q)' in every cell
Daniel@0 21 % where r = self_sz and q = prod(parent_sz) (see Heckerman)
Daniel@0 22 % trim - 1 means trim redundant params (rows in CPT) when using entropic prior [0]
Daniel@0 23 % entropic_pcases - list of assignments to the parents nodes when we should use
Daniel@0 24 % the entropic prior; all other cases will be estimated using ML [1:psz]
Daniel@0 25 % sparse - 1 means use 1D sparse array to represent CPT [0]
Daniel@0 26 %
Daniel@0 27 % e.g., tabular_CPD(bnet, i, 'CPT', T)
Daniel@0 28 % e.g., tabular_CPD(bnet, i, 'CPT', 'unif', 'dirichlet_weight', 2, 'dirichlet_type', 'unif')
Daniel@0 29 %
Daniel@0 30 % REFERENCES
Daniel@0 31 % M. Brand - "Structure learning in conditional probability models via an entropic prior
Daniel@0 32 % and parameter extinction", Neural Computation 11 (1999): 1155--1182
Daniel@0 33 % M. Brand - "Pattern discovery via entropy minimization" [covers annealing]
Daniel@0 34 % AI & Statistics 1999. Equation numbers refer to this paper, which is available from
Daniel@0 35 % www.merl.com/reports/docs/TR98-21.pdf
Daniel@0 36 % D. Heckerman, D. Geiger and M. Chickering,
Daniel@0 37 % "Learning Bayesian networks: the combination of knowledge and statistical data",
Daniel@0 38 % Microsoft Research Tech Report, 1994
Daniel@0 39
Daniel@0 40
Daniel@0 41 if nargin==0
Daniel@0 42 % This occurs if we are trying to load an object from a file.
Daniel@0 43 CPD = init_fields;
Daniel@0 44 CPD = class(CPD, 'tabular_CPD', discrete_CPD(0, []));
Daniel@0 45 return;
Daniel@0 46 elseif isa(bnet, 'tabular_CPD')
Daniel@0 47 % This might occur if we are copying an object.
Daniel@0 48 CPD = bnet;
Daniel@0 49 return;
Daniel@0 50 end
Daniel@0 51 CPD = init_fields;
Daniel@0 52
Daniel@0 53 ns = bnet.node_sizes;
Daniel@0 54 ps = parents(bnet.dag, self);
Daniel@0 55 fam_sz = ns([ps self]);
Daniel@0 56 psz = prod(ns(ps));
Daniel@0 57 CPD.sizes = fam_sz;
Daniel@0 58 CPD.leftright = 0;
Daniel@0 59 CPD.sparse = 0;
Daniel@0 60
Daniel@0 61 % set defaults
Daniel@0 62 CPD.CPT = mk_stochastic(myrand(fam_sz));
Daniel@0 63 CPD.adjustable = 1;
Daniel@0 64 CPD.prior_type = 'none';
Daniel@0 65 dirichlet_type = 'BDeu';
Daniel@0 66 dirichlet_weight = 1;
Daniel@0 67 CPD.trim = 0;
Daniel@0 68 selfprob = 0.1;
Daniel@0 69 CPD.entropic_pcases = 1:psz;
Daniel@0 70
Daniel@0 71 % extract optional args
Daniel@0 72 args = varargin;
Daniel@0 73 % check for old syntax CPD(bnet, i, CPT) as opposed to CPD(bnet, i, 'CPT', CPT)
Daniel@0 74 if ~isempty(args) & ~isstr(args{1})
Daniel@0 75 CPD.CPT = myreshape(args{1}, fam_sz);
Daniel@0 76 args = [];
Daniel@0 77 end
Daniel@0 78
Daniel@0 79 for i=1:2:length(args)
Daniel@0 80 switch args{i},
Daniel@0 81 case 'CPT',
Daniel@0 82 T = args{i+1};
Daniel@0 83 if ischar(T)
Daniel@0 84 switch T
Daniel@0 85 case 'unif', CPD.CPT = mk_stochastic(myones(fam_sz));
Daniel@0 86 case 'rnd', CPD.CPT = mk_stochastic(myrand(fam_sz));
Daniel@0 87 otherwise, error(['invalid CPT ' T]);
Daniel@0 88 end
Daniel@0 89 else
Daniel@0 90 CPD.CPT = myreshape(T, fam_sz);
Daniel@0 91 end
Daniel@0 92 case 'prior_type', CPD.prior_type = args{i+1};
Daniel@0 93 case 'dirichlet_type', dirichlet_type = args{i+1};
Daniel@0 94 case 'dirichlet_weight', dirichlet_weight = args{i+1};
Daniel@0 95 case 'adjustable', CPD.adjustable = args{i+1};
Daniel@0 96 case 'clamped', CPD.adjustable = ~args{i+1};
Daniel@0 97 case 'trim', CPD.trim = args{i+1};
Daniel@0 98 case 'entropic_pcases', CPD.entropic_pcases = args{i+1};
Daniel@0 99 case 'sparse', CPD.sparse = args{i+1};
Daniel@0 100 otherwise, error(['invalid argument name: ' args{i}]);
Daniel@0 101 end
Daniel@0 102 end
Daniel@0 103
Daniel@0 104 switch CPD.prior_type
Daniel@0 105 case 'dirichlet',
Daniel@0 106 switch dirichlet_type
Daniel@0 107 case 'unif', CPD.dirichlet = dirichlet_weight * myones(fam_sz);
Daniel@0 108 case 'BDeu', CPD.dirichlet = (dirichlet_weight/psz) * mk_stochastic(myones(fam_sz));
Daniel@0 109 otherwise, error(['invalid dirichlet_type ' dirichlet_type])
Daniel@0 110 end
Daniel@0 111 case {'entropic', 'none'}
Daniel@0 112 CPD.dirichlet = [];
Daniel@0 113 otherwise, error(['invalid prior_type ' prior_type])
Daniel@0 114 end
Daniel@0 115
Daniel@0 116
Daniel@0 117
Daniel@0 118 % fields to do with learning
Daniel@0 119 if ~CPD.adjustable
Daniel@0 120 CPD.counts = [];
Daniel@0 121 CPD.nparams = 0;
Daniel@0 122 CPD.nsamples = [];
Daniel@0 123 else
Daniel@0 124 %CPD.counts = zeros(size(CPD.CPT));
Daniel@0 125 CPD.counts = zeros(prod(size(CPD.CPT)), 1);
Daniel@0 126 psz = fam_sz(1:end-1);
Daniel@0 127 ss = fam_sz(end);
Daniel@0 128 if CPD.leftright
Daniel@0 129 % For each of the Qps contexts, we specify Q elements on the diagoanl
Daniel@0 130 CPD.nparams = Qps * Q;
Daniel@0 131 else
Daniel@0 132 % sum-to-1 constraint reduces the effective arity of the node by 1
Daniel@0 133 CPD.nparams = prod([psz ss-1]);
Daniel@0 134 end
Daniel@0 135 CPD.nsamples = 0;
Daniel@0 136 end
Daniel@0 137
Daniel@0 138 CPD.trimmed_trans = [];
Daniel@0 139 fam_sz = CPD.sizes;
Daniel@0 140
Daniel@0 141 %psz = prod(fam_sz(1:end-1));
Daniel@0 142 %ssz = fam_sz(end);
Daniel@0 143 %CPD.trimmed_trans = zeros(psz, ssz); % must declare before reading
Daniel@0 144
Daniel@0 145 %sparse CPT
Daniel@0 146 if CPD.sparse
Daniel@0 147 CPD.CPT = sparse(CPD.CPT(:));
Daniel@0 148 end
Daniel@0 149
Daniel@0 150 CPD = class(CPD, 'tabular_CPD', discrete_CPD(~CPD.adjustable, fam_sz));
Daniel@0 151
Daniel@0 152
Daniel@0 153 %%%%%%%%%%%
Daniel@0 154
Daniel@0 155 function CPD = init_fields()
Daniel@0 156 % This ensures we define the fields in the same order
Daniel@0 157 % no matter whether we load an object from a file,
Daniel@0 158 % or create it from scratch. (Matlab requires this.)
Daniel@0 159
Daniel@0 160 CPD.CPT = [];
Daniel@0 161 CPD.sizes = [];
Daniel@0 162 CPD.prior_type = [];
Daniel@0 163 CPD.dirichlet = [];
Daniel@0 164 CPD.adjustable = [];
Daniel@0 165 CPD.counts = [];
Daniel@0 166 CPD.nparams = [];
Daniel@0 167 CPD.nsamples = [];
Daniel@0 168 CPD.trim = [];
Daniel@0 169 CPD.trimmed_trans = [];
Daniel@0 170 CPD.leftright = [];
Daniel@0 171 CPD.entropic_pcases = [];
Daniel@0 172 CPD.sparse = [];
Daniel@0 173