To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / _FullBNT / BNT / graph / mk_nbrs_of_digraph.m @ 8:b5b38998ef3b

History | View | Annotate | Download (4.6 KB)

1
function [Gs, op, nodes, A] = my_mk_nbs_of_digraph(G0,A)
2
% MY_MK_NBRS_OF_DIGRAPH Make all digraphs that differ from G0 by a single edge deletion, addition or reversal, subject to acyclicity
3
% [Gs, op, nodes, A] = my_mk_nbrs_of_digraph(G0,<A>)
4
%
5
% G0 is an adj matrix s.t. G0(i,j)=1 iff i->j in graph
6
% A is the ancestor matrix for G0  (opt, creates if necessary)
7
%
8
% Gs(:,:,i) is the i'th neighbor
9
% op{i} = 'add', 'del', or 'rev' is the operation used to create the i'th neighbor. 
10
% nodes(i,1:2) are the head and tail of the operated-on arc.
11
% Modified from mk_nbrs_of_digraph by Sonia Leach
12
%
13
% Modified by Sonia Leach Feb 02
14

    
15
if nargin ==1, A = reachability_graph(G0');, end
16

    
17
n = length(G0);
18
[I,J] = find(G0); % I(k), J(k) is the k'th edge
19
E = length(I);    % num edges present in G0
20

    
21

    
22
% SINGLE EDGE DELETIONS
23
% all deletions are valid wrt acyclity
24

    
25
Grep = repmat(G0(:), 1, E); % each column is a copy of G0
26
% edge_ndx(k) is the scalar location of the k'th edge 
27
edge_ndx = find(G0);
28

    
29
% edge_ndx = subv2ind([n n], [I J]); % equivalent
30
% We set (ndx(k), k) to 0 for k=1:E in Grep
31
ndx = subv2ind(size(Grep), [edge_ndx(:) (1:E)']);
32
G1 = Grep;
33
G1(ndx) = 0;
34
Gdel = reshape(G1, [n n E]);
35

    
36

    
37
% SINGLE EDGE REVERSALS
38

    
39
% SML: previously Kevin had that legal structure was if
40
% A(P,i)=1 for any P = { p | p in parents(j), p~=i}
41
% specifically he said 
42
%  "if any(A(ps,i)) then there is a path i -> parent of j -> j
43
%   so reversing i->j would create a cycle"
44
% Thus put in another way:
45
%    for each i,j if sum(G0(:,j)' * A(:,i)) > 0, reversing i->j
46
% is not legal.
47
%
48
% Ex. Suppose we want to check if 2->4 can be reversed in the 
49
% following graph: 
50
% G0 =                               A =
51
%     0     0     1     0               0     0     0     0
52
%     0     0     1     1               0     0     0     0
53
%     0     0     0     1               1     1     0     0
54
%     0     0     0     0               1     1     1     0
55
% 
56
% Then parents(4) = G0(:,4) = [0 1 1 0]'
57
% and A(:,2) = [0 0 1 1]. Thus G0(:,4)'*A(:,2) = 1 b/c 3 is
58
% an ancestor of 4 and a child of 2. Note that this works b/c
59
% matrix multiplication has the effect of ANDing the two vectors 
60
% and summing up the result (equiv. to the any(A(ps,i)) in kevin's code)
61
%
62
% So, we vectorize and check for all i,j pairs by looking for
63
% 1's in L = (G0'*A)' which has L(i,j)=1 if rev(i,j) not legal
64
% Note that this will give 1's where there are none in the G0
65
% so we do a L=max(0, G0-L) to cancel out only the existing edges that 
66
% aren't legal (subtracting where both are 1 and setting where
67
% G0=0 and A=1 back to 0).
68

    
69
L = max(0, G0-(G0'*A)');
70
[IL, JL] = find(L);  % I(k), J(k) is the k'th legal edge to rev.
71
EL = length(IL);
72

    
73

    
74
% SML: First we have to DELETE THE EDGES WE ARE REVERSING
75
% We can't use G1 w/ reversed edges already deleted (as
76
% Kevin did) b/c the space of possible deletions are different 
77
% now (some reverses aren't legal)
78

    
79
Grep = repmat(G0(:), 1, EL); % each column is a copy of G0
80
% edge_ndx(k) is the scalar location of the k'th edge 
81
edge_ndx = subv2ind([n n], [IL JL]); 
82
% We set (ndx(k), k) to 0 for k=1:E in Grep
83
ndx = subv2ind(size(Grep), [edge_ndx(:) (1:EL)']);
84
G1 = Grep;
85
G1(ndx) = 0;
86

    
87
% SML: Now we add in our REVERSED EDGES
88
% rev_edge_ndx(k) is the scalar location of the k'th legal reversed edge
89
rev_edge_ndx = subv2ind([n n], [JL IL]);
90

    
91
% We set (rev_edge_ndx(k), k) to 1 for k=1:EL in G1
92
% We have already deleted i->j in the previous step
93
ndx = subv2ind(size(Grep), [rev_edge_ndx(:) (1:EL)']);
94
G1(ndx) = 1;
95
Grev = reshape(G1, [n n EL]);
96

    
97
% SINGLE EDGE ADDITIONS
98

    
99
% SML: previously Kevin had that any addition was legal if A(i,j)=0
100
% however, you can not add i->j  if j is a descendent of i.
101
% Thus, we create all possible additions in Gbar and then
102
% subtract the descendants of each edge as possible parents
103
% This means the potential parents of i (i.e. Gbar(:,i))
104
% can not also be descendants if i i.e. (A(:,i)) which is accomplished
105
% by subtracting (Gbar-A == 1 iff Gbar=1 & A=0)
106

    
107
Gbar = ~G0;  % Gbar(i,j)=1 iff there is no i->j edge in G0
108
Gbar = setdiag(Gbar, 0); % turn off self loops
109

    
110
GbarL = Gbar-A;
111
[IbarL, JbarL] = find(GbarL);  % I(k), J(k) is the k'th legal edge to add
112
EbarL = length(IbarL);
113

    
114
bar_edge_ndx = find(GbarL);
115

    
116
Grep = repmat(G0(:), 1, EbarL); % each column is a copy of G0
117
ndx = subv2ind(size(Grep), [bar_edge_ndx(:) (1:EbarL)']);
118
Grep(ndx) = 1;
119
Gadd = reshape(Grep, [n n EbarL]);
120

    
121

    
122
Gs = cat(3, Gdel, Grev, Gadd);
123

    
124
nodes = [I J;
125
     IL JL;
126
   IbarL JbarL];
127

    
128
op = cell(1, E+EL+EbarL);
129
op(1:E) = {'del'};
130
op(E+(1:EL)) = {'rev'};
131
op((E+EL+1):end) = {'add'};
132