//create walker for first stage
// if the walker sees a node of degree 2 it adds it to the current
// set of nodes, else it starts a new set
m_walker = new GraphWalker() {
public int visit(Graphable element, GraphTraversal traversal) {
Node node = (Node)element;
//if the node is not of degree 2, start a new set
if (node.getDegree() != 2) {
finish();
}
else {
//add node to current set
m_nodes.add(node);
m_ndegree2--;
}
return(GraphTraversal.CONTINUE);
}
public void finish() {
//no need to recreate if empty
if (!m_nodes.isEmpty()) {
m_sets.add(m_nodes);
m_nodes = new ArrayList();
}
}
};
//perform a topological depth first traversal
m_traversal = new BasicGraphTraversal(
m_graph, m_walker, new DepthFirstTopologicalIterator()
);
//initialise set and node collections
m_sets = new ArrayList();
m_nodes = new ArrayList();
m_ndegree2 = m_graph.getNodesOfDegree(2).size();
if (m_ndegree2 == 0) return(true); // nothing to fuse
m_traversal.init();
//reset edge visited flags
m_graph.visitNodes(
new GraphVisitor() {
public int visit(Graphable component) {
component.setVisited(false);
return 0;
}
}
);
//perform the traversal
m_traversal.traverse();
//if all nodes of degree 2 have been visited, we are finished
if (m_ndegree2 > 0) {
//if there are still nodes of degree 2 that havent been visited, it means
// that the graph has a cycle and that the remaining degree 2 nodes are
// internal to the cycle, so the strategy for the second stage is to
// find all unvisited nodes of degree 2 that are not visited and start
// a no bifurcation traversal from them
Iterator sources = m_graph.queryNodes(
new GraphVisitor() {
public int visit(Graphable component) {
Node node = (Node)component;
if (!node.isVisited() && node.getDegree() == 2) {
//check for adjacent node of degree > 2
for (Iterator itr = node.getRelated(); itr.hasNext(); ) {
Node rel = (Node)itr.next();
if (rel.getDegree() > 2) return(Graph.PASS_AND_CONTINUE);
}
}
return(Graph.FAIL_QUERY);
}
}
).iterator();
//if the query returned no nodes, it means that all the cycle is
// disconnected from the rest of graph, so just pick any node of degree 2
if (!sources.hasNext()) {
sources = m_graph.queryNodes(
new GraphVisitor() {
public int visit(Graphable component) {
if (!component.isVisited()) return(Graph.PASS_AND_STOP);
return(Graph.FAIL_QUERY);
}
}
).iterator();
}
//create stage 2 walker, simple add any nodes visited nodes to the
// current node set
m_walker = new GraphWalker() {
public int visit(Graphable element, GraphTraversal traversal) {
m_ndegree2--;
m_nodes.add(element);
return(GraphTraversal.CONTINUE);
}
public void finish() {
m_sets.add(m_nodes);
m_nodes = new ArrayList();
}
};
m_traversal.setWalker(m_walker);
m_traversal.setIterator(new NoBifurcationIterator());
//clear current node list
m_nodes = new ArrayList();
Node source = null;
while(sources.hasNext()) {
while(sources.hasNext()) {
source = (Node)sources.next();
if (source.isVisited()) continue;
((SourceGraphIterator)m_traversal.getIterator()).setSource(source);
m_traversal.traverse();
}
}
}
// should be zero, if not something wierd not accounted for
if(m_ndegree2 == 0) {
//build the fused graph
for(Iterator sitr = m_sets.iterator(); sitr.hasNext();) {
ArrayList nodes = (ArrayList)sitr.next();
ArrayList edges = new ArrayList();
Node first = null; //node of degree != 2 adjacent to first node in set
Node last = null; //node of degree != 2 adjacent to last node in set
if (nodes.size() == 1) {
//set first and last to be related nodes
Iterator related = ((Node)nodes.get(0)).getRelated();
first = (Node)related.next();
last = (Node)related.next();
edges.addAll(((Node)nodes.get(0)).getEdges());
}
else {
//get the node of degree != 2 adjacent to first node in set
Node node = (Node)nodes.get(0);
Iterator rel = node.getRelated();
first = (Node)rel.next();
if (first.equals(nodes.get(1))) first = (Node)rel.next();
//get the node of degree != 2 adjacent to last node in set
node = (Node)nodes.get(nodes.size()-1);
rel = node.getRelated();
last = (Node)rel.next();
if (last.equals(nodes.get(nodes.size()-2))) last = (Node)rel.next();
//check to see that the first node is not of degree 2, if it is we
// have a set of nodes that forms a cycle with no bifurcations
// set first to point to node at index 1, and last index x, also
// remove node at index 0 from node set so it doesn't get removed
if (first.getDegree() == 2) {
first = (Node)nodes.get(1);
last = (Node)nodes.get(0);
first = last = (Node)nodes.get(0);
//remove first node from list so that it doesn't get deleted
nodes.remove(0);
}
//add edge between first node in set, and the node of degree != 2
// that is adjacent to it
edges.add(first.getEdge((Node)nodes.get(0)));
//add middle edges
for (int i = 1; i < nodes.size(); i++) {
Node curr = (Node)nodes.get(i);
Node prev = (Node)nodes.get(i-1);
edges.add(curr.getEdge(prev));
}
//add edge between last node in set, and the node of degree != 2
// that is adjacent to it