package edu.uci.ics.jung.algorithms.shortestpath;
import java.util.Collection;
import java.util.Set;
import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.functors.ConstantTransformer;
import edu.uci.ics.jung.algorithms.cluster.WeakComponentClusterer;
import edu.uci.ics.jung.algorithms.filters.FilterUtils;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Tree;
import edu.uci.ics.jung.graph.util.TreeUtils;
/**
* For the input Graph, creates a MinimumSpanningTree
* using a variation of Prim's algorithm.
*
* @author Tom Nelson - tomnelson@dev.java.net
*
* @param <V>
* @param <E>
*/
@SuppressWarnings("unchecked")
public class MinimumSpanningForest2<V,E> {
protected Graph<V,E> graph;
protected Forest<V,E> forest;
protected Transformer<E,Double> weights =
(Transformer<E,Double>)new ConstantTransformer<Double>(1.0);
/**
* create a Forest from the supplied Graph and supplied Factory, which
* is used to create a new, empty Forest. If non-null, the supplied root
* will be used as the root of the tree/forest. If the supplied root is
* null, or not present in the Graph, then an arbitary Graph vertex
* will be selected as the root.
* If the Minimum Spanning Tree does not include all vertices of the
* Graph, then a leftover vertex is selected as a root, and another
* tree is created
* @param graph
* @param factory
* @param weights
*/
public MinimumSpanningForest2(Graph<V, E> graph,
Factory<Forest<V,E>> factory,
Factory<? extends Graph<V,E>> treeFactory,
Transformer<E, Double> weights) {
this(graph, factory.create(),
treeFactory,
weights);
}
/**
* create a forest from the supplied graph, populating the
* supplied Forest, which must be empty.
* If the supplied root is null, or not present in the Graph,
* then an arbitary Graph vertex will be selected as the root.
* If the Minimum Spanning Tree does not include all vertices of the
* Graph, then a leftover vertex is selected as a root, and another
* tree is created
* @param graph the Graph to find MST in
* @param forest the Forest to populate. Must be empty
* @param weights edge weights, may be null
*/
public MinimumSpanningForest2(Graph<V, E> graph,
Forest<V,E> forest,
Factory<? extends Graph<V,E>> treeFactory,
Transformer<E, Double> weights) {
if(forest.getVertexCount() != 0) {
throw new IllegalArgumentException("Supplied Forest must be empty");
}
this.graph = graph;
this.forest = forest;
if(weights != null) {
this.weights = weights;
}
WeakComponentClusterer<V,E> wcc =
new WeakComponentClusterer<V,E>();
Set<Set<V>> component_vertices = wcc.transform(graph);
Collection<Graph<V,E>> components =
FilterUtils.createAllInducedSubgraphs(component_vertices, graph);
for(Graph<V,E> component : components) {
PrimMinimumSpanningTree<V,E> mst =
new PrimMinimumSpanningTree<V,E>(treeFactory, this.weights);
Graph<V,E> subTree = mst.transform(component);
if(subTree instanceof Tree) {
TreeUtils.addSubTree(forest, (Tree<V,E>)subTree, null, null);
}
}
}
/**
* Returns the generated forest.
*/
public Forest<V,E> getForest() {
return forest;
}
}