Skip to content

Commit

Permalink
Refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolayo committed Sep 6, 2013
1 parent 63c4d3d commit b229217
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 57 deletions.
10 changes: 5 additions & 5 deletions src/main/java/net/ognyanov/niographs/JohnsonSimpleCycles.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
=============================================================================*/
package net.ognyanov.niographs;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.jgrapht.DirectedGraph;
import org.jgrapht.graph.ClassBasedEdgeFactory;
Expand Down Expand Up @@ -56,14 +56,14 @@ public class JohnsonSimpleCycles<V, E>
private Map<V, Integer> vToI = null;
private Set<V> blocked = null;
private Map<V, Set<V>> bSets = null;
private Stack<V> stack = null;
private ArrayDeque<V> stack = null;

// The state of the embedded Tarjan SCC algorithm.
private List<Set<V>> SCCs = null;
private int index = 0;
private Map<V, Integer> vIndex = null;
private Map<V, Integer> vLowlink = null;
private Stack<V> path = null;
private ArrayDeque<V> path = null;
private Set<V> pathSet = null;

/**
Expand Down Expand Up @@ -346,7 +346,7 @@ private void initState()
vToI = new HashMap<V, Integer>();
blocked = new HashSet<V>();
bSets = new HashMap<V, Set<V>>();
stack = new Stack<V>();
stack = new ArrayDeque<V>();

for (int i = 0; i < iToV.length; i++) {
vToI.put(iToV[i], i);
Expand All @@ -369,7 +369,7 @@ private void initMinSCGState()
SCCs = new ArrayList<Set<V>>();
vIndex = new HashMap<V, Integer>();
vLowlink = new HashMap<V, Integer>();
path = new Stack<V>();
path = new ArrayDeque<V>();
pathSet = new HashSet<V>();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@
=============================================================================*/
package net.ognyanov.niographs;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.jgrapht.UndirectedGraph;

/**
* Find a cycle basis of an undirected graph using the Paton's
* Find a cycle base of an undirected graph using the Paton's
* algorithm.
* <p/>
* See:<br/>
Expand All @@ -40,26 +40,26 @@
* @param <V> - the vertex type.
* @param <E> - the edge type.
*/
public class PatonSimpleCycles<V, E>
implements UndirectedSimpleCycles<V, E>
public class PatonCycleBase<V, E>
implements UndirectedCycleBase<V, E>
{
private UndirectedGraph<V, E> graph;

/**
* Create a cycle basis finder with an unspecified graph.
* Create a cycle base finder with an unspecified graph.
*/
public PatonSimpleCycles()
public PatonCycleBase()
{
}

/**
* Create a cycle basis finder for the specified graph.
* 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
* <code>null</code>.
*/
public PatonSimpleCycles(UndirectedGraph<V, E> graph)
public PatonCycleBase(UndirectedGraph<V, E> graph)
{
if (graph == null) {
throw new IllegalArgumentException("Null graph argument.");
Expand Down Expand Up @@ -92,14 +92,14 @@ public void setGraph(UndirectedGraph<V, E> graph)
* {@inheritDoc}
*/
@Override
public List<List<V>> findSimpleCycles()
public List<List<V>> findCycleBase()
{
if (graph == null) {
throw new IllegalArgumentException("Null graph.");
}
Map<V, Set<V>> used = new HashMap<V, Set<V>>();
Map<V, V> parent = new HashMap<V, V>();
Stack<V> stack = new Stack<V>();
ArrayDeque<V> stack = new ArrayDeque<V>();
List<List<V>> cycles = new ArrayList<List<V>>();

for (V root : graph.vertexSet()) {
Expand All @@ -123,29 +123,29 @@ public List<List<V>> findSimpleCycles()
V current = stack.pop();
Set<V> currentUsed = used.get(current);
for (E e : graph.edgesOf(current)) {
V neighbour = graph.getEdgeTarget(e);
if (neighbour.equals(current)) {
neighbour = graph.getEdgeSource(e);
V neighbor = graph.getEdgeTarget(e);
if (neighbor.equals(current)) {
neighbor = graph.getEdgeSource(e);
}
if (!used.containsKey(neighbour)) {
if (!used.containsKey(neighbor)) {
// found a new node
parent.put(neighbour, current);
parent.put(neighbor, current);
Set<V> neighbourUsed = new HashSet<V>();
neighbourUsed.add(current);
used.put(neighbour, neighbourUsed);
stack.push(neighbour);
used.put(neighbor, neighbourUsed);
stack.push(neighbor);
}
else if (neighbour.equals(current)) {
else if (neighbor.equals(current)) {
// found a self loop
List<V> cycle = new ArrayList<V>();
cycle.add(current);
cycles.add(cycle);
}
else if (!currentUsed.contains(neighbour)) {
else if (!currentUsed.contains(neighbor)) {
// found a cycle
Set<V> neighbourUsed = used.get(neighbour);
Set<V> neighbourUsed = used.get(neighbor);
List<V> cycle = new ArrayList<V>();
cycle.add(neighbour);
cycle.add(neighbor);
cycle.add(current);
V p = parent.get(current);
while (!neighbourUsed.contains(p)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
=============================================================================*/
package net.ognyanov.niographs;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.jgrapht.DirectedGraph;
import org.jgrapht.alg.StrongConnectivityInspector;
Expand Down Expand Up @@ -55,7 +55,7 @@ public class SzwarcfiterLauerSimpleCycles<V, E>
private V[] iToV = null;
private Map<V, Integer> vToI = null;
private Map<V, Set<V>> bSets = null;
private Stack<V> stack = null;
private ArrayDeque<V> stack = null;
private Set<V> marked = null;
private Map<V, Set<V>> removed = null;
private int[] position = null;
Expand Down Expand Up @@ -174,11 +174,22 @@ private boolean cycle(int v, int q)
}
else if (position[w] <= q) {
foundCycle = true;
int vIndex = stack.indexOf(vV);
int wIndex = stack.indexOf(wV);
List<V> cycle = new ArrayList<V>();
for (int i = wIndex; i <= vIndex; i++) {
cycle.add(stack.elementAt(i));
Iterator<V> it = stack.descendingIterator();
V current = null;
while (it.hasNext()) {
current = it.next();
if (wV.equals(current)) {
break;
}
}
cycle.add(wV);
while (it.hasNext()) {
current = it.next();
cycle.add(current);
if (current.equals(vV)) {
break;
}
}
cycles.add(cycle);
}
Expand Down Expand Up @@ -229,7 +240,7 @@ private void initState()
iToV = (V[]) graph.vertexSet().toArray();
vToI = new HashMap<V, Integer>();
bSets = new HashMap<V, Set<V>>();
stack = new Stack<V>();
stack = new ArrayDeque<V>();
marked = new HashSet<V>();
removed = new HashMap<V, Set<V>>();
int size = graph.vertexSet().size();
Expand Down
26 changes: 17 additions & 9 deletions src/main/java/net/ognyanov/niographs/TarjanSimpleCycles.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
=============================================================================*/
package net.ognyanov.niographs;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.jgrapht.DirectedGraph;

Expand All @@ -47,8 +48,8 @@ public class TarjanSimpleCycles<V, E>

private List<List<V>> cycles;
private Set<V> marked;
private Stack<V> markedStack;
private Stack<V> pointStack;
private ArrayDeque<V> markedStack;
private ArrayDeque<V> pointStack;
private Map<V, Integer> vToI;
private Map<V, Set<V>> removed;

Expand Down Expand Up @@ -138,10 +139,17 @@ private boolean backtrack(V start, V vertex)
else if (comparison == 0) {
foundCycle = true;
List<V> cycle = new ArrayList<V>();
int cycleStart = pointStack.indexOf(start);
int cycleEnd = pointStack.size() - 1;
for (int i = cycleStart; i <= cycleEnd; i++) {
cycle.add(pointStack.get(i));
Iterator<V> it = pointStack.descendingIterator();
V v = null;
while (it.hasNext()) {
v = it.next();
if (start.equals(v)) {
break;
}
}
cycle.add(start);
while (it.hasNext()) {
cycle.add(it.next());
}
cycles.add(cycle);
}
Expand All @@ -167,8 +175,8 @@ private void initState()
{
cycles = new ArrayList<List<V>>();
marked = new HashSet<V>();
markedStack = new Stack<V>();
pointStack = new Stack<V>();
markedStack = new ArrayDeque<V>();
pointStack = new ArrayDeque<V>();
vToI = new HashMap<V, Integer>();
removed = new HashMap<V, Set<V>>();
int index = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,24 @@

/**
* A common interface for classes implementing algorithms
* for finding a cycle basis of an undirected graph.
* for finding a cycle base of an undirected graph.
*
* @author Nikolay Ognyanov
*
* @param <V> - the vertex type.
*/
public interface UndirectedSimpleCycles<V, E>
public interface UndirectedCycleBase<V, E>
{
/**
* Returns the graph on which the cycle basis
* Returns the graph on which the cycle base
* search algorithm is executed by this object.
*
* @return The graph.
*/
UndirectedGraph<V, E> getGraph();

/**
* Sets the graph on which the cycle basis
* Sets the graph on which the cycle base
* search algorithm is executed by this object.
*
* @throws IllegalArgumentException if the
Expand All @@ -49,16 +49,16 @@ public interface UndirectedSimpleCycles<V, E>
void setGraph(UndirectedGraph<V, E> graph);

/**
* Finds a cycle basis of the graph.<br/>
* Finds a cycle base of the graph.<br/>
* Note that the full algorithm is executed on
* every call since the graph may have changed
* between calls.
*
* @return A list of cycles constituting a cycle
* basis for the graph. Possibly empty but never
* base for the graph. Possibly empty but never
* <code>null</code>.
* @throws IllegalArgumentException if the
* current graph is null.
*/
List<List<V>> findSimpleCycles();
List<List<V>> findCycleBase();
}
4 changes: 2 additions & 2 deletions src/main/java/net/ognyanov/niographs/package.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<li>Tiernan</li>
</ol>
&nbsp;&nbsp;&nbsp;&nbsp;The worst case time complexity of the
Paton's algorithm for finding a cycle basis in undirected graphs
Paton's algorithm for finding a cycle base in undirected graphs
is O(V^3)
</p>
<b>Literature:</b>
Expand Down Expand Up @@ -71,4 +71,4 @@

</ol>
</body>
</html>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,22 @@
import org.jgrapht.graph.SimpleGraph;
import org.junit.Test;

public class UndirectedSimpleCyclesTest
public class UndirectedCycleBaseTest
{
private static int MAX_SIZE = 10;
private static int[] RESULTS = { 0, 0, 0, 1, 3, 6, 10, 15, 21, 28, 36 };

@Test
public void test()
{
PatonSimpleCycles<Integer, DefaultEdge> patonFinder =
new PatonSimpleCycles<Integer, DefaultEdge>();
PatonCycleBase<Integer, DefaultEdge> patonFinder =
new PatonCycleBase<Integer, DefaultEdge>();

testAlgorithm(patonFinder);
}

private void testAlgorithm(
UndirectedSimpleCycles<Integer, DefaultEdge>
UndirectedCycleBase<Integer, DefaultEdge>
finder)
{
SimpleGraph<Integer, DefaultEdge> graph = new SimpleGraph<Integer, DefaultEdge>
Expand Down Expand Up @@ -97,10 +97,10 @@ private void testAlgorithm(
}
}

private void checkResult(UndirectedSimpleCycles
private void checkResult(UndirectedCycleBase
<Integer, DefaultEdge> finder,
int size)
{
assertTrue(finder.findSimpleCycles().size() == size);
assertTrue(finder.findCycleBase().size() == size);
}
}

0 comments on commit b229217

Please sign in to comment.