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 }