org.jgrapht.alg.cycle.PatonCycleBase Maven / Gradle / Ivy
/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2008, by Barak Naveh and Contributors.
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
/* -------------------------
* PatonCycleBase.java
* -------------------------
* (C) Copyright 2013, by Nikolay Ognyanov
*
* Original Author: Nikolay Ognyanov
* Contributor(s) :
*
* $Id$
*
* Changes
* -------
* 06-Sep-2013 : Initial revision (NO);
*/
package org.jgrapht.alg.cycle;
import java.util.*;
import org.jgrapht.*;
/**
* Find a cycle base of an undirected graph using the Paton's algorithm.
*
* See:
* K. Paton, An algorithm for finding a fundamental set of cycles for an
* undirected linear graph, Comm. ACM 12 (1969), pp. 514-518.
*
* @param the vertex type.
* @param the edge type.
*
* @author Nikolay Ognyanov
*/
public class PatonCycleBase
implements UndirectedCycleBase
{
private UndirectedGraph graph;
/**
* Create a cycle base finder with an unspecified graph.
*/
public PatonCycleBase()
{
}
/**
* Create a cycle base finder for the specified graph.
*
* @param graph - the DirectedGraph in which to find cycles.
*
* @throws IllegalArgumentException if the graph argument is
* null
.
*/
public PatonCycleBase(UndirectedGraph graph)
{
if (graph == null) {
throw new IllegalArgumentException("Null graph argument.");
}
this.graph = graph;
}
/**
* {@inheritDoc}
*/
@Override public UndirectedGraph getGraph()
{
return graph;
}
/**
* {@inheritDoc}
*/
@Override public void setGraph(UndirectedGraph graph)
{
if (graph == null) {
throw new IllegalArgumentException("Null graph argument.");
}
this.graph = graph;
}
/**
* {@inheritDoc}
*/
@Override public List> findCycleBase()
{
if (graph == null) {
throw new IllegalArgumentException("Null graph.");
}
Map> used = new HashMap>();
Map parent = new HashMap();
ArrayDeque stack = new ArrayDeque();
List> cycles = new ArrayList>();
for (V root : graph.vertexSet()) {
// Loop over the connected
// components of the graph.
if (parent.containsKey(root)) {
continue;
}
// Free some memory in case of
// multiple connected components.
used.clear();
// Prepare to walk the spanning tree.
parent.put(root, root);
used.put(root, new HashSet());
stack.push(root);
// Do the walk. It is a BFS with
// a LIFO instead of the usual
// FIFO. Thus it is easier to
// find the cycles in the tree.
while (!stack.isEmpty()) {
V current = stack.pop();
Set currentUsed = used.get(current);
for (E e : graph.edgesOf(current)) {
V neighbor = graph.getEdgeTarget(e);
if (neighbor.equals(current)) {
neighbor = graph.getEdgeSource(e);
}
if (!used.containsKey(neighbor)) {
// found a new node
parent.put(neighbor, current);
Set neighbourUsed = new HashSet();
neighbourUsed.add(current);
used.put(neighbor, neighbourUsed);
stack.push(neighbor);
} else if (neighbor.equals(current)) {
// found a self loop
List cycle = new ArrayList();
cycle.add(current);
cycles.add(cycle);
} else if (!currentUsed.contains(neighbor)) {
// found a cycle
Set neighbourUsed = used.get(neighbor);
List cycle = new ArrayList();
cycle.add(neighbor);
cycle.add(current);
V p = parent.get(current);
while (!neighbourUsed.contains(p)) {
cycle.add(p);
p = parent.get(p);
}
cycle.add(p);
cycles.add(cycle);
neighbourUsed.add(current);
}
}
}
}
return cycles;
}
}
// End PatonCycleBase.java