1 package baseCode.dataStructure.graph;
2
3 import java.util.Iterator;
4 import java.util.LinkedHashSet;
5 import java.util.Set;
6
7 /***
8 * A graph node that has the concept of parents and children. Keys can be anything, but probably Strings or Integers.
9 * <p>
10 * Copyright (c) Columbia University
11 *
12 * @author Paul Pavlidis
13 * @version $Id: DirectedGraphNode.java,v 1.10 2004/07/27 03:18:58 pavlidis Exp $
14 */
15 public class DirectedGraphNode extends AbstractGraphNode implements Comparable {
16
17 protected Set parents;
18
19 protected Set children;
20
21
22 protected int topoSortOrder = 0;
23
24 /***
25 * @param key Object
26 * @param value Object
27 * @param graph Graph
28 */
29 public DirectedGraphNode( Object key, Object value, Graph graph ) {
30 super( key, value, graph );
31 parents = new LinkedHashSet();
32 children = new LinkedHashSet();
33 }
34
35 /***
36 * @param i int
37 */
38 public void setTopoSortOrder( int i ) {
39 topoSortOrder = i;
40 }
41
42 /***
43 * @return int
44 */
45 public int getTopoSortOrder() {
46 return topoSortOrder;
47 }
48
49 /***
50 * @param newChildKey Object
51 */
52 public void addChild( Object newChildKey ) {
53 children.add( newChildKey );
54 }
55
56 /***
57 * @param newParentKey Object
58 */
59 public void addParent( Object newParentKey ) {
60 parents.add( newParentKey );
61 }
62
63 /***
64 * @return Object
65 */
66 public Object getParentKeys() {
67 return parents;
68 }
69
70 /***
71 * @return Object
72 */
73 public Object getChildKeys() {
74 return children;
75 }
76
77 /***
78 * Get the immediate children of this node. References to the DirectedGraphNodes are given, as opposed to key values.
79 *
80 * @return Set containing the child nodes of this node.
81 */
82 public Set getChildNodes() {
83 Set f = new LinkedHashSet();
84 for ( Iterator i = this.getChildIterator(); i.hasNext(); ) {
85 Object k = i.next();
86 f.add( getGraph().get( k ) );
87 }
88 return f;
89 }
90
91 /***
92 * Get the immediate parents of this node. References to the DirectedGraphNodes are given, as opposed to key values.
93 *
94 * @return Set
95 */
96 public Set getParentNodes() {
97 Set f = new LinkedHashSet();
98 for ( Iterator i = this.getParentIterator(); i.hasNext(); ) {
99 Object k = i.next();
100 f.add( getGraph().get( k ) );
101 }
102 return f;
103 }
104
105 /***
106 * Get the subgraph starting from this node, including this node.
107 *
108 * @return Graph
109 */
110 public Graph getChildGraph() {
111 Set k = this.getAllChildNodes();
112 k.add( this );
113
114 DirectedGraph returnVal = new DirectedGraph();
115 for ( Iterator it = k.iterator(); it.hasNext(); ) {
116 DirectedGraphNode m = ( DirectedGraphNode ) it.next();
117 returnVal.addNode( ( DirectedGraphNode ) m.clone() );
118 }
119 returnVal.prune();
120 return returnVal;
121 }
122
123
124
125 /***
126 * @return
127 */
128 public boolean isLeaf() {
129 return children.size() == 0;
130 }
131
132 /***
133 * @return int number of immediate children this node has.
134 */
135 public int outDegree() {
136 return children.size();
137 }
138
139 /***
140 * @return int number of immediate parents this node has.
141 */
142 public int inDegree() {
143 return parents.size();
144 }
145
146 /***
147 * @return int how many children this node has, determined recursively.
148 */
149 public int numChildren() {
150 return getAllChildNodes( null ).size();
151 }
152
153 /***
154 * @return int how many parents this node has, determined recursively.
155 */
156 public int numParents() {
157 return getAllParentNodes( null ).size();
158 }
159
160 /***
161 * Get all the children of this node, recursively.
162 */
163 public Set getAllChildNodes() {
164 return this.getAllChildNodes( null );
165 }
166
167 /***
168 * Get all the parents of this node, recursively.
169 *
170 * @return
171 */
172 public Set getAllParentNodes() {
173 return this.getAllParentNodes( null );
174 }
175
176 /***
177 * Check to see if this node has a particular immediate child.
178 *
179 * @param j Object
180 * @return boolean
181 */
182 public boolean hasChild( Object j ) {
183 return children.contains( j );
184 }
185
186 /***
187 * Check to see if this node has a particular immediate parent.
188 *
189 * @param j Object
190 * @return boolean
191 */
192 public boolean hasParent( Object j ) {
193 return parents.contains( j );
194 }
195
196 public String toString() {
197 return this.getItem().toString();
198 }
199
200 /***
201 * Remove connections that are to nodes not contained in this graph
202 */
203 public void prune() {
204 for ( Iterator it = this.getChildIterator(); it.hasNext(); ) {
205 Object j = it.next();
206 DirectedGraphNode k = ( DirectedGraphNode ) getGraph().get( j );
207 if ( k == null ) {
208 if ( log.isDebugEnabled() ) {
209 log.debug( "Pruned child " + j + " from " + this );
210 }
211 children.remove( j );
212 }
213
214 }
215
216 for ( Iterator it = this.getParentIterator(); it.hasNext(); ) {
217 Object j = it.next();
218 DirectedGraphNode k = ( DirectedGraphNode ) getGraph().get( j );
219 if ( k == null ) {
220 if ( log.isDebugEnabled() ) {
221 log.debug( "Pruned parent " + j + " from " + this );
222 }
223 parents.remove( j );
224 }
225
226 }
227
228 }
229
230 /*** ************* private methods *************** */
231
232 private Set getAllChildNodes( Set list ) {
233 if ( list == null ) {
234 list = new LinkedHashSet();
235 }
236
237 for ( Iterator it = this.getChildIterator(); it.hasNext(); ) {
238 Object j = it.next();
239 list.add( getGraph().get( j ) );
240 ( ( DirectedGraphNode ) getGraph().get( j ) ).getAllChildNodes( list );
241 }
242 return list;
243 }
244
245 private Set getAllParentNodes( Set list ) {
246 if ( list == null ) {
247 list = new LinkedHashSet();
248 }
249
250 for ( Iterator it = this.getParentIterator(); it.hasNext(); ) {
251 Object j = it.next();
252 list.add( getGraph().get( j ) );
253 ( ( DirectedGraphNode ) getGraph().get( j ) ).getAllParentNodes( list );
254 }
255 return list;
256 }
257
258 private Iterator getChildIterator() {
259 return children.iterator();
260 }
261
262 private Iterator getParentIterator() {
263 return parents.iterator();
264 }
265
266 /***
267 * Uses the topological sort order.
268 *
269 * @param o Object
270 * @return int
271 */
272 public int compareTo( Object o ) {
273 DirectedGraphNode k = ( DirectedGraphNode ) o;
274 int ord = k.getTopoSortOrder();
275 if ( ord < this.topoSortOrder ) {
276 return 1;
277 } else if ( ord > this.topoSortOrder ) {
278 return -1;
279 }
280 return 0;
281 }
282
283 /***
284 * Makes a copy of this node. It does not make a deep copy of the contents. This should be used when making
285 * subgraphs.
286 *
287 * @return Object
288 */
289 public Object clone() {
290 DirectedGraphNode r = new DirectedGraphNode( key, item, graph );
291 for ( Iterator it = this.getParentIterator(); it.hasNext(); ) {
292 Object j = it.next();
293 r.addParent( j );
294 }
295
296 for ( Iterator it = this.getChildIterator(); it.hasNext(); ) {
297 Object j = it.next();
298 r.addChild( j );
299 }
300 return r;
301 }
302
303 }