1 19 20 package edu.umd.cs.findbugs.graph; 21 22 import java.util.ArrayList ; 23 import java.util.Iterator ; 24 import java.util.LinkedList ; 25 26 import edu.umd.cs.findbugs.annotations.SuppressWarnings; 27 28 47 public abstract class AbstractDepthFirstSearch 48 < 49 GraphType extends Graph<EdgeType, VertexType>, 50 EdgeType extends GraphEdge<EdgeType, VertexType>, 51 VertexType extends GraphVertex<VertexType> 52 > 53 implements DFSEdgeTypes { 54 55 public final static boolean DEBUG = false; 56 57 private GraphType graph; 58 private int[] colorList; 59 private int[] discoveryTimeList; 60 private int[] finishTimeList; 61 private int[] dfsEdgeTypeList; 62 private int timestamp; 63 private LinkedList <VertexType> topologicalSortList; 64 private VertexChooser<VertexType> vertexChooser; 65 private SearchTreeCallback<VertexType> searchTreeCallback; 66 67 70 protected static final int WHITE = 0; 71 72 76 protected static final int GRAY = 1; 77 78 82 protected static final int BLACK = 2; 83 84 90 public AbstractDepthFirstSearch(GraphType graph) { 91 this.graph = graph; 92 93 int numBlocks = graph.getNumVertexLabels(); 94 colorList = new int[numBlocks]; discoveryTimeList = new int[numBlocks]; 96 finishTimeList = new int[numBlocks]; 97 98 int maxEdgeId = graph.getNumEdgeLabels(); 99 dfsEdgeTypeList = new int[maxEdgeId]; 100 101 timestamp = 0; 102 103 topologicalSortList = new LinkedList <VertexType>(); 104 } 105 106 110 113 protected abstract Iterator <EdgeType> outgoingEdgeIterator(GraphType graph, VertexType vertex); 114 115 118 protected abstract VertexType getTarget(EdgeType edge); 119 120 123 protected abstract VertexType getSource(EdgeType edge); 124 125 133 protected VertexType getNextSearchTreeRoot() { 134 for (Iterator <VertexType> i = graph.vertexIterator(); i.hasNext(); ) { 136 VertexType vertex = i.next(); 137 if (visitMe(vertex)) 138 return vertex; 139 } 140 return null; 141 } 142 143 151 public void setVertexChooser(VertexChooser<VertexType> vertexChooser) { 152 this.vertexChooser = vertexChooser; 153 } 154 155 160 public void setSearchTreeCallback(SearchTreeCallback<VertexType> searchTreeCallback) { 161 this.searchTreeCallback = searchTreeCallback; 162 } 163 164 169 public AbstractDepthFirstSearch<GraphType, EdgeType, VertexType> search() { 170 visitAll(); 171 classifyUnknownEdges(); 172 173 return this; 174 } 175 176 184 public boolean containsCycle() { 185 for (Iterator <EdgeType> i = graph.edgeIterator(); i.hasNext(); ) { 186 EdgeType edge = i.next(); 187 if (getDFSEdgeType(edge) == BACK_EDGE) 188 return true; 189 } 190 return false; 191 } 192 193 200 public int getDFSEdgeType(EdgeType edge) { 201 return dfsEdgeTypeList[edge.getLabel()]; 202 } 203 204 210 public int getDiscoveryTime(VertexType vertex) { 211 return discoveryTimeList[vertex.getLabel()]; 212 } 213 214 220 public int getFinishTime(VertexType vertex) { 221 return finishTimeList[vertex.getLabel()]; 222 } 223 224 229 @SuppressWarnings ("EI") 230 public int[] getFinishTimeList() { 231 return finishTimeList; 232 } 233 234 238 public Iterator <VertexType> topologicalSortIterator() { 239 return topologicalSortList.iterator(); 240 } 241 242 private class Visit { 243 private VertexType vertex; 244 private Iterator <EdgeType> outgoingEdgeIterator; 245 246 public Visit(VertexType vertex) { 247 if (vertex == null) throw new IllegalStateException (); 248 this.vertex = vertex; 249 this.outgoingEdgeIterator = outgoingEdgeIterator(graph, vertex); 250 251 setColor(vertex, GRAY); 253 setDiscoveryTime(vertex, timestamp++); 254 } 255 256 public VertexType getVertex() { 257 return vertex; 258 } 259 260 public boolean hasNextEdge() { 261 return outgoingEdgeIterator.hasNext(); 262 } 263 264 public EdgeType getNextEdge() { 265 return outgoingEdgeIterator.next(); 266 } 267 } 268 269 private void visitAll() { 270 for (;;) { 271 VertexType searchTreeRoot = getNextSearchTreeRoot(); 272 if (searchTreeRoot == null) 273 break; 275 276 if (searchTreeCallback != null) 277 searchTreeCallback.startSearchTree(searchTreeRoot); 278 279 ArrayList <Visit> stack = new ArrayList <Visit>(graph.getNumVertexLabels()); 280 stack.add(new Visit(searchTreeRoot)); 281 282 while (!stack.isEmpty()) { 283 Visit visit = stack.get(stack.size() - 1); 284 285 if (visit.hasNextEdge()) { 286 EdgeType edge = visit.getNextEdge(); 288 visitSuccessor(stack, edge); 289 } else { 290 VertexType vertex = visit.getVertex(); 292 setColor(vertex, BLACK); 293 topologicalSortList.addFirst(vertex); 294 setFinishTime(vertex, timestamp++); 295 296 stack.remove(stack.size() - 1); 297 } 298 } 299 } 300 } 301 302 private void visitSuccessor(ArrayList <Visit> stack, EdgeType edge) { 303 VertexType succ = getTarget(edge); 305 int succColor = getColor(succ); 306 307 int dfsEdgeType = 0; 309 switch (succColor) { 310 case WHITE: 311 dfsEdgeType = TREE_EDGE; 312 break; 313 case GRAY: 314 dfsEdgeType = BACK_EDGE; 315 break; 316 case BLACK: 317 dfsEdgeType = UNKNOWN_EDGE; 318 break; default: 320 assert false; 321 } 322 setDFSEdgeType(edge, dfsEdgeType); 323 324 if (visitMe(succ)) { 326 if (searchTreeCallback != null) 328 searchTreeCallback.addToSearchTree(getSource(edge), getTarget(edge)); 329 330 stack.add(new Visit(succ)); 332 } 333 } 334 335 private void classifyUnknownEdges() { 337 Iterator <EdgeType> edgeIter = graph.edgeIterator(); 338 while (edgeIter.hasNext()) { 339 EdgeType edge = edgeIter.next(); 340 int dfsEdgeType = getDFSEdgeType(edge); 341 if (dfsEdgeType == UNKNOWN_EDGE) { 342 int srcDiscoveryTime = getDiscoveryTime(getSource(edge)); 343 int destDiscoveryTime = getDiscoveryTime(getTarget(edge)); 344 345 if (srcDiscoveryTime < destDiscoveryTime) { 346 dfsEdgeType = FORWARD_EDGE; 349 } else { 350 dfsEdgeType = CROSS_EDGE; 353 } 354 355 setDFSEdgeType(edge, dfsEdgeType); 356 } 357 } 358 } 359 360 private void setColor(VertexType vertex, int color) { 361 colorList[vertex.getLabel()] = color; 362 } 363 364 370 protected int getColor(VertexType vertex) { 371 return colorList[vertex.getLabel()]; 372 } 373 374 382 protected boolean visitMe(VertexType vertex) { 383 return (getColor(vertex) == WHITE) 384 && (vertexChooser == null || vertexChooser.isChosen(vertex)); 385 } 386 387 private void setDiscoveryTime(VertexType vertex, int ts) { 388 discoveryTimeList[vertex.getLabel()] = ts; 389 } 390 391 private void setFinishTime(VertexType vertex, int ts) { 392 finishTimeList[vertex.getLabel()] = ts; 393 } 394 395 private void setDFSEdgeType(EdgeType edge, int dfsEdgeType) { 396 dfsEdgeTypeList[edge.getLabel()] = dfsEdgeType; 397 } 398 } 399 400 | Popular Tags |