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    }