// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea
// Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com
// Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
// Distributed under the terms of the GNU Lesser General Public License (LGPL): http://www.gnu.org/licenses/
package graphtea.library.algorithms.spanningtree;
import graphtea.library.BaseEdge;
import graphtea.library.BaseGraph;
import graphtea.library.BaseVertex;
import graphtea.library.algorithms.Algorithm;
import graphtea.library.algorithms.AutomatedAlgorithm;
import graphtea.library.algorithms.util.EventUtils;
import graphtea.library.event.MessageEvent;
import graphtea.library.event.typedef.BaseGraphRequest;
import graphtea.library.event.typedef.BaseVertexRequest;
import graphtea.library.exceptions.InvalidGraphException;
import graphtea.library.exceptions.InvalidVertexException;
import graphtea.library.genericcloners.BaseEdgeVertexCopier;
import graphtea.library.genericcloners.EdgeVertexCopier;
import graphtea.library.util.Pair;
import java.util.*;
/**
* Implementation of Prim algorithm to find minimum spanning tree.
* The output of this method is a new independent graph representing
* the spanning tree.
*
* @author Omid Aladini
*/
public class Prim<VertexType extends BaseVertex,
EdgeType extends BaseEdge<VertexType>>
extends Algorithm implements AutomatedAlgorithm {
/**
* Temporary reference to the graph the algorithm is going to run on it.
*/
final BaseGraph<VertexType, EdgeType> graph;
/**
* Reference to a GraphConverter object which is responsible for duplication
* of the graph elements, because graph edges and vertices are going to be
* copied to the newly created spanning tree.
*/
private EdgeVertexCopier<VertexType, EdgeType> gc;
/**
* Priority queue implemented as a binary heap to store edges, sorted according
* to their weights.
*/
private PriorityQueue<EdgeType> pq;
/**
* Compares two edges of type EdgeType.
*
* @author Omid
*/
public class DefaultEdgeComparator implements Comparator<EdgeType> {
public int compare(EdgeType o1, EdgeType o2) {
if (o1.getWeight() < o2.getWeight())
return -1;
if (o1.getWeight() == o2.getWeight())
return 0;
else
return 1;
}
}
/**
* Reference to EdgeComparator object needed by the priority queue.
*/
Comparator<EdgeType> ec;
/**
* Constructor of the Prim algorithm.
*
* @param graph Graph the algorithm is going to find it's minimum spanning tree.
* @param gc Reference to a GraphConverter object which is responsible for duplication
* of the graph elements, because graph edges and vertices are going to be
* copied to the newly created spanning tree.
*/
public Prim(BaseGraph<VertexType, EdgeType> graph,
EdgeVertexCopier<VertexType, EdgeType> gc) {
//if (gc == null || graph == null)
// throw new NullPointerException();
this.graph = graph;
this.gc = gc;
this.ec = new DefaultEdgeComparator();
}
/**
* Finds minimum spanning tree starting at vertex v. Note that if
* your graph is not connected, the algorithm falls in an infinite loop
* it's the caller's task to check connectivity.
*
* @param v Start vertex of Prim algorithm.
* @return The spanning tree graph.
* @throws InvalidGraphException if the supplied vertex is invalid.
*/
public Pair<Vector<VertexType>, Vector<EdgeType>>
findMinimumSpanningTree(VertexType v, Comparator<EdgeType> comparator)
throws InvalidGraphException, InvalidVertexException {
if (comparator == null)
throw new NullPointerException("Null comparator supplied to Prim algorithm.");
ec = comparator;
return findMinimumSpanningTree(v);
}
/**
* Finds minimum spanning tree starting at vertex v. Note that if
* your graph is not connected, the algorithm falls in an infinite loop
* it's the caller's task to check connectivity. Default comparator
* which compares weight parameter of the graph is used.
*
* @param v Start vertex of Prim algorithm.
* @return The spanning tree graph.
* @throws InvalidGraphException if the supplied vertex is invalid.
*/
public Pair<Vector<VertexType>, Vector<EdgeType>>
findMinimumSpanningTree(VertexType v)
throws InvalidGraphException, InvalidVertexException {
graph.checkVertex(v);
BaseGraph<VertexType, EdgeType> gCopy = graph.copy(gc);
gCopy = graph;
Vector<VertexType> oVertices = new Vector<>();
Vector<EdgeType> oEdges = new Vector<>();
//dispatchEvent(new GraphEvent<VertexType,EdgeType>(oGraph));
pq = new PriorityQueue<>(1, ec);
{ //lovely block
Iterator<EdgeType> edgeList = gCopy.edgeIterator();
while (edgeList.hasNext())
pq.add(edgeList.next());
}
for (VertexType searchV : gCopy)
if (searchV.getId() == v.getId()) {
oVertices.add(searchV);
searchV.setMark(true);
//dispatchEvent(new VertexEvent<VertexType, EdgeType>(graph, searchV, VertexEvent.EventType.MARK));
}
while (true) {
Pair<EdgeType, VertexType> pev = getNewEdgeForSpanningTree(oVertices, oEdges);
//Pair<EdgeType,VertexType> pev = getNewEdgeForSpanningTree(oGraph);
if (pev == null) {
break;
} else {
pev.second.setMark(true);
//dispatchEvent(new VertexEvent<VertexType, EdgeType>(graph, pev.second, VertexEvent.EventType.MARK));
oVertices.add(pev.second);
oEdges.add(pev.first);
//dispatchEvent(new EdgeEvent<VertexType, EdgeType>(graph, pev.first, EdgeEvent.EventType.MARK));
pev.first.setMark(true);
EventUtils.algorithmStep(this, "");
}
}
return new Pair<>(oVertices, oEdges);
}
private Pair<EdgeType, VertexType>
getNewEdgeForSpanningTree(Vector<VertexType> vertices, Vector<EdgeType> edges) {
ArrayList<EdgeType> tempEdgeArray = new ArrayList<>();
try {
while (true) {
EdgeType edge = pq.poll();
if (edge == null)
return null;
if (!vertices.contains(edge.target) &&
vertices.contains(edge.source))
return new Pair<>(edge, edge.target);
if (!graph.isDirected() &&
vertices.contains(edge.target) &&
!vertices.contains(edge.source))
return new Pair<>(edge, edge.source);
tempEdgeArray.add(edge);
}
} finally {
for (EdgeType e : tempEdgeArray)
pq.add(e);
}
}
public void doAlgorithm() {
BaseGraphRequest gr = new BaseGraphRequest();
dispatchEvent(gr);
BaseGraph<BaseVertex, BaseEdge<BaseVertex>> graph = gr.getGraph();
dispatchEvent(new MessageEvent("Please choose a vertex for the Prim algorithm.", true, 2000));
BaseVertexRequest vr = new BaseVertexRequest(graph);
dispatchEvent(vr);
Prim<BaseVertex, BaseEdge<BaseVertex>> prim = new Prim<>(graph, new BaseEdgeVertexCopier());
prim.acceptEventDispatcher(getDispatcher());
//BaseGraph<BaseVertex,BaseEdge<BaseVertex>> output =
prim.findMinimumSpanningTree(vr.getVertex());
//dispatchEvent(new BaseGraphEvent(output));
}
}