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.spanningtree;
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.util.EventUtils;
013    import graphlab.library.event.MessageEvent;
014    import graphlab.library.event.typedef.BaseGraphRequest;
015    import graphlab.library.event.typedef.BaseVertexRequest;
016    import graphlab.library.exceptions.InvalidGraphException;
017    import graphlab.library.exceptions.InvalidVertexException;
018    import graphlab.library.genericcloners.BaseEdgeVertexCopier;
019    import graphlab.library.genericcloners.EdgeVertexCopier;
020    import graphlab.library.util.Pair;
021    
022    import java.util.*;
023    
024    
025    /**
026     * Implementation of Prim algorithm to find minimum spanning tree.
027     * The output of this method is a new independent graph representing
028     * the spanning tree.
029     *
030     * @author Omid Aladini
031     */
032    public class Prim<VertexType extends BaseVertex,
033            EdgeType extends BaseEdge<VertexType>>
034            extends Algorithm implements AutomatedAlgorithm {
035        /**
036         * Temporary reference to the graph the algorithm is going to run on it.
037         */
038        final BaseGraph<VertexType, EdgeType> graph;
039        /**
040         * Reference to a GraphConverter object which is responsible for duplication
041         * of the graph elements, because graph edges and vertices are going to be
042         * copied to the newly created spanning tree.
043         */
044        private EdgeVertexCopier<VertexType, EdgeType> gc;
045        /**
046         * Priority queue implemented as a binary heap to store edges, sorted according
047         * to their weights.
048         */
049        private PriorityQueue<EdgeType> pq;
050    
051        /**
052         * Compares two edges of type EdgeType.
053         *
054         * @author Omid
055         */
056        public class DefaultEdgeComparator implements Comparator<EdgeType> {
057            public int compare(EdgeType o1, EdgeType o2) {
058                if (o1.getWeight() < o2.getWeight())
059                    return -1;
060                if (o1.getWeight() == o2.getWeight())
061                    return 0;
062                else
063                    return 1;
064            }
065        }
066    
067        /**
068         * Reference to EdgeComparator object needed by the priority queue.
069         */
070        Comparator<EdgeType> ec;
071    
072        /**
073         * Constructor of the Prim algorithm.
074         *
075         * @param graph Graph the algorithm is going to find it's minimum spanning tree.
076         * @param gc    Reference to a GraphConverter object which is responsible for duplication
077         *              of the graph elements, because graph edges and vertices are going to be
078         *              copied to the newly created spanning tree.
079         */
080        public Prim(BaseGraph<VertexType, EdgeType> graph,
081                    EdgeVertexCopier<VertexType, EdgeType> gc) {
082            //if (gc == null || graph == null)
083            //      throw new NullPointerException();
084    
085            this.graph = graph;
086            this.gc = gc;
087            this.ec = new DefaultEdgeComparator();
088        }
089    
090        /**
091         * Finds minimum spanning tree starting at vertex v. Note that if
092         * your graph is not connected, the algorithm falls in an infinite loop
093         * it's the caller's task to check connectivity.
094         *
095         * @param v Start vertex of Prim algorithm.
096         * @return The spanning tree graph.
097         * @throws InvalidGraphException if the supplied vertex is invalid.
098         */
099        public Pair<Vector<VertexType>, Vector<EdgeType>>
100        findMinimumSpanningTree(VertexType v, Comparator<EdgeType> comparator)
101                throws InvalidGraphException, InvalidVertexException {
102            if (comparator == null)
103                throw new NullPointerException("Null comparator supplied to Prim algorithm.");
104            ec = comparator;
105            return findMinimumSpanningTree(v);
106    
107        }
108    
109        /**
110         * Finds minimum spanning tree starting at vertex v. Note that if
111         * your graph is not connected, the algorithm falls in an infinite loop
112         * it's the caller's task to check connectivity. Default comparator
113         * which compares weight parameter of the graph is used.
114         *
115         * @param v Start vertex of Prim algorithm.
116         * @return The spanning tree graph.
117         * @throws InvalidGraphException if the supplied vertex is invalid.
118         */
119        public Pair<Vector<VertexType>, Vector<EdgeType>>
120        findMinimumSpanningTree(VertexType v)
121                throws InvalidGraphException, InvalidVertexException {
122            graph.checkVertex(v);
123            BaseGraph<VertexType, EdgeType> gCopy = graph.copy(gc);
124            gCopy = graph;
125    
126            Vector<VertexType> oVertices = new Vector<VertexType>();
127            Vector<EdgeType> oEdges = new Vector<EdgeType>();
128    
129            //dispatchEvent(new GraphEvent<VertexType,EdgeType>(oGraph));
130    
131            pq = new PriorityQueue<EdgeType>(1, ec);
132    
133            {    //lovely block
134                Iterator<EdgeType> edgeList = gCopy.edgeIterator();
135    
136                while (edgeList.hasNext())
137                    pq.add(edgeList.next());
138            }
139    
140            for (VertexType searchV : gCopy)
141                if (searchV.getId() == v.getId()) {
142                    oVertices.add(searchV);
143                    searchV.setMark(true);
144                    //dispatchEvent(new VertexEvent<VertexType, EdgeType>(graph, searchV, VertexEvent.EventType.MARK));
145                }
146    
147            while (true) {
148                Pair<EdgeType, VertexType> pev = getNewEdgeForSpanningTree(oVertices, oEdges);
149                //Pair<EdgeType,VertexType> pev = getNewEdgeForSpanningTree(oGraph);
150    
151                if (pev == null) {
152                    break;
153                } else {
154                    pev.second.setMark(true);
155                    //dispatchEvent(new VertexEvent<VertexType, EdgeType>(graph, pev.second, VertexEvent.EventType.MARK));
156                    oVertices.add(pev.second);
157                    oEdges.add(pev.first);
158                    //dispatchEvent(new EdgeEvent<VertexType, EdgeType>(graph, pev.first, EdgeEvent.EventType.MARK));
159                    pev.first.setMark(true);
160                    EventUtils.algorithmStep(this, "");
161                }
162            }
163    
164            return new Pair<Vector<VertexType>, Vector<EdgeType>>(oVertices, oEdges);
165        }
166    
167    
168        private Pair<EdgeType, VertexType>
169        getNewEdgeForSpanningTree(Vector<VertexType> vertices, Vector<EdgeType> edges) {
170            ArrayList<EdgeType> tempEdgeArray = new ArrayList<EdgeType>();
171    
172            try {
173                while (true) {
174                    EdgeType edge = pq.poll();
175                    if (edge == null)
176                        return null;
177    
178                    if (!vertices.contains(edge.target) &&
179                            vertices.contains(edge.source))
180                        return new Pair<EdgeType, VertexType>(edge, edge.target);
181    
182                    if (!graph.isDirected() &&
183                            vertices.contains(edge.target) &&
184                            !vertices.contains(edge.source))
185                        return new Pair<EdgeType, VertexType>(edge, edge.source);
186    
187                    tempEdgeArray.add(edge);
188    
189                }
190            } finally {
191                for (EdgeType e : tempEdgeArray)
192                    pq.add(e);
193            }
194        }
195    
196        public void doAlgorithm() {
197            BaseGraphRequest gr = new BaseGraphRequest();
198            dispatchEvent(gr);
199            BaseGraph<BaseVertex, BaseEdge<BaseVertex>> graph = gr.getGraph();
200    
201            dispatchEvent(new MessageEvent("Please choose a vertex for the Prim algorithm.", true, 2000));
202    
203            BaseVertexRequest vr = new BaseVertexRequest(graph);
204            dispatchEvent(vr);
205    
206            Prim<BaseVertex, BaseEdge<BaseVertex>> prim = new Prim<BaseVertex, BaseEdge<BaseVertex>>(graph, new BaseEdgeVertexCopier());
207            prim.acceptEventDispatcher(getDispatcher());
208    
209            //BaseGraph<BaseVertex,BaseEdge<BaseVertex>> output =
210            prim.findMinimumSpanningTree(vr.getVertex());
211    
212            //dispatchEvent(new BaseGraphEvent(output));
213        }
214    }