function bnode = mk_tabular_node(bnet, self, ess, ps)
% MK_TABULAR_NODE Make a node whose conditional distrib. is a table (CPT).
%
% BNODE = MK_TABULAR_NODE(BNET, NODE_NUM)
% The CPT will be initialized randomly. It is stored as follows.
%   bnode.CPT(p1, ..., pn, s) = Pr(self=s | Pa(1) = p1, ..., Pa(n) = pn)
% The low numbered parents come before the high numbered parents.
% The last dimension always sums to 1.
%
% For example, suppose node X3 has 2 parents, X1 and X2, and all nodes are binary.
% To enter the following CPT (enumerated in matlab order: leftmost column toggles fastest)
%
% X1 X1 Pr(X3=1)  Pr(X3=2)
%------------------------
% 1  1   0.1       0.9
% 2  1   0.2       0.8
% 1  2   0.3       0.7
% 2  2   0.4       0.6
% 
% you type bnet.bnodes{3}.CPT(:) = [0.1 0.2 0.3 0.4 0.9 0.8 0.7 0.6];
%
% Here is an alternative way of entering the same information
%  bnet.bnodes{3}.CPT(1,1,1) = 0.1;
%  bnet.bnodes{3}.CPT(2,1,1) = 0.2;
%  bnet.bnodes{3}.CPT(1,2,1) = 0.3; etc
% Note that matlab counts from 1. Hence False==1, True==2.
%
% BNODE = MK_TABULAR_NODE(BNET, NODE_NUM, ESS)
% Set the effective sample size of a uniform Dirichlet prior to 'ess'. Default: 0.
% Set ess=0 to do ML estimation. Set to small value (e.g., 0.001) to avoid 0s but without adding too
% much bias. Change the field 'prior' if you want a non-uniform prior (stored in the same way as
% the CPT).
%
% BNODE = MK_TABULAR_NODE(BNET, NODE_NUM, ESS, PARENTS)
% The fn modify_parents_tabular uses this form to specify a different set of parents than the ones
% defined in bnet's graph. This is used in structure learning.

if nargin < 3, ess = 0; end
if nargin < 4, ps = parents(bnet.adj_mat, self); end

ns = bnet.node_sizes;
bnode.type = 'tabular';
bnode.adjustable = 1;
bnode.self = self;
bnode.parents = ps;
fam = [bnode.parents bnode.self];
assert(subset(fam, bnet.discrete_nodes));
bnode.sizes = [ns(ps) ns(self)];
% sum-to-1 constraint reduces the effective num. vals of the node by 1
bnode.nparams = prod([ns(ps) ns(self)-1]);

bnode = randomize_params_tabular(bnode);
bnode = reset_ess_tabular(bnode);

% If each bin has a pseudocount of ess/n (where n = num. bins, ess = effective sample size)
% the total weight in all bins is ess, as required.
num_entries = prod(bnode.sizes);
bnode.prior = myones(bnode.sizes) * (ess/num_entries); 
bnode.equiv_sample_size = ess;

%bnet.bnodes{self} = bnode;

