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    package graphlab.library.algorithms.util;
006    
007    import graphlab.library.BaseEdge;
008    import graphlab.library.BaseGraph;
009    import graphlab.library.BaseVertex;
010    import graphlab.library.algorithms.Algorithm;
011    import graphlab.library.algorithms.AutomatedAlgorithm;
012    import graphlab.library.algorithms.traversal.DepthFirstSearch;
013    import graphlab.library.event.MessageEvent;
014    import graphlab.library.event.handlers.PreWorkPostWorkHandler;
015    import graphlab.library.event.typedef.BaseGraphRequest;
016    import graphlab.library.exceptions.InvalidGraphException;
017    
018    /**
019     * Checks whether a graph is acyclic.
020     * Usage:
021     * <p/>
022     * graphlab.library.algorithms.util.AcyclicChecker.isGraphAcyclic(graph);
023     * <p/>
024     * The above statement returns true if the graph is acyclic. The graph
025     * parameter is your graph object. Note that there is no need to explicitly
026     * parameterize the generic method isGraphAcyclic. Types are automatically
027     * deduced from the supplied graph object with no java unchecked convertion warning.
028     *
029     * @author Omid Aladini
030     */
031    public class AcyclicChecker extends Algorithm implements AutomatedAlgorithm {
032        /**
033         * Checks whether the current graph is acyclic.
034         *
035         * @return True if graph is acyclic and false otherwise.
036         * @throws InvalidGraphException
037         */
038        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
039        boolean isGraphAcyclic(BaseGraph<VertexType, EdgeType> graph) {
040            if (!graph.isDirected()) {
041                int n = graph.getVerticesCount();
042                int m = graph.getEdgesCount();
043                int components = 0;
044    
045                if (m >= n)
046                    return false;
047    
048                for (VertexType v : graph) {
049                    if (v.getMark())
050                        continue;
051    
052                    ++components;
053    
054                    new DepthFirstSearch<VertexType, EdgeType>(graph)
055                            .doSearch(v, new AcyclicCheckerHandler<VertexType, EdgeType>(graph), false);
056                }
057    
058                return (n == m + components);
059            } else {
060                return true;
061    
062    
063            }
064        }
065    
066        /**
067         * Prework-PostWork Handler for checking whether the graph is acyclic.
068         *
069         * @author Omid Aladini
070         * @param <VertexType> Graph's vertices type.
071         * @param <EdgeType>   Graph's edges type.
072         */
073        private static class AcyclicCheckerHandler<VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
074                implements PreWorkPostWorkHandler<VertexType> {
075            BaseGraph<VertexType, EdgeType> graph;
076    
077            public AcyclicCheckerHandler(BaseGraph<VertexType, EdgeType> graph) {
078                this.graph = graph;
079            }
080    
081            public boolean doPreWork(VertexType fromVertex, VertexType toVertex) {
082                toVertex.setMark(true);
083                return false;
084            }
085    
086            public boolean doPostWork(VertexType returnFrom, VertexType returnTo) {
087                return false;
088            }
089        }
090    
091        public void doAlgorithm() {
092            BaseGraphRequest gr = new BaseGraphRequest();
093            dispatchEvent(gr);
094            BaseGraph<BaseVertex, BaseEdge<BaseVertex>> graph = gr.getGraph();
095    
096            if (isGraphAcyclic(graph)) {
097                dispatchEvent(new MessageEvent("Graph is acyclic."));
098            } else
099                dispatchEvent(new MessageEvent("Graph is NOT acyclic."));
100    
101        }
102    
103    }