about summary refs log tree commit diff
path: root/sourcecodes/bnt-master/BNT/learning
diff options
context:
space:
mode:
Diffstat (limited to 'sourcecodes/bnt-master/BNT/learning')
-rw-r--r--sourcecodes/bnt-master/BNT/learning/CVS/Entries23
-rw-r--r--sourcecodes/bnt-master/BNT/learning/CVS/Repository1
-rw-r--r--sourcecodes/bnt-master/BNT/learning/CVS/Root1
-rw-r--r--sourcecodes/bnt-master/BNT/learning/CovMat.m39
-rw-r--r--sourcecodes/bnt-master/BNT/learning/bayes_update_params.m38
-rw-r--r--sourcecodes/bnt-master/BNT/learning/bic_score_family.m23
-rw-r--r--sourcecodes/bnt-master/BNT/learning/compute_cooling_schedule.m13
-rw-r--r--sourcecodes/bnt-master/BNT/learning/dirichlet_score_family.m42
-rw-r--r--sourcecodes/bnt-master/BNT/learning/kpm_learn_struct_mcmc.m265
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_params.m26
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_params_dbn.m36
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_params_dbn_em.m179
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_params_em.m88
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_struct_K2.m104
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_struct_dbn_reveal.m101
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_struct_mcmc.m284
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_ic_star.m155
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc.m130
-rw-r--r--sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc_constrain.m177
-rw-r--r--sourcecodes/bnt-master/BNT/learning/mcmc_sample_to_hist.m36
-rw-r--r--sourcecodes/bnt-master/BNT/learning/mk_schedule.m10
-rw-r--r--sourcecodes/bnt-master/BNT/learning/mk_tetrad_data_file.m25
-rw-r--r--sourcecodes/bnt-master/BNT/learning/score_dags_old.m62
-rw-r--r--sourcecodes/bnt-master/BNT/learning/score_dags_wocache.m67
-rw-r--r--sourcecodes/bnt-master/BNT/learning/score_family_wocache.m57
25 files changed, 1982 insertions, 0 deletions
diff --git a/sourcecodes/bnt-master/BNT/learning/CVS/Entries b/sourcecodes/bnt-master/BNT/learning/CVS/Entries
new file mode 100644
index 00000000..02e90b7f
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/CVS/Entries
@@ -0,0 +1,23 @@
+/CovMat.m/1.1.1.1/Sun Jul 28 23:09:42 2002//
+/bayes_update_params.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/bic_score_family.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/compute_cooling_schedule.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/dirichlet_score_family.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/kpm_learn_struct_mcmc.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/learn_params.m/1.1.1.1/Thu Jun 10 01:28:08 2004//
+/learn_params_dbn.m/1.1.1.1/Sun Feb  2 00:23:38 2003//
+/learn_params_dbn_em.m/1.1.1.1/Mon Aug 18 21:50:34 2003//
+/learn_params_em.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/learn_struct_K2.m/1.1.1.1/Thu Sep 26 08:39:16 2002//
+/learn_struct_dbn_reveal.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/learn_struct_mcmc.m/1.1.1.1/Fri Sep  5 14:06:40 2003//
+/learn_struct_pdag_ic_star.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/learn_struct_pdag_pc.m/1.2/Mon Feb 12 01:15:13 2007//
+/learn_struct_pdag_pc_constrain.m/1.1.1.1/Sun Jul 28 23:09:38 2002//
+/mcmc_sample_to_hist.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/mk_schedule.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/mk_tetrad_data_file.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/score_dags.m/1.1.1.1/Mon Apr  4 01:39:46 2005//
+/score_dags_old.m/1.1.1.1/Wed May 29 15:59:56 2002//
+/score_family.m/1.1.1.1/Thu Jun 10 01:33:14 2004//
+D
diff --git a/sourcecodes/bnt-master/BNT/learning/CVS/Repository b/sourcecodes/bnt-master/BNT/learning/CVS/Repository
new file mode 100644
index 00000000..ed7d464f
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/CVS/Repository
@@ -0,0 +1 @@
+FullBNT/BNT/learning
diff --git a/sourcecodes/bnt-master/BNT/learning/CVS/Root b/sourcecodes/bnt-master/BNT/learning/CVS/Root
new file mode 100644
index 00000000..f3bd14a6
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/CVS/Root
@@ -0,0 +1 @@
+:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt
diff --git a/sourcecodes/bnt-master/BNT/learning/CovMat.m b/sourcecodes/bnt-master/BNT/learning/CovMat.m
new file mode 100644
index 00000000..9b788172
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/CovMat.m
@@ -0,0 +1,39 @@
+function [CovMatrix, obs, varfields] = CovMat(filename,row_cols)
+%[CovMatrix, obs, varfields] = CovMat(filename,row_cols)
+%% generates a Covariance Matrix from a file of data consisting of N columns of M data rows
+%%      filename        string name (with path and extension) of file to open
+%%      row_cols        Number_of_converstions_per_row  (turns into  [3 inf])
+%% Return
+%%      CovMatrix       Covariance matrix
+%%      obs             Number of observations read in
+%%      varfields       Labels of the variables see filename structure below
+%%
+%%  Filename structure: 
+%%      Comma separated, starting with the variable labels, then the data in rows.
+%%    filename test.txt consists of:
+%%
+%%      Earthquake,Burglar,Radio,Alarm,Call
+%%      1,2,3,4,5
+%%      11,22,33,44,55
+%%      . . .
+%%
+%% Example call: 
+%%  [cvmat numdat lables] = CovMat('test.txt',5);
+%%
+%%      Returns Covariance matrix, number of date rows and variable field names
+%% Gary R. Bradski   7/2002
+
+fmtstr = '%f';
+for i = 2:row_cols
+    fmtstr = strcat(fmtstr,',%f');
+end
+
+%% load data
+fidCov = fopen(filename,'r');
+
+varfields = fgetl(fidCov);
+Corx = fscanf(fidCov,fmtstr,[row_cols inf]);
+Corx= Corx';
+[obs bla] = size(Corx);
+CovMatrix = cov(Corx); 
+fclose(fidCov);
\ No newline at end of file
diff --git a/sourcecodes/bnt-master/BNT/learning/bayes_update_params.m b/sourcecodes/bnt-master/BNT/learning/bayes_update_params.m
new file mode 100644
index 00000000..4a0a28f4
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/bayes_update_params.m
@@ -0,0 +1,38 @@
+function bnet = bayes_update_params(bnet, cases, clamped)
+% BAYES_UPDATE_PARAMS Bayesian parameter updating given completely observed data
+% bnet = bayes_update_params(bnet, cases, clamped)
+%
+% If there is a missing data, you must use EM.
+% cases(i,m) is the value assigned to node i in case m (this can also be a cell array).
+% clamped(i,m) = 1 if node i was set by intervention in case m (default: clamped = zeros).
+% Clamped nodes are not updated.
+% If there is a single case, clamped is a list of the clamped nodes, not a bit vector.
+
+
+%if iscell(cases), usecell = 1; else usecell = 0; end
+
+n = length(bnet.dag);
+ncases = size(cases, 2);
+if n ~= size(cases, 1)
+  error('data must be of size nnodes * ncases');
+end
+
+if ncases == 1 % clamped is a list of nodes
+  if nargin < 3, clamped = []; end
+  clamp_set = clamped;
+  clamped = zeros(n,1);
+  clamped(clamp_set) = 1;
+else % each row of clamped is a bit vector
+  if nargin < 3, clamped = zeros(n,ncases); end
+end
+
+for i=1:n
+  e = bnet.equiv_class(i);
+  if adjustable_CPD(bnet.CPD{e})
+    u = find(clamped(i,:)==0);
+    ps = parents(bnet.dag, i);
+    bnet.CPD{e} = bayes_update_params(bnet.CPD{e}, cases(i,u), cases(ps,u));
+  end
+end
+
+
diff --git a/sourcecodes/bnt-master/BNT/learning/bic_score_family.m b/sourcecodes/bnt-master/BNT/learning/bic_score_family.m
new file mode 100644
index 00000000..f3725ecb
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/bic_score_family.m
@@ -0,0 +1,23 @@
+function [S, LL] = bic_score(counts, CPT, ncases)
+% BIC_SCORE Bayesian Information Criterion score for a single family
+% [S, LL] = bic_score(counts, CPT, ncases)
+%
+% S is a large sample approximation to the log marginal likelihood,
+% which can be computed using dirichlet_score.
+%
+% S  = \log [ prod_j _prod_k theta_ijk ^ N_ijk ]  - 0.5*d*log(ncases) 
+% where counts encode N_ijk, theta_ijk is the MLE comptued from counts,
+% and d is the num of free parameters.
+
+%CPT = mk_stochastic(counts);
+tiny = exp(-700);
+LL = sum(log(CPT(:)  + tiny) .* counts(:));
+% CPT(i) = 0 iff counts(i) = 0 so it is okay to add tiny
+
+ns = mysize(counts);
+ns_ps = ns(1:end-1);
+ns_self = ns(end);
+nparams = prod([ns_ps (ns_self-1)]);
+% sum-to-1 constraint reduces the effective num. vals of the node by 1
+
+S = LL - 0.5*nparams*log(ncases);
diff --git a/sourcecodes/bnt-master/BNT/learning/compute_cooling_schedule.m b/sourcecodes/bnt-master/BNT/learning/compute_cooling_schedule.m
new file mode 100644
index 00000000..397c2f8c
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/compute_cooling_schedule.m
@@ -0,0 +1,13 @@
+function temp_schedule = compute_cooling_schedule(init_temp, final_temp, anneal_rate)
+
+temp_schedule = [];
+i = 1;
+temp_schedule(i)=init_temp;
+while temp_schedule(i) > final_temp
+  i = i + 1;
+  temp_schedule(i)=temp_schedule(i-1)*anneal_rate;
+end
+
+  
+
+
diff --git a/sourcecodes/bnt-master/BNT/learning/dirichlet_score_family.m b/sourcecodes/bnt-master/BNT/learning/dirichlet_score_family.m
new file mode 100644
index 00000000..abfb046b
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/dirichlet_score_family.m
@@ -0,0 +1,42 @@
+function LL = dirichlet_score_family(counts, prior)
+% DIRICHLET_SCORE Compute the log marginal likelihood of a single family
+% LL = dirichlet_score(counts, prior)
+%
+% counts(a, b, ..., z) is the number of times parent 1 = a, parent 2 = b, ..., child = z
+% prior is an optional multidimensional array of the same shape as counts.
+% It defaults to a uniform prior.
+% 
+% We marginalize out the parameters:
+% LL = log \int \prod_m P(x(i,m) | x(Pa_i,m), theta_i) P(theta_i) d(theta_i)
+
+
+% LL = log[  prod_j gamma(alpha_ij)/gamma(alpha_ij + N_ij)  *
+%            prod_k gamma(alpha_ijk + N_ijk)/gamma(alpha_ijk)  ]
+% Call the prod_k term U and the prod_j term  V.
+% We reshape all quantities into (j,k) matrices
+% This formula was first derived by Cooper and Herskovits, 1992.
+% See also "Learning Bayesian Networks", Heckerman, Geiger and Chickering, MLJ 95.
+
+ns = mysize(counts);
+ns_ps = ns(1:end-1);
+ns_self = ns(end);
+
+if nargin < 2, prior = normalise(myones(ns)); end
+
+
+if 1
+  prior = reshape(prior(:), [prod(ns_ps) ns_self]);
+  counts = reshape(counts,  [prod(ns_ps) ns_self]);
+  %U = prod(gamma(prior + counts) ./ gamma(prior), 2); % mult over k
+  LU = sum(gammaln(prior + counts) - gammaln(prior), 2);
+  alpha_ij = sum(prior, 2); % sum over k
+  N_ij = sum(counts, 2);
+  %V = gamma(alpha_ij) ./ gamma(alpha_ij + N_ij);
+  LV = gammaln(alpha_ij) - gammaln(alpha_ij + N_ij);
+  %L = prod(U .* V);
+  LL = sum(LU + LV);
+else
+  CPT = mk_stochastic(prior + counts);
+  LL = sum(log(CPT(:) .* counts(:)));
+end
+
diff --git a/sourcecodes/bnt-master/BNT/learning/kpm_learn_struct_mcmc.m b/sourcecodes/bnt-master/BNT/learning/kpm_learn_struct_mcmc.m
new file mode 100644
index 00000000..b73910d2
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/kpm_learn_struct_mcmc.m
@@ -0,0 +1,265 @@
+function [sampled_graphs, accept_ratio, num_edges] = learn_struct_mcmc(data, ns, varargin)
+% LEARN_STRUCT_MCMC  Monte Carla Markov Chain search over DAGs assuming fully observed data
+% [sampled_graphs, accept_ratio, num_edges] = learn_struct_mcmc(data, ns, ...)
+% 
+% data(i,m) is the value of node i in case m.
+% ns(i) is the number of discrete values node i can take on.
+%
+% sampled_graphs{m} is the m'th sampled graph.
+% accept_ratio(t) = acceptance ratio at iteration t
+% num_edges(t) = number of edges in model at iteration t
+%
+% The following optional arguments can be specified in the form of name/value pairs:
+% [default value in brackets]
+%
+% scoring_fn - 'bayesian' or 'bic' [ 'bayesian' ]
+%              Currently, only networks with all tabular nodes support Bayesian scoring.
+% type       - type{i} is the type of CPD to use for node i, where the type is a string
+%              of the form 'tabular', 'noisy_or', 'gaussian', etc. [ all cells contain 'tabular' ]
+% params     - params{i} contains optional arguments passed to the CPD constructor for node i,
+%              or [] if none.  [ all cells contain {'prior', 1}, meaning use uniform Dirichlet priors ]
+% discrete   - the list of discrete nodes [ 1:N ]
+% clamped    - clamped(i,m) = 1 if node i is clamped in case m [ zeros(N, ncases) ]
+% nsamples   - number of samples to draw from the chain after burn-in [ 100*N ]
+% burnin     - number of steps to take before drawing samples [ 5*N ]
+% init_dag   - starting point for the search [ zeros(N,N) ]
+%
+% e.g., samples = learn_struct_mcmc(data, ns, 'nsamples', 1000);
+%
+% This interface is not backwards compatible with BNT2,
+% but is designed to be compatible with the other learn_struct_xxx routines.
+%
+% Note: We currently assume a uniform structural prior.
+
+[n ncases] = size(data);
+
+
+% set default params
+type = cell(1,n);
+params = cell(1,n);
+for i=1:n
+  type{i} = 'tabular';
+  %params{i} = { 'prior', 1 };
+  params{i} = { 'prior_type', 'dirichlet', 'dirichlet_weight', 1 };
+end
+scoring_fn = 'bayesian';
+discrete = 1:n;
+clamped = zeros(n, ncases);
+nsamples = 100*n;
+burnin = 5*n;
+dag = zeros(n);
+
+args = varargin;
+nargs = length(args);
+for i=1:2:nargs
+  switch args{i},
+   case 'nsamples',   nsamples = args{i+1};
+   case 'burnin',     burnin = args{i+1};
+   case 'init_dag',   dag = args{i+1};
+   case 'scoring_fn', scoring_fn = args{i+1};
+   case 'type',       type = args{i+1}; 
+   case 'discrete',   discrete = args{i+1}; 
+   case 'clamped',    clamped = args{i+1}; 
+   case 'params',     if isempty(args{i+1}), params = cell(1,n); else params = args{i+1};  end
+  end
+end
+
+% We implement the fast acyclicity check described by P. Giudici and R. Castelo,
+% "Improving MCMC model search for data mining", submitted to J. Machine Learning, 2001.
+use_giudici = 1;
+if use_giudici
+  [nbrs, ops, nodes] = mk_nbrs_of_digraph(dag);
+  A = init_ancestor_matrix(dag);
+else
+  [nbrs, ops, nodes] = mk_nbrs_of_dag(dag);
+  A = [];
+end
+
+num_accepts = 1;
+num_rejects = 1;
+T = burnin + nsamples;
+accept_ratio = zeros(1, T);
+num_edges = zeros(1, T);
+sampled_graphs = cell(1, nsamples);
+%sampled_bitv = zeros(nsamples, n^2);
+
+for t=1:T
+  [dag, nbrs, ops, nodes, A, accept] = take_step(dag, nbrs, ops, nodes, ns, data, clamped, A, ...
+						 scoring_fn, discrete, type, params);
+  num_edges(t) = sum(dag(:));
+  num_accepts = num_accepts + accept;
+  num_rejects = num_rejects + (1-accept);
+  accept_ratio(t) =  num_accepts/num_rejects;
+  if t > burnin
+    sampled_graphs{t-burnin} = dag;
+    %sampled_bitv(t-burnin, :) = dag(:)';
+  end
+end
+
+
+%%%%%%%%%
+
+
+function [new_dag, new_nbrs, new_ops, new_nodes, A, accept] = ...
+    take_step(dag, nbrs, ops, nodes, ns, data, clamped, A, ...
+	      scoring_fn, discrete, type, params)
+
+
+use_giudici = ~isempty(A);
+if use_giudici
+  [new_dag, op, i, j] = pick_digraph_nbr(dag, nbrs, ops, nodes, A);
+  %assert(acyclic(new_dag));
+  [new_nbrs, new_ops, new_nodes] = mk_nbrs_of_digraph(new_dag);
+else
+  d = sample_discrete(normalise(ones(1, length(nbrs))));
+  new_dag = nbrs{d};
+  op = ops{d};
+  i = nodes(d, 1); j = nodes(d, 2);
+  [new_nbrs, new_ops, new_nodes] = mk_nbrs_of_dag(new_dag);
+end
+
+bf =  bayes_factor(dag, new_dag, op, i, j, ns, data, clamped, scoring_fn, discrete, type, params);
+
+%R = bf * (new_prior / prior) * (length(nbrs) / length(new_nbrs)); 
+R = bf * (length(nbrs) / length(new_nbrs)); 
+u = rand(1,1);
+if u > min(1,R) % reject the move
+  accept = 0;
+  new_dag = dag;
+  new_nbrs = nbrs;
+  new_ops = ops;
+  new_nodes = nodes;
+else
+  accept = 1;
+  if use_giudici
+    A = update_ancestor_matrix(A, op, i, j, new_dag);
+  end
+end
+
+
+%%%%%%%%%
+
+function bfactor = bayes_factor(old_dag, new_dag, op, i, j, ns, data, clamped, scoring_fn, discrete, type, params)
+
+u = find(clamped(j,:)==0);
+LLnew = score_family(j, parents(new_dag, j), type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+LLold = score_family(j, parents(old_dag, j), type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+bf1 = exp(LLnew - LLold);
+
+if strcmp(op, 'rev')  % must also multiply in the changes to i's family
+  u = find(clamped(i,:)==0);
+  LLnew = score_family(i, parents(new_dag, i), type{i}, scoring_fn, ns, discrete, data(:,u), params{i});
+  LLold = score_family(i, parents(old_dag, i), type{i}, scoring_fn, ns, discrete, data(:,u), params{i});
+  bf2 = exp(LLnew - LLold);
+else
+  bf2 = 1;
+end
+bfactor = bf1 * bf2;
+
+
+%%%%%%%% Giudici stuff follows %%%%%%%%%%
+
+
+function [new_dag, op, i, j] = pick_digraph_nbr(dag, digraph_nbrs, ops, nodes, A)
+
+legal = 0;
+while ~legal
+  d = sample_discrete(normalise(ones(1, length(digraph_nbrs))));
+  i = nodes(d, 1); j = nodes(d, 2);
+  switch ops{d}
+   case 'add',
+    if A(i,j)==0
+      legal = 1;
+    end
+   case 'del',
+    legal = 1;
+   case 'rev',
+    ps = mysetdiff(parents(dag, j), i);
+    % if any(A(ps,i)) then there is a path i -> parent of j -> j
+    % so reversing i->j would create a cycle
+    legal = ~any(A(ps, i));
+  end
+end
+%new_dag = digraph_nbrs{d};
+new_dag = digraph_nbrs(:,:,d);
+op = ops{d};
+i = nodes(d, 1); j = nodes(d, 2);
+
+
+%%%%%%%%%%%%%%
+
+
+function A = update_ancestor_matrix(A, op, i, j, dag)
+
+switch op
+ case 'add',
+  A = do_addition(A, op, i, j, dag);
+ case 'del', 
+  A = do_removal(A, op, i, j, dag);
+ case 'rev', 
+  A = do_removal(A, op, i, j, dag);
+  A = do_addition(A, op, j, i, dag);
+end
+
+  
+%%%%%%%%%%%%
+
+function A = do_addition(A, op, i, j, dag)
+
+A(j,i) = 1; % i is an ancestor of j
+anci = find(A(i,:));
+if ~isempty(anci)
+  A(j,anci) = 1; % all of i's ancestors are added to Anc(j)
+end
+ancj = find(A(j,:));
+descj = find(A(:,j)); 
+if ~isempty(ancj)
+  for k=descj(:)'
+    A(k,ancj) = 1; % all of j's ancestors are added to each descendant of j
+  end
+end
+
+%%%%%%%%%%%
+
+function A = do_removal(A, op, i, j, dag)
+
+% find all the descendants of j, and put them in topological order
+%descj = find(A(:,j)); 
+R = reachability_graph(dag);
+descj = find(R(j,:)); 
+order = topological_sort(dag);
+descj_topnum = order(descj);
+[junk, perm] = sort(descj_topnum);
+descj = descj(perm);
+% Update j and all its descendants
+A = update_row(A, j, dag);
+for k = descj(:)'
+  A = update_row(A, k, dag);
+end
+
+%%%%%%%%%
+
+function A = update_row(A, j, dag)
+
+% We compute row j of A
+A(j, :) = 0;
+ps = parents(dag, j);
+if ~isempty(ps)
+  A(j, ps) = 1;
+end
+for k=ps(:)'
+  anck = find(A(k,:));
+  if ~isempty(anck)
+    A(j, anck) = 1;
+  end
+end
+  
+%%%%%%%%
+
+function A = init_ancestor_matrix(dag)
+
+order = topological_sort(dag);
+A = zeros(length(dag));
+for j=order(:)'
+  A = update_row(A, j, dag);
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_params.m b/sourcecodes/bnt-master/BNT/learning/learn_params.m
new file mode 100644
index 00000000..1bf9c843
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_params.m
@@ -0,0 +1,26 @@
+function bnet = learn_params(bnet, data)
+% LEARN_PARAMS Find the maximum likelihood params for a fully observed model
+% bnet = learn_params(bnet, data)
+%
+% data(i,m) is the value of node i in case m (can be a cell array)
+%
+% We set bnet.CPD{i} to its ML/MAP estimate.
+%
+% Currently we assume no param tying
+
+% AND THAT EACH DATA POINT IS A SCALAR - no longer assumed
+
+%if iscell(data)
+%  data=cell2num(data);
+%end
+[n ncases] = size(data);
+for j=1:n
+  e = bnet.equiv_class(j);
+  assert(e==j);
+  if adjustable_CPD(bnet.CPD{e})
+    fam = family(bnet.dag,j);
+    %bnet.CPD{j} = learn_params(bnet.CPD{j}, data(fam,:));
+    bnet.CPD{j} = learn_params(bnet.CPD{j}, fam, data, bnet.node_sizes, bnet.cnodes);
+  end
+end
+
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_params_dbn.m b/sourcecodes/bnt-master/BNT/learning/learn_params_dbn.m
new file mode 100644
index 00000000..4d0dc501
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_params_dbn.m
@@ -0,0 +1,36 @@
+function bnet = learn_params_dbn(bnet, data)
+% LEARN_PARAM_DBN Estimate params of a DBN for a fully observed model
+% bnet = learn_params_dbn(bnet, data)
+%
+% data(i,t) is the value of node i in slice t (can be a cell array)
+% We currently assume there is a single time series
+%
+% We set bnet.CPD{i} to its ML/MAP estimate.
+%
+% Currently we assume each node in the first 2 slices has its own CPD (no param tying);
+% all nodes in slices >2 share their params with slice 2 as usual.
+
+[ss T] = size(data);
+
+% slice 1
+for j=1:ss
+  if adjustable_CPD(bnet.CPD{j})
+    fam = family(bnet.dag,j);
+    bnet.CPD{j} = learn_params(bnet.CPD{j}, data(fam,1));
+  end
+end
+
+
+% slices 2:T
+% data2(:,t) contains [data(:,t-1); data(:,t)].
+% Then we extract out the rows corresponding to the parents in the current and previous slice.
+data2 = [data(:,1:T-1);
+	 data(:,2:T)];
+for j=1:ss
+  j2 = j+ss;
+  if adjustable_CPD(bnet.CPD{j2})
+    fam = family(bnet.dag,j2);
+    bnet.CPD{j2} = learn_params(bnet.CPD{j2}, data2(fam,:));
+  end
+end
+
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_params_dbn_em.m b/sourcecodes/bnt-master/BNT/learning/learn_params_dbn_em.m
new file mode 100644
index 00000000..e6f7f9f7
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_params_dbn_em.m
@@ -0,0 +1,179 @@
+function [bnet, LL, engine] = learn_params_dbn_em(engine, evidence, varargin)
+% LEARN_PARAMS_DBN Set the parameters in a DBN to their ML/MAP values using batch EM.
+% [bnet, LLtrace, engine] = learn_params_dbn_em(engine, data, ...)
+%
+% data{l}{i,t} = value of node i in slice t of time-series l, or [] if hidden.
+%   Suppose you have L time series, each of length T, in an O*T*L array D, 
+%   where O is the num of observed scalar nodes, and N is the total num nodes per slice.
+%   Then you can create data as follows, where onodes is the index of the observable nodes:
+%      data = cell(1,L);
+%      for l=1:L
+%        data{l} = cell(N, T);
+%        data{l}(onodes,:) = num2cell(D(:,:,l));
+%      end
+% Of course it is possible for different sets of nodes to be observed in
+% each slice/ sequence, and for each sequence to be a different length.
+%
+% LLtrace is the learning curve: the vector of log-likelihood scores at each iteration.
+%
+% Optional arguments [default]
+%
+% max_iter - specifies the maximum number of iterations [100]
+% thresh - specifies the thresold for stopping EM [1e-3]
+%   We stop when |f(t) - f(t-1)| / avg < threshold,
+%   where avg = (|f(t)| + |f(t-1)|)/2 and f is log lik.
+% verbose - display loglik at each iteration [1]
+% anneal - 1 means do deterministic annealing (only for entropic priors) [0]
+% anneal_rate - geometric cooling rate [0.8]
+% init_temp - initial annealing temperature [10]
+% final_temp - final annealing temperature [1e-3]
+%
+
+max_iter = 100;
+thresh = 1e-3;
+anneal = 0;
+anneal_rate = 0.8;
+init_temp = 10;
+final_temp = 1e-3;
+verbose = 1;
+
+for i=1:2:length(varargin)
+  switch varargin{i}
+   case 'max_iter', max_iter = varargin{i+1}; 
+   case 'thresh', thresh = varargin{i+1}; 
+   case 'anneal', anneal = varargin{i+1}; 
+   case 'anneal_rate', anneal_rate = varargin{i+1}; 
+   case 'init_temp', init_temp = varargin{i+1}; 
+   case 'final_temp', final_temp = varargin{i+1}; 
+   otherwise, error(['unrecognized argument' varargin{i}])
+  end
+end
+
+% take 1 EM step at each temperature value, then when temp=0, run to convergence
+% When using an entropic prior, Z = 1-T, so 
+% T=2 => Z=-1 (max entropy)
+% T=1 => Z=0 (max likelihood)
+% T=0 => Z=1 (min entropy / max structure)
+num_iter = 1;
+LL = [];
+if anneal
+  temperature = init_temp;
+  while temperature > final_temp
+    [engine, loglik, logpost] = EM_step(engine, evidence, temperature);
+    if verbose
+      fprintf('EM iteration %d, loglik = %8.4f, logpost = %8.4f, temp=%8.4f\n', ...
+	      num_iter, loglik, logpost, temperature);
+    end
+    num_iter = num_iter + 1;
+    LL = [LL loglik];
+    temperature = temperature * anneal_rate;
+  end
+  temperature = 0;
+  previous_loglik = loglik;
+  previous_logpost = logpost;
+else
+  temperature = 0;
+  previous_loglik = -inf;
+  previous_logpost = -inf;
+end
+
+converged = 0;
+while ~converged & (num_iter <= max_iter)
+  [engine, loglik, logpost] = EM_step(engine, evidence, temperature);
+  if verbose
+    %fprintf('EM iteration %d, loglik = %8.4f, logpost = %8.4f\n', ...
+    %	    num_iter, loglik, logpost);
+    fprintf('EM iteration %d, loglik = %8.4f\n', num_iter, loglik);
+  end
+  num_iter = num_iter + 1;
+  [converged, decreased] = em_converged(loglik, previous_loglik, thresh);
+  %[converged, decreased] = em_converged(logpost, previous_logpost, thresh);
+  previous_loglik = loglik;
+  previous_logpost = logpost;
+  LL = [LL loglik];
+end
+
+bnet = bnet_from_engine(engine);
+
+%%%%%%%%%
+
+function [engine, loglik, logpost] = EM_step(engine, cases, temp)
+
+bnet = bnet_from_engine(engine); % engine contains the old params that are used for the E step
+ss = length(bnet.intra);
+CPDs = bnet.CPD; % these are the new params that get maximized
+num_CPDs = length(CPDs);
+
+% log P(theta|D) = (log P(D|theta) + log P(theta)) - log(P(D))
+% where log P(D|theta) = sum_cases log P(case|theta)
+% and log P(theta) = sum_CPDs log P(CPD) - only count once even if tied!
+% logpost = log P(theta,D) (un-normalized)
+% This should be negative, and increase at every step.
+
+adjustable = zeros(1,num_CPDs);
+logprior = zeros(1, num_CPDs);
+for e=1:num_CPDs
+  adjustable(e) = adjustable_CPD(CPDs{e});
+end
+adj = find(adjustable);
+
+for e=adj(:)'
+  logprior(e) = log_prior(CPDs{e});
+  CPDs{e} = reset_ess(CPDs{e});
+end
+
+loglik = 0;
+for l=1:length(cases)
+  evidence = cases{l};
+  if ~iscell(evidence)
+    error('training data must be a cell array of cell arrays')
+  end
+  [engine, ll] = enter_evidence(engine, evidence);
+  assert(~isnan(ll))
+  loglik = loglik + ll;
+  T = size(evidence, 2);
+  
+  % We unroll ns etc because in update_ess, we refer to nodes by their unrolled number
+  % so that they extract evidence from the right place.
+  % (The CPD should really store its own version of ns and cnodes...)
+  ns = repmat(bnet.node_sizes_slice(:), [1 T]);
+  cnodes = unroll_set(bnet.cnodes_slice, ss, T);
+ 
+  %hidden_bitv = repmat(bnet.hidden_bitv(1:ss), [1 T]);
+  hidden_bitv = zeros(ss, T);
+  hidden_bitv(isemptycell(evidence))=1;
+  % hidden_bitv(i) = 1 means node i is hidden.
+  % We pass this in, rather than using isemptycell(evidence(dom)), because
+  % isemptycell is very slow.
+  
+  t = 1;
+  for i=1:ss
+    e = bnet.equiv_class(i,1);
+    if adjustable(e)
+      fmarg = marginal_family(engine, i, t);
+      CPDs{e} = update_ess(CPDs{e}, fmarg, evidence, ns(:), cnodes(:), hidden_bitv(:)); 
+    end
+  end
+  
+  for i=1:ss   
+    e = bnet.equiv_class(i,2);
+    if adjustable(e)
+      for t=2:T
+	fmarg = marginal_family(engine, i, t);
+	CPDs{e} = update_ess(CPDs{e}, fmarg, evidence, ns(:), cnodes(:), hidden_bitv(:));
+      end
+    end
+  end
+end
+
+logpost = loglik + sum(logprior(:));
+
+for e=adj(:)'
+  CPDs{e} = maximize_params(CPDs{e}, temp);
+end
+
+engine = update_engine(engine, CPDs);
+
+
+
+
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_params_em.m b/sourcecodes/bnt-master/BNT/learning/learn_params_em.m
new file mode 100644
index 00000000..f673e712
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_params_em.m
@@ -0,0 +1,88 @@
+function [bnet, LL, engine] = learn_params_em(engine, evidence, max_iter, thresh)
+% LEARN_PARAMS_EM Set the parameters of each adjustable node to their ML/MAP values using batch EM.
+% [bnet, LLtrace, engine] = learn_params_em(engine, data, max_iter, thresh)
+%
+% data{i,l} is the value of node i in case l, or [] if hidden.
+%   Suppose you have L training cases in an O*L array, D, where O is the num observed
+%   scalar nodes, and N is the total num nodes.
+%   Then you can create 'data' as follows, where onodes is the index of the observable nodes:
+%      data = cell(N, L);
+%      data(onodes,:) = num2cell(D);
+%   Of course it is possible for different sets of nodes to be observed in each case.
+%
+% We return the modified bnet and engine.
+% To see the learned parameters for node i, use the construct
+%   s = struct(bnet.CPD{i}); % violate object privacy
+% LLtrace is the learning curve: the vector of log-likelihood scores at each iteration.
+%
+% max_iter specifies the maximum number of iterations. Default: 10.
+%
+% thresh specifies the thresold for stopping EM. Default: 1e-3.
+% We stop when |f(t) - f(t-1)| / avg < threshold,
+% where avg = (|f(t)| + |f(t-1)|)/2 and f is log lik.  
+
+if nargin < 3, max_iter = 10; end
+if nargin < 4, thresh = 1e-3; end
+
+verbose = 1;
+
+loglik = 0;
+previous_loglik = -inf;
+converged = 0;
+num_iter = 1;
+LL = [];
+
+while ~converged & (num_iter <= max_iter)
+  [engine, loglik] = EM_step(engine, evidence);
+  if verbose, fprintf('EM iteration %d, ll = %8.4f\n', num_iter, loglik); end
+  num_iter = num_iter + 1;
+  converged = em_converged(loglik, previous_loglik, thresh);
+  previous_loglik = loglik;
+  LL = [LL loglik];
+end
+if verbose, fprintf('\n'); end
+
+bnet = bnet_from_engine(engine);
+
+%%%%%%%%%
+
+function [engine, loglik] = EM_step(engine, cases)
+
+bnet = bnet_from_engine(engine); % engine contains the old params that are used for the E step
+CPDs = bnet.CPD; % these are the new params that get maximized
+num_CPDs = length(CPDs);
+adjustable = zeros(1,num_CPDs);
+for e=1:num_CPDs
+  adjustable(e) = adjustable_CPD(CPDs{e});
+end
+adj = find(adjustable);
+n = length(bnet.dag);
+
+for e=adj(:)'
+  CPDs{e} = reset_ess(CPDs{e});
+end
+
+loglik = 0;
+ncases = size(cases, 2);
+for l=1:ncases
+  evidence = cases(:,l);
+  [engine, ll] = enter_evidence(engine, evidence);
+  loglik = loglik + ll;
+  hidden_bitv = zeros(1,n);
+  hidden_bitv(isemptycell(evidence))=1;
+  for i=1:n
+    e = bnet.equiv_class(i);
+    if adjustable(e)
+      fmarg = marginal_family(engine, i);
+      CPDs{e} = update_ess(CPDs{e}, fmarg, evidence, bnet.node_sizes, bnet.cnodes, hidden_bitv);
+    end
+  end
+end
+
+for e=adj(:)'
+  CPDs{e} = maximize_params(CPDs{e});
+end
+
+engine = update_engine(engine, CPDs);
+
+
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_struct_K2.m b/sourcecodes/bnt-master/BNT/learning/learn_struct_K2.m
new file mode 100644
index 00000000..8a01a2e9
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_struct_K2.m
@@ -0,0 +1,104 @@
+function dag = learn_struct_K2(data, ns, order, varargin)
+% LEARN_STRUCT_K2 Greedily learn the best structure compatible with a fixed node ordering
+% best_dag = learn_struct_K2(data, node_sizes, order, ...)
+%
+% data(i,m) = value of node i in case m (can be a cell array).
+% node_sizes(i) is the size of node i.
+% order(i) is the i'th node in the topological ordering.
+%
+% The following optional arguments can be specified in the form of name/value pairs:
+% [default value in brackets]
+%
+% max_fan_in - this the largest number of parents we allow per node [N]
+% scoring_fn - 'bayesian' or 'bic' [ 'bayesian' ]
+%              Currently, only networks with all tabular nodes support Bayesian scoring.
+% type       - type{i} is the type of CPD to use for node i, where the type is a string
+%              of the form 'tabular', 'noisy_or', 'gaussian', etc. [ all cells contain 'tabular' ]
+% params     - params{i} contains optional arguments passed to the CPD constructor for node i,
+%              or [] if none.  [ all cells contain {'prior', 1}, meaning use uniform Dirichlet priors ]
+% discrete   - the list of discrete nodes [ 1:N ]
+% clamped    - clamped(i,m) = 1 if node i is clamped in case m [ zeros(N, ncases) ]
+% verbose    - 'yes' means display output while running [ 'no' ]
+%
+% e.g., dag = learn_struct_K2(data, ns, order, 'scoring_fn', 'bic', 'params', [])
+%
+% To be backwards compatible with BNT2, you can also specify arguments as follows
+%   dag = learn_struct_K2(data, node_sizes, order, max_fan_in)    
+%
+% This algorithm is described in
+% - Cooper and Herskovits,  "A Bayesian method for the induction of probabilistic
+%      networks from data", Machine Learning Journal 9:308--347, 1992
+
+[n ncases] = size(data);
+
+% set default params
+type = cell(1,n);
+params = cell(1,n);
+for i=1:n
+  type{i} = 'tabular';
+  %params{i} = { 'prior', 1 };
+  params{i} = { 'prior_type', 'dirichlet', 'dirichlet_weight', 1 };
+end
+scoring_fn = 'bayesian';
+discrete = 1:n;
+clamped = zeros(n, ncases);
+
+max_fan_in = n;
+verbose = 0;
+
+args = varargin;
+nargs = length(args);
+if length(args) > 0 
+  if isstr(args{1})
+    for i=1:2:nargs
+      switch args{i},
+       case 'verbose',    verbose = strcmp(args{i+1}, 'yes');
+       case 'max_fan_in', max_fan_in = args{i+1}; 
+       case 'scoring_fn', scoring_fn = args{i+1};
+       case 'type',       type = args{i+1}; 
+       case 'discrete',   discrete = args{i+1}; 
+       case 'clamped',    clamped = args{i+1}; 
+       case 'params',     if isempty(args{i+1}), params = cell(1,n); else params = args{i+1};  end
+      end
+    end
+  else
+    max_fan_in = args{1};
+  end
+end
+
+dag = zeros(n,n);
+
+for i=1:n
+  ps = [];
+  j = order(i);
+  u = find(clamped(j,:)==0);    
+  score = score_family(j, ps, type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+  if verbose, fprintf('\nnode %d, empty score %6.4f\n', j, score); end
+  done = 0;
+  while ~done & (length(ps) <= max_fan_in)
+    pps = mysetdiff(order(1:i-1), ps); % potential parents
+    nps = length(pps);
+    pscore = zeros(1, nps);
+    for pi=1:nps
+      p = pps(pi);
+      pscore(pi) = score_family(j, [ps p], type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+      if verbose, fprintf('considering adding %d to %d, score %6.4f\n', p, j, pscore(pi)); end
+    end
+    [best_pscore, best_p] = max(pscore);
+    best_p = pps(best_p);
+    if best_pscore > score
+      score = best_pscore;
+      ps = [ps best_p];
+      if verbose, fprintf('* adding %d to %d, score %6.4f\n', best_p, j, best_pscore); end
+    else
+      done = 1;
+    end
+  end
+  if ~isempty(ps) % need this check for matlab 5.2
+    dag(ps, j) = 1;
+  end
+end
+
+
+
+
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_struct_dbn_reveal.m b/sourcecodes/bnt-master/BNT/learning/learn_struct_dbn_reveal.m
new file mode 100644
index 00000000..7be4e5da
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_struct_dbn_reveal.m
@@ -0,0 +1,101 @@
+function inter = learn_struct_dbn_reveal(seqs, ns, max_fan_in, penalty)
+% LEARN_STRUCT_DBN_REVEAL Learn inter-slice adjacency matrix given fully observable discrete time series
+% inter = learn_struct_dbn_reveal(seqs, node_sizes, max_fan_in, penalty)
+% 
+% seqs{l}{i,t} = value of node i in slice t of time-series l.
+%   If you have a single time series in an N*T array D, use
+%      seqs = { num2cell(D) }.
+%   If you have L time series, each of length T, in an N*T*L array D, use
+%      seqs= cell(1,L); for l=1:L, seqs{l} = num2cell(D(:,:,l)); end
+%   or, in vectorized form,
+%      seqs = squeeze(num2cell(num2cell(D),[1 2]));
+% Currently the data is assumed to be discrete (1,2,...)
+%
+% node_sizes(i) is the number of possible values for node i
+% max_fan_in is the largest number of parents we allow per node (default: N)
+% penalty is weight given to the complexity penalty (default: 0.5)
+%  A penalty of 0.5 gives the BIC score.
+%  A penalty of 0 gives the ML score.
+%  Maximizing likelihood is equivalent to maximizing mutual information between parents and child.
+%
+% inter(i,j) = 1 iff node in slice t connects to node j in slice t+1
+%
+% The parent set for each node in slice 2 is computed by evaluating all subsets of nodes in slice 1,
+% and picking the largest scoring one. This takes O(n^k) time per node, where n is the num. nodes
+% per slice, and k <= n is the max fan in.
+% Since all the nodes are observed, we do not need to use an inference engine.
+% And since we are only learning the inter-slice matrix, we do not need to check for cycles.
+%
+% This algorithm is described in
+% - "REVEAL: A general reverse engineering algorithm for inference of genetic network
+%      architectures", Liang et al. PSB 1998
+% - "Extended dependency analysis of large systems",
+%       Roger Conant, Intl. J. General Systems, 1988, vol 14, pp 97-141
+% - "Learning the structure of DBNs", Friedman, Murphy and Russell, UAI 1998.
+
+n = length(ns);
+
+if nargin < 3, max_fan_in = n; end
+if nargin < 4, penalty = 0.5; end
+
+inter = zeros(n,n);
+
+if ~iscell(seqs)
+  data{1} = seqs;
+end
+
+nseq = length(seqs);
+nslices = 0;
+data = cell(1, nseq);
+for l=1:nseq
+  nslices = nslices + size(seqs{l}, 2);
+  data{l} = cell2num(seqs{l})'; % each row is a case
+end
+ndata = nslices - nseq; % subtract off the initial slice of each sequence
+
+% We concatenate the sequences as in the following example.
+% Let there be 2 sequences of lengths 4 and 5, with n nodes per slice,
+% and let i be the target node.
+% Then we construct following matrix D 
+%
+% s{1}{1,1} ... s{1}{1,3}     s{2}{1,1} ... s{2}{1,4}
+% ....
+% s{1}{n,1} ... s{1}{n,3}     s{2}{n,1} ... s{2}{n,4}
+% s{1}{i,2} ... s{1}{i,4}     s{2}{i,2} ... s{2}{i,5}
+%
+% D(1:n, i) is the i'th input and D(n+1, i) is the i'th output.
+% 
+% We concatenate each sequence separately to avoid treating the transition
+% from the end of one sequence to the beginning of another as a "normal" transition.
+
+
+for i=1:n
+  D = [];
+  for l=1:nseq
+    T = size(seqs{l}, 2);
+    A = cell2num(seqs{l}(:, 1:T-1));
+    B = cell2num(seqs{l}(i, 2:T));
+    C = [A;B];
+    D = [D C];
+  end
+  SS = subsets(1:n, max_fan_in, 1); % skip the empty set 
+  nSS = length(SS);
+  bic_score = zeros(1, nSS);
+  ll_score = zeros(1, nSS);
+  target = n+1;
+  ns2 = [ns ns(i)];
+  for h=1:nSS
+    ps = SS{h};
+    dom = [ps target];
+    counts = compute_counts(D(dom, :), ns2(dom));
+    CPT = mk_stochastic(counts);
+    [bic_score(h), ll_score(h)] = bic_score_family(counts, CPT, ndata);
+  end
+  if penalty == 0
+    h = argmax(ll_score);
+  else
+    h = argmax(bic_score);
+  end
+  ps = SS{h};
+  inter(ps, i) = 1;
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_struct_mcmc.m b/sourcecodes/bnt-master/BNT/learning/learn_struct_mcmc.m
new file mode 100644
index 00000000..d39af881
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_struct_mcmc.m
@@ -0,0 +1,284 @@
+function [sampled_graphs, accept_ratio, num_edges] = learn_struct_mcmc(data, ns, varargin)
+% MY_LEARN_STRUCT_MCMC  Monte Carlo Markov Chain search over DAGs assuming fully observed data
+% [sampled_graphs, accept_ratio, num_edges] = learn_struct_mcmc(data, ns, ...)
+% 
+% data(i,m) is the value of node i in case m.
+% ns(i) is the number of discrete values node i can take on.
+%
+% sampled_graphs{m} is the m'th sampled graph.
+% accept_ratio(t) = acceptance ratio at iteration t
+% num_edges(t) = number of edges in model at iteration t
+%
+% The following optional arguments can be specified in the form of name/value pairs:
+% [default value in brackets]
+%
+% scoring_fn - 'bayesian' or 'bic' [ 'bayesian' ]
+%              Currently, only networks with all tabular nodes support Bayesian scoring.
+% type       - type{i} is the type of CPD to use for node i, where the type is a string
+%              of the form 'tabular', 'noisy_or', 'gaussian', etc. [ all cells contain 'tabular' ]
+% params     - params{i} contains optional arguments passed to the CPD constructor for node i,
+%              or [] if none.  [ all cells contain {'prior', 1}, meaning use uniform Dirichlet priors ]
+% discrete   - the list of discrete nodes [ 1:N ]
+% clamped    - clamped(i,m) = 1 if node i is clamped in case m [ zeros(N, ncases) ]
+% nsamples   - number of samples to draw from the chain after burn-in [ 100*N ]
+% burnin     - number of steps to take before drawing samples [ 5*N ]
+% init_dag   - starting point for the search [ zeros(N,N) ]
+%
+% e.g., samples = my_learn_struct_mcmc(data, ns, 'nsamples', 1000);
+%
+% Modified by Sonia Leach (SML) 2/4/02, 9/5/03
+
+
+
+[n ncases] = size(data);
+
+
+% set default params
+type = cell(1,n);
+params = cell(1,n);
+for i=1:n
+ type{i} = 'tabular';
+ %params{i} = { 'prior', 1};
+ params{i} = { 'prior_type', 'dirichlet', 'dirichlet_weight', 1 };
+end
+scoring_fn = 'bayesian';
+discrete = 1:n;
+clamped = zeros(n, ncases);
+nsamples = 100*n;
+burnin = 5*n;
+dag = zeros(n);
+
+args = varargin;
+nargs = length(args);
+for i=1:2:nargs
+ switch args{i},
+  case 'nsamples',   nsamples = args{i+1};
+  case 'burnin',     burnin = args{i+1};
+  case 'init_dag',   dag = args{i+1};
+  case 'scoring_fn', scoring_fn = args{i+1};
+  case 'type',       type = args{i+1}; 
+  case 'discrete',   discrete = args{i+1}; 
+  case 'clamped',    clamped = args{i+1}; 
+  case 'params',     if isempty(args{i+1}), params = cell(1,n); else params = args{i+1};  end
+ end
+end
+
+% We implement the fast acyclicity check described by P. Giudici and R. Castelo,
+% "Improving MCMC model search for data mining", submitted to J. Machine Learning, 2001.
+
+% SML: also keep descendant matrix C
+use_giudici = 1;
+if use_giudici
+ [nbrs, ops, nodes, A] = mk_nbrs_of_digraph(dag);
+else
+ [nbrs, ops, nodes] = mk_nbrs_of_dag(dag);
+ A = [];
+end
+
+num_accepts = 1;
+num_rejects = 1;
+T = burnin + nsamples;
+accept_ratio = zeros(1, T);
+num_edges = zeros(1, T);
+sampled_graphs = cell(1, nsamples);
+%sampled_bitv = zeros(nsamples, n^2);
+
+for t=1:T
+ [dag, nbrs, ops, nodes, A, accept] = take_step(dag, nbrs, ops, ...
+                    nodes, ns, data, clamped, A, ...
+                      scoring_fn, discrete, type, params);
+ num_edges(t) = sum(dag(:));
+ num_accepts = num_accepts + accept;
+ num_rejects = num_rejects + (1-accept);
+ accept_ratio(t) =  num_accepts/num_rejects;
+ if t > burnin
+   sampled_graphs{t-burnin} = dag;
+   %sampled_bitv(t-burnin, :) = dag(:)';
+ end
+end
+
+
+%%%%%%%%%
+
+
+function [new_dag, new_nbrs, new_ops, new_nodes, A,  accept] = ...
+   take_step(dag, nbrs, ops, nodes, ns, data, clamped, A,  ...
+     scoring_fn, discrete, type, params, prior_w)
+
+
+use_giudici = ~isempty(A);
+if use_giudici
+ [new_dag, op, i, j, new_A] =  pick_digraph_nbr(dag, nbrs, ops, nodes,A); % updates A
+ [new_nbrs, new_ops, new_nodes] =  mk_nbrs_of_digraph(new_dag, new_A);
+else
+ d = sample_discrete(normalise(ones(1, length(nbrs))));
+ new_dag = nbrs{d};
+ op = ops{d};
+ i = nodes(d, 1); j = nodes(d, 2);
+ [new_nbrs, new_ops, new_nodes] = mk_nbrs_of_dag(new_dag);
+end
+
+bf =  bayes_factor(dag, new_dag, op, i, j, ns, data, clamped, scoring_fn, discrete, type, params);
+
+%R = bf * (new_prior / prior) * (length(nbrs) / length(new_nbrs)); 
+R = bf * (length(nbrs) / length(new_nbrs)); 
+u = rand(1,1);
+if u > min(1,R) % reject the move
+ accept = 0;
+ new_dag = dag;
+ new_nbrs = nbrs;
+ new_ops = ops;
+ new_nodes = nodes;
+else
+ accept = 1;
+ if use_giudici
+A = new_A; % new_A already updated in pick_digraph_nbr
+ end
+end
+
+
+%%%%%%%%%
+
+function bfactor = bayes_factor(old_dag, new_dag, op, i, j, ns, data, clamped, scoring_fn, discrete, type, params)
+
+u = find(clamped(j,:)==0);
+LLnew = score_family(j, parents(new_dag, j), type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+LLold = score_family(j, parents(old_dag, j), type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+bf1 = exp(LLnew - LLold);
+
+if strcmp(op, 'rev')  % must also multiply in the changes to i's family
+ u = find(clamped(i,:)==0);
+ LLnew = score_family(i, parents(new_dag, i), type{i}, scoring_fn, ns, discrete, data(:,u), params{i});
+ LLold = score_family(i, parents(old_dag, i), type{i}, scoring_fn, ns, discrete, data(:,u), params{i});
+ bf2 = exp(LLnew - LLold);
+else
+ bf2 = 1;
+end
+bfactor = bf1 * bf2;
+
+
+%%%%%%%% Giudici stuff follows %%%%%%%%%%
+
+
+% SML: This now updates A as it goes from digraph it choses
+function [new_dag, op, i, j, new_A] = pick_digraph_nbr(dag, digraph_nbrs, ops, nodes, A)
+
+d = sample_discrete(normalise(ones(1, length(digraph_nbrs))));
+%d = myunidrnd(length(digraph_nbrs),1,1);
+i = nodes(d, 1); j = nodes(d, 2);
+new_dag = digraph_nbrs(:,:,d);
+op = ops{d};
+new_A = update_ancestor_matrix(A, op, i, j, new_dag); 
+
+
+%%%%%%%%%%%%%%
+
+
+function A = update_ancestor_matrix(A,  op, i, j, dag)
+
+switch op
+case 'add',
+ A = do_addition(A,  op, i, j, dag);
+case 'del', 
+ A = do_removal(A,  op, i, j, dag);
+case 'rev', 
+ A = do_removal(A,  op, i, j, dag);
+ A = do_addition(A,  op, j, i, dag);
+end
+
+ 
+%%%%%%%%%%%%
+
+function A = do_addition(A, op, i, j, dag)
+
+A(j,i) = 1; % i is an ancestor of j
+anci = find(A(i,:));
+if ~isempty(anci)
+ A(j,anci) = 1; % all of i's ancestors are added to Anc(j)
+end
+ancj = find(A(j,:));
+descj = find(A(:,j)); 
+if ~isempty(ancj)
+ for k=descj(:)'
+   A(k,ancj) = 1; % all of j's ancestors are added to each descendant of j
+ end
+end
+
+%%%%%%%%%%%
+function A = do_removal(A, op, i, j, dag)
+
+% find all the descendants of j, and put them in topological order
+
+% SML: originally Kevin had the next line commented and the %* lines
+% being used but I think this is equivalent and much less expensive
+% I assume he put it there for debugging and never changed it back...?
+descj = find(A(:,j));
+%*  R = reachability_graph(dag);
+%*  descj = find(R(j,:));
+
+order = topological_sort(dag);
+
+% SML: originally Kevin used the %* line but this was extracting the
+% wrong things to sort
+%* descj_topnum = order(descj);
+[junk, perm] = sort(order); %SML:node i is perm(i)-TH in order
+descj_topnum = perm(descj); %SML:descj(i) is descj_topnum(i)-th in order
+
+% SML: now re-sort descj by rank in descj_topnum
+[junk, perm] = sort(descj_topnum);
+descj = descj(perm);
+
+% Update j and all its descendants
+A = update_row(A, j, dag);
+for k = descj(:)'
+   A = update_row(A, k, dag);
+end
+
+%%%%%%%%%%%
+
+function A = old_do_removal(A, op, i, j, dag)
+
+% find all the descendants of j, and put them in topological order
+% SML: originally Kevin had the next line commented and the %* lines
+% being used but I think this is equivalent and much less expensive
+% I assume he put it there for debugging and never changed it back...?
+descj = find(A(:,j)); 
+%*  R = reachability_graph(dag);
+%*  descj = find(R(j,:)); 
+
+order = topological_sort(dag);
+descj_topnum = order(descj);
+[junk, perm] = sort(descj_topnum);
+descj = descj(perm);
+% Update j and all its descendants
+A = update_row(A, j, dag);
+for k = descj(:)'
+ A = update_row(A, k, dag);
+end
+
+%%%%%%%%%
+
+function A = update_row(A, j, dag)
+
+% We compute row j of A
+A(j, :) = 0;
+ps = parents(dag, j);
+if ~isempty(ps)
+ A(j, ps) = 1;
+end
+for k=ps(:)'
+ anck = find(A(k,:));
+ if ~isempty(anck)
+   A(j, anck) = 1;
+ end
+end
+ 
+%%%%%%%%
+
+function A = init_ancestor_matrix(dag)
+
+order = topological_sort(dag);
+A = zeros(length(dag));
+for j=order(:)'
+ A = update_row(A, j, dag);
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_ic_star.m b/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_ic_star.m
new file mode 100644
index 00000000..4bbba20e
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_ic_star.m
@@ -0,0 +1,155 @@
+function [pdag, G] = learn_struct_pdag_ic_star(cond_indep, n, k, varargin)
+% LEARN_STRUCT_PDAG_IC_STAR Learn a partially oriented DAG (pattern) with latent 
+% variables using the IC* algorithm
+% P = learn_struct_pdag_ic_star(cond_indep, n, k, ...)
+%
+% n is the number of nodes.
+% k is an optional upper bound on the fan-in (default: n)
+% cond_indep is a boolean function that will be called as follows:
+% feval(cond_indep, x, y, S, ...)
+% where x and y are nodes, and S is a set of nodes (positive integers),
+% and ... are any optional parameters passed to this function.
+%
+% The output P is an adjacency matrix, in which
+% P(i,j) = -1 if there is either a latent variable L such that i <-L-> j 
+% OR there is a directed edge from i->j.
+% P(i,j) = -2 if there is a marked directed i-*>j edge.
+% P(i,j) = P(j,i) = 1 if there is and undirected edge i--j
+% P(i,j) = P(j,i) = 2 if there is a latent variable L such that i<-L->j.
+%
+% The IC* algorithm learns a latent structure associated with a set of observed 
+% variables. 
+% The latent structure revealed is the projection in which every latent variable is
+% 1) a root node
+% 2) linked to exactly two observed variables.
+% Latent variables in the projection are represented using a bidirectional graph, 
+% and thus remain implicit.
+%
+% See Pearl, "Causality: Models, Reasoning, and Inference", 2000, p52 for more details.
+% Written by Tamar Kushnir, 2000
+
+sep = cell(n,n);
+ord = 0;
+done = 0;
+G = ones(n,n);
+G = setdiag(G,0);
+while ~done
+  done = 1;
+  [X,Y] = find(G); 
+  for i=1:length(X)
+    x = X(i); y = Y(i);
+    nbrs = mysetdiff(myunion(neighbors(G, x), neighbors(G,y)), [x y]);
+    if length(nbrs) >= ord & G(x,y) ~= 0
+      done = 0;
+      SS = subsets(nbrs, ord, ord); % all subsets of size ord
+      for si=1:length(SS)
+	S = SS{si};
+	if feval(cond_indep, x, y, S, varargin{:})  
+	  G(x,y) = 0;
+	  G(y,x) = 0;
+	  sep{x,y} = myunion(sep{x,y}, S);
+	  sep{y,x} = myunion(sep{y,x}, S);
+	  break; % no need to check any more subsets 
+	end
+      end
+    end
+  end
+  ord = ord + 1;
+end
+
+% Create the minimal pattern,
+% i.e., the only directed edges are V structures.
+pdag = G;
+[X, Y] = find(G);
+% We want to generate all unique triples x,y,z
+% where y is a common neighbor to x and z
+for i=1:length(X)
+  x = X(i);
+  y = Y(i);
+  Z = find(G(y,:));
+  Z = mysetdiff(Z, x);
+  for z=Z(:)'
+    if G(x,z)==0 & ~ismember(y, sep{x,z}) & ~ismember(y, sep{z,x})
+      pdag(x,y) = -1; pdag(y,x) = 0;
+      pdag(z,y) = -1; pdag(y,z) = 0;
+    end
+  end
+end
+
+% Convert the minimal pattern to a complete one using the following rules:
+% Rule 1:
+% if a and b are non-adjacent nodes with a common neighbor c,
+% if a->c and not b->c then c-*>b (marked arrow).
+% Rule 2:
+% if a and b are adjacent and there is a directed path (marked links) from a to b
+% then a->b (add arrowhead).
+%Pearl (2000)
+
+arrowin = [-1 -2 2];
+old_pdag = zeros(n);
+iter = 0;
+while ~isequal(pdag, old_pdag)
+  iter = iter + 1;
+  old_pdag = pdag;
+  % rule 1
+  [X, Y] = find(pdag);
+  for i=1:length(X)
+    x = X(i);
+    y = Y(i);
+    Z = find(pdag(y,:));
+    Z = mysetdiff(Z, x);
+    for z=Z(:)'
+      if G(x,z)==0 & ismember(pdag(x,y),arrowin) & ~ismember(pdag(z,y),arrowin)
+        pdag(y,z) = -2; pdag(z,y) = 0;
+      end
+    end
+  end
+  % rule 2
+  [X, Y] = find(G); 
+  %check all adjacent nodes because if pdag(x,y) = -1 
+  %and pdag(y,x) = 0 there could still be an bidirected edge between x & y.
+  for i=1:length(X)
+    x = X(i);
+    y = Y(i);
+    if ~ismember(pdag(x,y), arrowin) %x->y doesn't exist yet
+      %find marked path from x to y
+      add_arrow = marked_path(x,y,pdag);
+      if add_arrow 
+        if pdag(y,x)==-1 %bidirected edge
+          pdag(x,y) = 2; pdag(y,x) = 2;
+        else
+          pdag(x,y) = -1;pdag(y,x) = 0;
+        end
+      end
+    end
+  end
+end
+
+
+%%%%%%%%%%%%%
+
+function t = marked_path(x,y,L)
+% MARKED_PATH is a boolean function which returns 1 if a marked path 
+% between nodes x and y exists in the partially directed latent structure L.
+%
+% t = marked_path(x,y,L)
+%
+% x and y are the starting and ending nodes in the path, respectively.
+% L is a latent structure (partially directed graph with possible latent variables).
+%
+% Rule 2 of IC* algorithm (see Pearl, 2000)
+
+t=0;
+
+%find set of marked links from x
+marked = find(L(x,:)==-2);
+if ismember(y,marked)
+  t=1; %marked path found
+else
+  for m=marked(:)'
+    t = marked_path(m,y,L);
+    if t==1
+      break; %stop when marked path found
+    end
+  end
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc.m b/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc.m
new file mode 100644
index 00000000..d734a0bd
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc.m
@@ -0,0 +1,130 @@
+function [pdag, G] = learn_struct_pdag_pc(cond_indep, n, k, varargin)
+% LEARN_STRUCT_PDAG_PC Learn a partially oriented DAG (pattern) using the PC algorithm
+% P = learn_struct_pdag_pc(cond_indep, n, k, ...)
+%
+% n is the number of nodes.
+% k is an optional upper bound on the fan-in (default: n)
+% cond_indep is a boolean function that will be called as follows:
+%   feval(cond_indep, x, y, S, ...)
+% where x and y are nodes, and S is a set of nodes (positive integers),
+% and ... are any optional parameters passed to this function.
+%
+% The output P is an adjacency matrix, in which
+% P(i,j) = -1 if there is an i->j edge.
+% P(i,j) = P(j,i) = 1 if there is an undirected edge i <-> j
+%
+% The PC algorithm does structure learning assuming all variables are observed.
+% See Spirtes, Glymour and Scheines, "Causation, Prediction and Search", 1993, p117.
+% This algorithm may take O(n^k) time if there are n variables and k is the max fan-in,
+% but this is quicker than the Verma-Pearl IC algorithm, which is always O(n^n).
+
+  
+sep = cell(n,n);
+ord = 0;
+done = 0;
+G = ones(n,n);
+G=setdiag(G,0);
+while ~done
+  done = 1;
+  [X,Y] = find(G); 
+  for i=1:length(X)
+    x = X(i); y = Y(i);
+    %nbrs = mysetdiff(myunion(neighbors(G, x), neighbors(G,y)), [x y]);
+    nbrs = mysetdiff(neighbors(G, y), x);  % bug fix by Raanan Yehezkel <raanany@ee.bgu.ac.il> 6/27/04
+    nbrs = unique(nbrs); % bug fix Immer Ebert ebert@tree.com 3/278/11
+    if length(nbrs) >= ord & G(x,y) ~= 0
+      done = 0;
+      %SS = subsets(nbrs, ord, ord); % all subsets of size ord
+      SS = subsets1(nbrs, ord);
+      for si=1:length(SS)
+	S = SS{si};
+	if feval(cond_indep, x, y, S, varargin{:})
+	  %if isempty(S)
+ 	  %  fprintf('%d indep of %d ', x, y);
+	  %else
+ 	  %  fprintf('%d indep of %d given ', x, y); fprintf('%d ', S);
+ 	  %end
+ 	  %fprintf('\n');
+	  
+	  % diagnostic
+	  %[CI, r] = cond_indep_fisher_z(x, y, S, varargin{:});
+	  %fprintf(': r = %6.4f\n', r);
+	  
+	  G(x,y) = 0;
+	  G(y,x) = 0;
+	  sep{x,y} = myunion(sep{x,y}, S);
+	  sep{y,x} = myunion(sep{y,x}, S);
+	  break; % no need to check any more subsets 
+	end
+      end
+    end 
+  end
+  ord = ord + 1;
+end
+
+
+% Create the minimal pattern,
+% i.e., the only directed edges are V structures.
+pdag = G;
+[X, Y] = find(G);
+% We want to generate all unique triples x,y,z
+% This code generates x,y,z and z,y,x.
+for i=1:length(X)
+  x = X(i);
+  y = Y(i);
+  Z = find(G(y,:));
+  Z = mysetdiff(Z, x);
+  for z=Z(:)'
+    if G(x,z)==0 & ~ismember(y, sep{x,z}) & ~ismember(y, sep{z,x})
+      %fprintf('%d -> %d <- %d\n', x, y, z);
+      pdag(x,y) = -1; pdag(y,x) = 0;
+      pdag(z,y) = -1; pdag(y,z) = 0;
+    end
+  end
+end
+
+% Convert the minimal pattern to a complete one,
+% i.e., every directed edge in P is compelled
+% (must be directed in all Markov equivalent models),
+% and every undirected edge in P is reversible.
+% We use the rules of Pearl (2000) p51 (derived in Meek (1995))
+
+old_pdag = zeros(n);
+iter = 0;
+while ~isequal(pdag, old_pdag)
+  iter = iter + 1;
+  old_pdag = pdag;
+  % rule 1
+  [A,B] = find(pdag==-1); % a -> b
+  for i=1:length(A)
+    a = A(i); b = B(i);
+    C = find(pdag(b,:)==1 & G(a,:)==0); % all nodes adj to b but not a
+    if ~isempty(C)
+      pdag(b,C) = -1; pdag(C,b) = 0;
+      %fprintf('rule 1: a=%d->b=%d and b=%d-c=%d implies %d->%d\n', a, b, b, C, b, C);
+    end
+  end
+  % rule 2
+  [A,B] = find(pdag==1); % unoriented a-b edge
+  for i=1:length(A)
+    a = A(i); b = B(i);
+    if any( (pdag(a,:)==-1) & (pdag(:,b)==-1)' );
+      pdag(a,b) = -1; pdag(b,a) = 0;
+      %fprintf('rule 2: %d -> %d\n', a, b);
+    end
+  end
+  % rule 3
+  [A,B] = find(pdag==1); % a-b
+  for i=1:length(A)
+    a = A(i); b = B(i);
+    C = find( (pdag(a,:)==1) & (pdag(:,b)==-1)' );
+    % C contains nodes c s.t. a-c->ba
+    G2 = setdiag(G(C, C), 1);
+    if any(G2(:)==0) % there are 2 different non adjacent elements of C
+      pdag(a,b) = -1; pdag(b,a) = 0;
+      %fprintf('rule 3: %d -> %d\n', a, b);
+    end
+  end
+end
+
+  
diff --git a/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc_constrain.m b/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc_constrain.m
new file mode 100644
index 00000000..f226b87e
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/learn_struct_pdag_pc_constrain.m
@@ -0,0 +1,177 @@
+function [pdag, G] = dn_learn_struct_pdag_pc_constrain(adj, cond_indep, n, k, varargin)
+% LEARN_STRUCT_PDAG_PC Learn a partially oriented DAG (pattern) using the PC algorithm
+% Pdag = learn_struct_pdag_pc_constrain(adj, cond_indep, n, k, ...)
+%
+% adj = adjacency matrix learned from dependency network P(i,j) = 1 => i--j; 0 => i  j
+% n is the number of nodes.
+% k is an optional upper bound on the fan-in (default: n)
+% cond_indep is a boolean function that will be called as follows:
+%   feval(cond_indep, x, y, S, ...)
+% where x and y are nodes, and S is a set of nodes (positive integers),
+% and ... are any optional parameters passed to this function.
+%
+%Output
+% pdag  Partially directed graph
+% G     Resulting adjacency graph prior to setting direction arrows
+%
+% The output P is an adjacency matrix, in which
+% P(i,j) = -1 if there is an i->j edge.
+% P(i,j) = P(j,i) = 1 if there is an undirected edge i <-> j
+%
+% The PC algorithm does structure learning assuming all variables are observed.
+% See Spirtes, Glymour and Scheines, "Causation, Prediction and Search", 1993, p117.
+% This algorithm may take O(n^k) time if there are n variables and k is the max fan-in,
+% but this is quicker than the Verma-Pearl IC algorithm, which is always O(n^n).
+% 
+%%  Example
+%%  Given data in a comma separated, filename starting with the variable labels, then the data in rows.
+%%    filename test.txt consists of:
+%%
+%%      Earthquake,Burglar,Radio,Alarm,Call
+%%      1,2,2,2,1
+%%      1,1,2,1,2
+%%      . . .
+%[CovMatrix, obs, varfields] = CovMat('test.txt',5);
+%
+%dn = zeros(5,5); 
+%dn(1,2) = 1;   % This was the known Markov blanket of the system that generated test.txt
+%dn(2,1) = 1;
+%dn(2,4) = 1;
+%dn(4,2) = 1;
+%dn(1,3) = 1;
+%dn(3,1) = 1;
+%dn(1,4) = 1;
+%dn(4,1) = 1;
+%dn(4,5) = 1;
+%dn(5,4) = 1;
+%dn(3,5) = 1; %loop r->c
+%dn(5,3) = 1; %loop c-r
+%dn(3,4) = 1;
+%dn(4,3) = 1;
+%
+%max_fan_in = 4;
+%alpha = 0.05;
+%
+%[pdag G] = learn_struct_pdag_pc_constrain(dn,'cond_indep_fisher_z', 5, max_fan_in, CovMatrix, obs, alpha);
+%%
+%%
+%% Gary Bradski, 7/2002 Modified this to take an adjacency matrix from a dependency network.
+
+  
+sep = cell(n,n);
+ord = 0;
+done = 0;
+G = ones(n,n);
+G=setdiag(G,0);
+
+while ~done
+    done = 1;
+    [X,Y] = find(G);
+    for i=1:length(X)
+        x = X(i); y = Y(i);
+%        nbrs = mysetdiff(myunion(neighbors(G, x), neighbors(G,y)), [x y]);%parents, children, but not self
+        nbrs = mysetdiff(myunion(neighbors(adj, x), neighbors(adj,y)), [x y]);%parents, children, but not self
+
+        if length(nbrs) >= ord & G(x,y) ~= 0
+            done = 0;
+            SS = subsets(nbrs, ord, ord); % all subsets of size ord
+            for si=1:length(SS)
+                S = SS{si};
+                 %if (feval(dsep,x,y,S,adj)) | (feval(cond_indep, x, y, S, varargin{:}))
+                 if feval(cond_indep, x, y, S, varargin{:})
+                     %if isempty(S)
+                    %  fprintf('%d indep of %d ', x, y);
+                    %else
+                    %  fprintf('%d indep of %d given ', x, y); fprintf('%d ', S);
+                    %end
+                    %fprintf('\n');
+                    
+                    % diagnostic
+                    %[CI, r] = cond_indep_fisher_z(x, y, S, varargin{:});
+                    %fprintf(': r = %6.4f\n', r);
+                    
+                    G(x,y) = 0;
+                    G(y,x) = 0;
+                    adj(x,y) = 0;  %make sure found cond. independencies are marked out
+                    adj(y,x) = 0;
+                    sep{x,y} = myunion(sep{x,y}, S);
+                    sep{y,x} = myunion(sep{y,x}, S);
+                    break; % no need to check any more subsets 
+                end
+            end
+        end 
+    end
+    ord = ord + 1;
+end
+
+
+
+
+% Create the minimal pattern,
+% i.e., the only directed edges are V structures.
+
+pdag = G;
+[X, Y] = find(G);
+% We want to generate all unique triples x,y,z
+% This code generates x,y,z and z,y,x.
+for i=1:length(X)
+  x = X(i);
+  y = Y(i);
+  Z = find(G(y,:));
+  Z = mysetdiff(Z, x);
+  for z=Z(:)'
+    if G(x,z)==0 & ~ismember(y, sep{x,z}) & ~ismember(y, sep{z,x})
+      %fprintf('%d -> %d <- %d\n', x, y, z);
+      pdag(x,y) = -1; pdag(y,x) = 0;
+      pdag(z,y) = -1; pdag(y,z) = 0;
+    end
+  end
+end
+
+% Convert the minimal pattern to a complete one,
+% i.e., every directed edge in P is compelled
+% (must be directed in all Markov equivalent models),
+% and every undirected edge in P is reversible.
+% We use the rules of Pearl (2000) p51 (derived in Meek (1995))
+
+old_pdag = zeros(n);
+iter = 0;
+while ~isequal(pdag, old_pdag)
+  iter = iter + 1;
+  old_pdag = pdag;
+  % rule 1
+  [A,B] = find(pdag==-1); % a -> b
+  for i=1:length(A)
+    a = A(i); b = B(i);
+    C = find(pdag(b,:)==1 & G(a,:)==0); % all nodes adj to b but not a
+    if ~isempty(C)
+      pdag(b,C) = -1; pdag(C,b) = 0;
+      %fprintf('rule 1: a=%d->b=%d and b=%d-c=%d implies %d->%d\n', a, b, b, C, b, C);
+    end
+  end
+  % rule 2
+  [A,B] = find(pdag==1); % unoriented a-b edge
+  for i=1:length(A)
+    a = A(i); b = B(i);
+    if any( (pdag(a,:)==-1) & (pdag(:,b)==-1)' );
+      pdag(a,b) = -1; pdag(b,a) = 0;
+      %fprintf('rule 2: %d -> %d\n', a, b);
+    end
+  end
+  % rule 3
+  [A,B] = find(pdag==1); % a-b
+  for i=1:length(A)
+    a = A(i); b = B(i);
+    C = find( (G(a,:)==1) & (pdag(:,b)==-1)' );
+    % C contains nodes c s.t. a-c->ba
+    G2 = setdiag(G(C, C), 1);
+    if any(G2(:)==0) % there are 2 different non adjacent elements of C
+      pdag(a,b) = -1; pdag(b,a) = 0;
+      %fprintf('rule 3: %d -> %d\n', a, b);
+    end
+  end
+end
+
+
+  
+
diff --git a/sourcecodes/bnt-master/BNT/learning/mcmc_sample_to_hist.m b/sourcecodes/bnt-master/BNT/learning/mcmc_sample_to_hist.m
new file mode 100644
index 00000000..8b277c8a
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/mcmc_sample_to_hist.m
@@ -0,0 +1,36 @@
+function mcmc_post = mcmc_sample_to_hist(sampled_graphs, dags)
+% MCMC_SAMPLE_TO_HIST Convert a set of sampled dags into a histogram over dags
+% hist = mcmc_sample_to_hist(sampled_graphs, dags)
+%
+% sampled_graphs{m} is the m'th sampled dag
+% dags{i} is the i'th dag in the hypothesis space
+% hist(i) = Pr(model i | data)
+
+ndags = length(dags);
+nsamples = length(sampled_graphs);
+nnodes = length(dags{1});
+% sampled_bitv(m, :) is the m'th sampled graph represented as a vector of n^2 bits, computed
+% by stacking the columns of the adjacency matrix vertically.
+sampled_bitvs = zeros(nsamples, nnodes*nnodes);
+for m=1:nsamples
+  sampled_bitvs(m, :) = sampled_graphs{m}(:)';
+end
+  
+[ugraphs, I, J] = unique(sampled_bitvs, 'rows');  % each row of ugraphs is a unique bit vector
+sampled_indices  = subv2ind(2*ones(1,nnodes*nnodes), ugraphs+1);
+counts = hist(J, 1:size(ugraphs,1)); % counts(i) = number of times graphs(i,:) occurs in the sample
+
+mcmc_post = zeros(1, ndags);
+for i=1:ndags
+  bitv = dags{i}(:)';
+  % Find the samples that corresponds to this graph by converting the graphs to bitvectors and
+  % then to integers.
+  ndx = subv2ind(2*ones(1,nnodes*nnodes), bitv+1);
+  locn = find(ndx == sampled_indices);
+  if ~isempty(locn)
+    mcmc_post(i) = counts(locn);
+  end
+end
+mcmc_post = normalise(mcmc_post);
+
+
diff --git a/sourcecodes/bnt-master/BNT/learning/mk_schedule.m b/sourcecodes/bnt-master/BNT/learning/mk_schedule.m
new file mode 100644
index 00000000..018f3d16
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/mk_schedule.m
@@ -0,0 +1,10 @@
+function schedule = mk_schedule(init_temp, final_temp, anneal_rate)
+
+init_temp = 10; final_temp = 1e-2; anneal_rate = 0.8;
+schedule = [];
+temp=init_temp;
+schedule = [schedule temp];
+while temp > final_temp
+  temp = temp * anneal_rate;
+  schedule = [schedule temp];
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/mk_tetrad_data_file.m b/sourcecodes/bnt-master/BNT/learning/mk_tetrad_data_file.m
new file mode 100644
index 00000000..9c556556
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/mk_tetrad_data_file.m
@@ -0,0 +1,25 @@
+function mk_tetrad_data_file(filename, samples, sig)
+% MK_TETRAD_DATA_FILE Make a file containing raw discrete data for input to TETRAD
+% mk_tetrad_data_file(filename, samples, sig)
+%
+% samples(i,j) is the value for case i, variable j
+% The resulting file can be used for the 'build' part of Tetrad.
+% For details on tetrad, see hss.cmu.edu/html/departments/philosophy/TETRAD/tetrad.html
+
+[nsamples N] = size(samples);
+
+fid = fopen(filename, 'w');
+fprintf(fid, '/Raw\n');
+fprintf(fid, '%d\n', nsamples);
+for i=1:N
+  fprintf(fid, 'x%d ', i);
+end
+fprintf(fid, '\n');
+for i=1:nsamples
+  fprintf(fid, '%d ', samples(i,:)-1); % tetrad counts from 0
+  fprintf(fid, '\n');
+end
+%fprintf(fid, '/Knowledge\n');
+%fprintf(fid, 'Significance %4.2f\n', sig);
+fclose(fid);
+
diff --git a/sourcecodes/bnt-master/BNT/learning/score_dags_old.m b/sourcecodes/bnt-master/BNT/learning/score_dags_old.m
new file mode 100644
index 00000000..507721f6
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/score_dags_old.m
@@ -0,0 +1,62 @@
+function score = score_dags(data, ns, dags, varargin)
+% SCORE_DAGS Compute the score of one or more DAGs
+% score = score_dags(data, ns, dags, varargin)
+%
+% data{i,m} = value of node i in case m (can be a cell array).
+% node_sizes(i) is the number of size of node i.
+% dags{g} is the g'th dag
+% score(g) is the score of the i'th dag
+%
+% The following optional arguments can be specified in the form of name/value pairs:
+% [default value in brackets]
+%
+% scoring_fn - 'bayesian' or 'bic' [ 'bayesian' ]
+%              Currently, only networks with all tabular nodes support Bayesian scoring.
+% type       - type{i} is the type of CPD to use for node i, where the type is a string
+%              of the form 'tabular', 'noisy_or', 'gaussian', etc. [ all cells contain 'tabular' ]
+% params     - params{i} contains optional arguments passed to the CPD constructor for node i,
+%              or [] if none.  [ all cells contain {'prior', 1}, meaning use uniform Dirichlet priors ]
+% discrete   - the list of discrete nodes [ 1:N ]
+% clamped    - clamped(i,m) = 1 if node i is clamped in case m [ zeros(N, ncases) ]
+%
+% e.g., score = score_dags(data, ns, mk_all_dags(n), 'scoring_fn', 'bic', 'params', []);
+%
+% If the DAGs have a lot of families in common, we can cache the sufficient statistics,
+% making this potentially more efficient than scoring the DAGs one at a time.
+% (Caching is not currently implemented, however.)
+
+[n ncases] = size(data);
+
+% set default params
+type = cell(1,n);
+params = cell(1,n);
+for i=1:n
+  type{i} = 'tabular';
+  params{i} = { 'prior_type', 'dirichlet', 'dirichlet_weight', 1 };
+end
+scoring_fn = 'bayesian';
+discrete = 1:n;
+clamped = zeros(n, ncases);
+
+args = varargin;
+nargs = length(args);
+for i=1:2:nargs
+  switch args{i},
+   case 'scoring_fn', scoring_fn = args{i+1};
+   case 'type',       type = args{i+1}; 
+   case 'discrete',   discrete = args{i+1}; 
+   case 'clamped',    clamped = args{i+1}; 
+   case 'params',     if isempty(args{i+1}), params = cell(1,n); else params = args{i+1};  end
+  end
+end
+
+NG = length(dags);
+score = zeros(1, NG);
+for g=1:NG
+  dag = dags{g};
+  for j=1:n
+    u = find(clamped(j,:)==0);    
+    ps = parents(dag, j);
+    score(g) = score(g) + score_family(j, ps, type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+  end
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/score_dags_wocache.m b/sourcecodes/bnt-master/BNT/learning/score_dags_wocache.m
new file mode 100644
index 00000000..79684080
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/score_dags_wocache.m
@@ -0,0 +1,67 @@
+function score = score_dags(data, ns, dags, varargin)
+% SCORE_DAGS Compute the score of one or more DAGs
+% score = score_dags(data, ns, dags, varargin)
+%
+% data{i,m} = value of node i in case m (can be a cell array).
+% node_sizes(i) is the number of size of node i.
+% dags{g} is the g'th dag
+% score(g) is the score of the i'th dag
+%
+% The following optional arguments can be specified in the form of name/value pairs:
+% [default value in brackets]
+%
+% scoring_fn - 'bayesian' or 'bic' [ 'bayesian' ]
+%              Currently, only networks with all tabular nodes support Bayesian scoring.
+% type       - type{i} is the type of CPD to use for node i, where the type is a string
+%              of the form 'tabular', 'noisy_or', 'gaussian', etc. [ all cells contain 'tabular' ]
+% params     - params{i} contains optional arguments passed to the CPD constructor for node i,
+%              or [] if none.  [ all cells contain {'prior', 1}, meaning use uniform Dirichlet priors ]
+% discrete   - the list of discrete nodes [ 1:N ]
+% clamped    - clamped(i,m) = 1 if node i is clamped in case m [ zeros(N, ncases) ]
+%
+% e.g., score = score_dags(data, ns, mk_all_dags(n), 'scoring_fn', 'bic', 'params', []);
+%
+% If the DAGs have a lot of families in common, we can cache the sufficient statistics,
+% making this potentially more efficient than scoring the DAGs one at a time.
+% (Caching is not currently implemented, however.)
+
+[n ncases] = size(data);
+
+% set default params
+type = cell(1,n);
+params = cell(1,n);
+for i=1:n
+  type{i} = 'tabular';
+  params{i} = { 'prior_type', 'dirichlet', 'dirichlet_weight', 1 };
+end
+scoring_fn = 'bayesian';
+discrete = 1:n;
+
+u = [1:ncases]'; % DWH
+isclamped = 0; %DWH
+clamped = zeros(n, ncases);
+
+args = varargin;
+nargs = length(args);
+for i=1:2:nargs
+  switch args{i},
+   case 'scoring_fn', scoring_fn = args{i+1};
+   case 'type',       type = args{i+1}; 
+   case 'discrete',   discrete = args{i+1}; 
+   case 'clamped',    clamped = args{i+1}, isclamped = 1; %DWH
+   case 'params',     if isempty(args{i+1}), params = cell(1,n); else params = args{i+1};  end
+  end
+end
+
+NG = length(dags);
+score = zeros(1, NG);
+for g=1:NG
+  dag = dags{g};
+  for j=1:n
+    if isclamped %DWH
+        u = find(clamped(j,:)==0);    
+    end
+    ps = parents(dag, j);
+    score(g) = score(g) + score_family(j, ps, type{j}, scoring_fn, ns, discrete, data(:,u), params{j});
+  end
+end
diff --git a/sourcecodes/bnt-master/BNT/learning/score_family_wocache.m b/sourcecodes/bnt-master/BNT/learning/score_family_wocache.m
new file mode 100644
index 00000000..a0710ba5
--- /dev/null
+++ b/sourcecodes/bnt-master/BNT/learning/score_family_wocache.m
@@ -0,0 +1,57 @@
+function score = score_family(j, ps, node_type, scoring_fn, ns, discrete, data, args)
+% SCORE_FAMILY_COMPLETE Compute the score of a node and its parents given completely observed data
+% score = score_family(j, ps, node_type, scoring_fn, ns, discrete, data, args)
+%
+% data(i,m) is the value of node i in case m (can be a cell array)
+% args is a cell array containing optional arguments passed to the constructor,
+% or is [] if none
+%
+% We create a whole Bayes net which only connects parents to node,
+% where node has a CPD of the specified type (with default parameters).
+% We then evaluate its score ('bic' or 'bayesian')
+
+% We should use a cache to avoid unnecessary computation.
+% In particular, log_marginal_prob_node for tabular CPDs calls gammaln
+% and compute_counts, both of which are slow.
+
+[n ncases] = size(data);
+dag = zeros(n,n);
+% SML added to sort ps b/c mk_bnet, learn_params use sorted ps to make
+% CPTs
+% Kevin had: if ~isempty(ps), dag(ps, j) = 1; end
+if ~isempty(ps), dag(ps, j) = 1;, ps = sort(ps);, end
+
+bnet = mk_bnet(dag, ns, 'discrete', discrete);
+%bnet.CPD{j} = xxx_CPD(bnet, j);
+%eval(sprintf('bnet.CPD{j} = %s_CPD(bnet, j);', node_type));
+fname = sprintf('%s_CPD', node_type);
+%fprintf('score CPD %d\n', j);
+if isempty(args)
+  bnet.CPD{j} = feval(fname, bnet, j);
+else
+  bnet.CPD{j} = feval(fname, bnet, j, args{:});
+end
+switch scoring_fn
+ case 'bic',
+  fam = [ps j];
+  %score = BIC_score_CPD(bnet.CPD{j}, fam, data, ns, bnet.cnodes);
+  %bnet.CPD{j} = learn_params(bnet.CPD{j}, fam, data, ns, bnet.cnodes);
+  
+  % SML 03/16/04 had to special case gaussian b/c generic_CPD/learn_params
+  % no longer supported because of simple interface to learn_params
+  % introduced by KPM for tabular nodes below:
+  % KPM 9 June 04 - tabular nodes have changed back!
+  if 1 % (isempty(find(j==discrete)))
+     bnet.CPD{j} = learn_params(bnet.CPD{j},  fam, data, ns, bnet.cnodes);
+  else 
+  	bnet.CPD{j} = learn_params(bnet.CPD{j}, data(fam, :));
+  end
+  L = log_prob_node(bnet.CPD{j}, data(j,:), data(ps,:));
+  S = struct(bnet.CPD{j}); % violate object privacy
+  score = L - 0.5*S.nparams*log(ncases);
+ case 'bayesian', 
+  %score = bayesian_score_CPD(bnet.CPD{j}, data(fam, :));
+  score = log_marg_prob_node(bnet.CPD{j}, data(j,:), data(ps,:));
+ otherwise,
+  error(['unrecognized scoring fn ' scoring_fn]);
+end