/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.graph.util.graph;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.geotools.graph.structure.Graph;
import org.geotools.graph.structure.Graphable;
import org.geotools.graph.structure.Node;
import org.geotools.graph.structure.basic.BasicGraph;
import org.geotools.graph.traverse.GraphTraversal;
import org.geotools.graph.traverse.GraphWalker;
import org.geotools.graph.traverse.basic.BasicGraphTraversal;
import org.geotools.graph.traverse.standard.DepthFirstIterator;
/**
* Creates a collection of connected graphs from a single graph. A
* connected graph in which for every two pair of nodes, there is a path between
* them.
*
* @author Justin Deoliveira, Refractions Research Inc, jdeolive@refractions.net
*
* @source $URL$
*/
public class GraphPartitioner implements GraphWalker {
/** graph to be partitioned into connected components **/
private Graph m_graph;
/** paritions of graph **/
private ArrayList m_partitions;
/** current partition **/
private ArrayList m_partition;
/** visited counter **/
private int m_nvisited;
/**
* Constructs a new partitioner for a graph.
*
* @param graph Graph to be partitioned.
*/
public GraphPartitioner(Graph graph) {
m_graph = graph;
m_partitions = new ArrayList();
}
/**
* Performs the partition.
*
* @return True if the partition was successful, otherwise false.
*/
public boolean partition() {
//strategy is to perform a depth first search from a node, every node is
// reaches is connected therefore in the same partition
// when traversal ends, start from a new source, repeat until no more
// sources
try {
m_nvisited = m_graph.getNodes().size();
DepthFirstIterator iterator = new DepthFirstIterator();
BasicGraphTraversal traversal = new BasicGraphTraversal(
m_graph, this, iterator
);
Iterator sources = m_graph.getNodes().iterator();
traversal.init();
m_partition = new ArrayList();
while(m_nvisited > 0) {
//find a node that hasn't been visited and set as source of traversal
Node source = null;
while(sources.hasNext() && (source = (Node)sources.next()).isVisited());
//if we could not find a source, return false
if (source == null || source.isVisited()) return(false);
iterator.setSource(source);
traversal.traverse();
}
//create the individual graphs
HashSet nodes = null;
HashSet edges = null;
ArrayList graphs = new ArrayList();
for (Iterator itr = m_partitions.iterator(); itr.hasNext();) {
m_partition = (ArrayList)itr.next();
if (m_partition.size() == 0) continue;
nodes = new HashSet();
edges = new HashSet();
for (Iterator nitr = m_partition.iterator(); nitr.hasNext();) {
Node node = (Node)nitr.next();
nodes.add(node);
edges.addAll(node.getEdges());
}
graphs.add(new BasicGraph(nodes, edges));
}
m_partitions = graphs;
return(true);
}
catch(Exception e) {
e.printStackTrace();
}
return(false);
}
/**
* Returns the partitions of the graph.
*
* @return A collection of Graph objects.
*
* @see Graph
*/
public List getPartitions() {
return(m_partitions);
}
/**
* Adds the element to the current partition.
*
* @see GraphWalker#visit(Graphable, GraphTraversal)
*/
public int visit(Graphable element, GraphTraversal traversal) {
//add element to current set
m_nvisited--;
m_partition.add(element);
return(GraphTraversal.CONTINUE);
}
/**
* Adds the current partition to the completed set of partitions and
* creates a new partition.
*
* @see GraphWalker#finish()
*/
public void finish() {
//create a new set
m_partitions.add(m_partition);
m_partition = new ArrayList();
}
}