annotate _FullBNT/BNT/learning/learn_struct_pdag_pc.m @ 9:4ea6619cb3f5 tip

removed log files
author matthiasm
date Fri, 11 Apr 2014 15:55:11 +0100
parents b5b38998ef3b
children
rev   line source
matthiasm@8 1 function [pdag, G] = learn_struct_pdag_pc(cond_indep, n, k, varargin)
matthiasm@8 2 % LEARN_STRUCT_PDAG_PC Learn a partially oriented DAG (pattern) using the PC algorithm
matthiasm@8 3 % P = learn_struct_pdag_pc(cond_indep, n, k, ...)
matthiasm@8 4 %
matthiasm@8 5 % n is the number of nodes.
matthiasm@8 6 % k is an optional upper bound on the fan-in (default: n)
matthiasm@8 7 % cond_indep is a boolean function that will be called as follows:
matthiasm@8 8 % feval(cond_indep, x, y, S, ...)
matthiasm@8 9 % where x and y are nodes, and S is a set of nodes (positive integers),
matthiasm@8 10 % and ... are any optional parameters passed to this function.
matthiasm@8 11 %
matthiasm@8 12 % The output P is an adjacency matrix, in which
matthiasm@8 13 % P(i,j) = -1 if there is an i->j edge.
matthiasm@8 14 % P(i,j) = P(j,i) = 1 if there is an undirected edge i <-> j
matthiasm@8 15 %
matthiasm@8 16 % The PC algorithm does structure learning assuming all variables are observed.
matthiasm@8 17 % See Spirtes, Glymour and Scheines, "Causation, Prediction and Search", 1993, p117.
matthiasm@8 18 % This algorithm may take O(n^k) time if there are n variables and k is the max fan-in,
matthiasm@8 19 % but this is quicker than the Verma-Pearl IC algorithm, which is always O(n^n).
matthiasm@8 20
matthiasm@8 21
matthiasm@8 22 sep = cell(n,n);
matthiasm@8 23 ord = 0;
matthiasm@8 24 done = 0;
matthiasm@8 25 G = ones(n,n);
matthiasm@8 26 G=setdiag(G,0);
matthiasm@8 27 while ~done
matthiasm@8 28 done = 1;
matthiasm@8 29 [X,Y] = find(G);
matthiasm@8 30 for i=1:length(X)
matthiasm@8 31 x = X(i); y = Y(i);
matthiasm@8 32 %nbrs = mysetdiff(myunion(neighbors(G, x), neighbors(G,y)), [x y]);
matthiasm@8 33 nbrs = mysetdiff(neighbors(G, y), x); % bug fix by Raanan Yehezkel <raanany@ee.bgu.ac.il> 6/27/04
matthiasm@8 34 if length(nbrs) >= ord & G(x,y) ~= 0
matthiasm@8 35 done = 0;
matthiasm@8 36 %SS = subsets(nbrs, ord, ord); % all subsets of size ord
matthiasm@8 37 SS = subsets1(nbrs, ord);
matthiasm@8 38 for si=1:length(SS)
matthiasm@8 39 S = SS{si};
matthiasm@8 40 if feval(cond_indep, x, y, S, varargin{:})
matthiasm@8 41 %if isempty(S)
matthiasm@8 42 % fprintf('%d indep of %d ', x, y);
matthiasm@8 43 %else
matthiasm@8 44 % fprintf('%d indep of %d given ', x, y); fprintf('%d ', S);
matthiasm@8 45 %end
matthiasm@8 46 %fprintf('\n');
matthiasm@8 47
matthiasm@8 48 % diagnostic
matthiasm@8 49 %[CI, r] = cond_indep_fisher_z(x, y, S, varargin{:});
matthiasm@8 50 %fprintf(': r = %6.4f\n', r);
matthiasm@8 51
matthiasm@8 52 G(x,y) = 0;
matthiasm@8 53 G(y,x) = 0;
matthiasm@8 54 sep{x,y} = myunion(sep{x,y}, S);
matthiasm@8 55 sep{y,x} = myunion(sep{y,x}, S);
matthiasm@8 56 break; % no need to check any more subsets
matthiasm@8 57 end
matthiasm@8 58 end
matthiasm@8 59 end
matthiasm@8 60 end
matthiasm@8 61 ord = ord + 1;
matthiasm@8 62 end
matthiasm@8 63
matthiasm@8 64
matthiasm@8 65 % Create the minimal pattern,
matthiasm@8 66 % i.e., the only directed edges are V structures.
matthiasm@8 67 pdag = G;
matthiasm@8 68 [X, Y] = find(G);
matthiasm@8 69 % We want to generate all unique triples x,y,z
matthiasm@8 70 % This code generates x,y,z and z,y,x.
matthiasm@8 71 for i=1:length(X)
matthiasm@8 72 x = X(i);
matthiasm@8 73 y = Y(i);
matthiasm@8 74 Z = find(G(y,:));
matthiasm@8 75 Z = mysetdiff(Z, x);
matthiasm@8 76 for z=Z(:)'
matthiasm@8 77 if G(x,z)==0 & ~ismember(y, sep{x,z}) & ~ismember(y, sep{z,x})
matthiasm@8 78 %fprintf('%d -> %d <- %d\n', x, y, z);
matthiasm@8 79 pdag(x,y) = -1; pdag(y,x) = 0;
matthiasm@8 80 pdag(z,y) = -1; pdag(y,z) = 0;
matthiasm@8 81 end
matthiasm@8 82 end
matthiasm@8 83 end
matthiasm@8 84
matthiasm@8 85 % Convert the minimal pattern to a complete one,
matthiasm@8 86 % i.e., every directed edge in P is compelled
matthiasm@8 87 % (must be directed in all Markov equivalent models),
matthiasm@8 88 % and every undirected edge in P is reversible.
matthiasm@8 89 % We use the rules of Pearl (2000) p51 (derived in Meek (1995))
matthiasm@8 90
matthiasm@8 91 old_pdag = zeros(n);
matthiasm@8 92 iter = 0;
matthiasm@8 93 while ~isequal(pdag, old_pdag)
matthiasm@8 94 iter = iter + 1;
matthiasm@8 95 old_pdag = pdag;
matthiasm@8 96 % rule 1
matthiasm@8 97 [A,B] = find(pdag==-1); % a -> b
matthiasm@8 98 for i=1:length(A)
matthiasm@8 99 a = A(i); b = B(i);
matthiasm@8 100 C = find(pdag(b,:)==1 & G(a,:)==0); % all nodes adj to b but not a
matthiasm@8 101 if ~isempty(C)
matthiasm@8 102 pdag(b,C) = -1; pdag(C,b) = 0;
matthiasm@8 103 %fprintf('rule 1: a=%d->b=%d and b=%d-c=%d implies %d->%d\n', a, b, b, C, b, C);
matthiasm@8 104 end
matthiasm@8 105 end
matthiasm@8 106 % rule 2
matthiasm@8 107 [A,B] = find(pdag==1); % unoriented a-b edge
matthiasm@8 108 for i=1:length(A)
matthiasm@8 109 a = A(i); b = B(i);
matthiasm@8 110 if any( (pdag(a,:)==-1) & (pdag(:,b)==-1)' );
matthiasm@8 111 pdag(a,b) = -1; pdag(b,a) = 0;
matthiasm@8 112 %fprintf('rule 2: %d -> %d\n', a, b);
matthiasm@8 113 end
matthiasm@8 114 end
matthiasm@8 115 % rule 3
matthiasm@8 116 [A,B] = find(pdag==1); % a-b
matthiasm@8 117 for i=1:length(A)
matthiasm@8 118 a = A(i); b = B(i);
matthiasm@8 119 C = find( (pdag(a,:)==1) & (pdag(:,b)==-1)' );
matthiasm@8 120 % C contains nodes c s.t. a-c->ba
matthiasm@8 121 G2 = setdiag(G(C, C), 1);
matthiasm@8 122 if any(G2(:)==0) % there are 2 different non adjacent elements of C
matthiasm@8 123 pdag(a,b) = -1; pdag(b,a) = 0;
matthiasm@8 124 %fprintf('rule 3: %d -> %d\n', a, b);
matthiasm@8 125 end
matthiasm@8 126 end
matthiasm@8 127 end
matthiasm@8 128
matthiasm@8 129