001 // GraphLab Project: http://graphlab.sharif.edu 002 // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology 003 // Distributed under the terms of the GNU Lesser General Public License (LGPL): http://www.gnu.org/licenses/ 004 005 /* 006 * DepthFirstSearch.java 007 * 008 * Created on November 20, 2004, 10:31 PM 009 */ 010 011 package graphlab.library.algorithms.traversal; 012 013 import graphlab.library.BaseEdge; 014 import graphlab.library.BaseGraph; 015 import graphlab.library.BaseVertex; 016 import graphlab.library.algorithms.Algorithm; 017 import graphlab.library.algorithms.AutomatedAlgorithm; 018 import graphlab.library.algorithms.util.EventUtils; 019 import graphlab.library.event.GraphRequest; 020 import graphlab.library.event.PostWorkEvent; 021 import graphlab.library.event.PreWorkEvent; 022 import graphlab.library.event.VertexRequest; 023 import graphlab.library.event.handlers.PreWorkPostWorkHandler; 024 import graphlab.library.exceptions.InvalidGraphException; 025 import graphlab.library.exceptions.InvalidVertexException; 026 027 028 /** 029 * @author Omid Aladini 030 */ 031 public class DepthFirstSearch<VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>> 032 extends Algorithm implements AutomatedAlgorithm { 033 private BaseGraph<VertexType, EdgeType> graph; 034 035 public DepthFirstSearch(BaseGraph<VertexType, EdgeType> graph) { 036 this.graph = graph; 037 } 038 039 public DepthFirstSearch() { 040 this.graph = null; 041 } 042 043 044 /** 045 * Calling this will not reset the marks. 046 * 047 * @param vertex Index of the starting vertex of the traversal. 048 * @param handler A reference to a PreWorkPostWorkHandler that contains implementation 049 * of pre-work and post-work operations that depends on the application of DFS. 050 * @return Whether the traversal has stopped at the middle by the handler. 051 */ 052 public boolean doSearch(VertexType vertex, PreWorkPostWorkHandler<VertexType> handler) { 053 return doSearch(vertex, handler, true); 054 } 055 056 /** 057 * Runs Depth First Search (DFS) algorithm on the graph starting from vertex <I>vertexId</I>. 058 * A reference to a PreWorkPostWorkHandler is supplied that contains implementation 059 * of pre-work and post-work operations that depends on the application of DFS. 060 * 061 * @param vertex Index of the starting vertex of the traversal. 062 * @param handler A reference to a PreWorkPostWorkHandler that contains implementation 063 * of pre-work and post-work operations that depends on the application of DFS. 064 * @param resetMarks If the search should reset vertex visit marks. 065 * @return Whether the traversal has stopped at the middle by the handler. 066 */ 067 public boolean doSearch(VertexType vertex, PreWorkPostWorkHandler<VertexType> handler, boolean resetMarks) 068 throws InvalidVertexException, InvalidGraphException { 069 070 if (graph == null) 071 throw new InvalidGraphException("Graph object is null."); 072 073 if (resetMarks) 074 for (VertexType v : graph) 075 v.setMark(false); 076 077 return depthFirstSearchRecursive(vertex, vertex, handler); 078 } 079 080 private boolean depthFirstSearchRecursive(VertexType vertex, VertexType fromVertex, PreWorkPostWorkHandler<VertexType> handler) 081 throws InvalidVertexException { 082 //TODO:Implementing non-recursive version 083 //int vertexId = vertex.getId(); 084 vertex.setMark(true); 085 if (handler != null) 086 if (handler.doPreWork(fromVertex, vertex)) 087 return true; 088 dispatchEvent(new PreWorkEvent<VertexType, EdgeType>(fromVertex, vertex, graph)); 089 EventUtils.algorithmStep(this, "visit: " + vertex.getId()); 090 VertexType lastInDepthVertex = vertex; 091 092 for (VertexType i : graph) { 093 if (graph.isEdge(vertex, i)) { 094 if (!i.getMark()) { 095 lastInDepthVertex = i; 096 if (depthFirstSearchRecursive(i, vertex, handler)) 097 return true; 098 } 099 } 100 } 101 102 dispatchEvent(new PostWorkEvent<VertexType, EdgeType>(lastInDepthVertex, vertex, graph)); 103 EventUtils.algorithmStep(this, "leave: " + vertex.getId()); 104 105 if (handler != null) 106 if (handler.doPostWork(lastInDepthVertex, vertex)) 107 return true; 108 109 return false; 110 } 111 112 113 public void doAlgorithm() { 114 GraphRequest<VertexType, EdgeType> gr = new GraphRequest<VertexType, EdgeType>(); 115 dispatchEvent(gr); 116 this.graph = gr.getGraph(); 117 VertexRequest<VertexType, EdgeType> vr = new VertexRequest<VertexType, EdgeType>(graph, "Please choose a vertex for the DFS algorithm."); 118 dispatchEvent(vr); 119 this.doSearch(vr.getVertex(), null); 120 } 121 }