Add more complicated irreducible graph test

This commit is contained in:
konsoletyper 2015-03-05 23:35:12 +03:00
parent 33b319ce16
commit 0fe826ade8
4 changed files with 98 additions and 20 deletions

View File

@ -69,11 +69,13 @@ public class DJGraph {
} }
// Add dom edges // Add dom edges
for (int i = 1; i < graph.size(); ++i) { for (int i = 0; i < graph.size(); ++i) {
int j = domTree.immediateDominatorOf(i); int j = domTree.immediateDominatorOf(i);
if (j >= 0) {
graph.addEdge(j, i); graph.addEdge(j, i);
} }
} }
}
private void buildLevels() { private void buildLevels() {
List<IntegerArray> builder = new ArrayList<>(); List<IntegerArray> builder = new ArrayList<>();

View File

@ -91,14 +91,13 @@ public final class GraphUtils {
for (int startNode : start) { for (int startNode : start) {
stack.push(startNode); stack.push(startNode);
IntegerArray currentComponent = new IntegerArray(1); IntegerStack currentComponent = new IntegerStack(1);
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
int node = stack.pop(); int node = stack.pop();
if (visitIndex[node] > 0) { if (visitIndex[node] > 0) {
if (headerIndex[node] > 0) { if (headerIndex[node] > 0) {
continue; continue;
} }
currentComponent.add(node);
int hdr = visitIndex[node]; int hdr = visitIndex[node];
for (int successor : graph.outgoingEdges(node)) { for (int successor : graph.outgoingEdges(node)) {
if (!filter.match(successor)) { if (!filter.match(successor)) {
@ -111,15 +110,21 @@ public final class GraphUtils {
} }
} }
if (hdr == visitIndex[node]) { if (hdr == visitIndex[node]) {
components.add(currentComponent.getAll()); IntegerArray componentMembers = new IntegerArray(graph.size());
for (int componentMember : currentComponent.getAll()) { while (true) {
int componentMember = currentComponent.pop();
componentMembers.add(componentMember);
headerIndex[componentMember] = graph.size() + 1; headerIndex[componentMember] = graph.size() + 1;
if (visitIndex[componentMember] == hdr) {
break;
} }
currentComponent.clear(); }
components.add(componentMembers.getAll());
} }
headerIndex[node] = hdr; headerIndex[node] = hdr;
} else { } else {
visitIndex[node] = ++lastIndex; visitIndex[node] = ++lastIndex;
currentComponent.push(node);
stack.push(node); stack.push(node);
for (int successor : graph.outgoingEdges(node)) { for (int successor : graph.outgoingEdges(node)) {
if (!filter.match(successor) || visitIndex[successor] > 0) { if (!filter.match(successor) || visitIndex[successor] > 0) {

View File

@ -63,17 +63,6 @@ class IrreducibleGraphConverter {
for (int[] scc : sccs) { for (int[] scc : sccs) {
if (scc.length > 1) { if (scc.length > 1) {
handleStronglyConnectedComponent(djGraph, scc, nodeMap); handleStronglyConnectedComponent(djGraph, scc, nodeMap);
int cls = djGraph.collapse(scc);
IntegerArray nodes = new IntegerArray(djGraph.getGraph().size());
for (int representative : djGraph.classRepresentatives(cls)) {
for (int node : nodeMap[representative]) {
nodes.add(node);
}
}
for (int representative : djGraph.classRepresentatives(cls)) {
nodeMap[representative] = new int[0];
}
nodeMap[cls] = nodes.getAll();
} }
} }
} }
@ -89,7 +78,7 @@ class IrreducibleGraphConverter {
for (int i = 0; i < scc.length; ++i) { for (int i = 0; i < scc.length; ++i) {
if (scc[i] == sharedDom) { if (scc[i] == sharedDom) {
djGraph.collapse(scc); collapse(djGraph, scc, nodeMap);
return; return;
} }
} }
@ -146,7 +135,7 @@ class IrreducibleGraphConverter {
// Collapse // Collapse
int[] sccAndTop = Arrays.copyOf(scc, scc.length + 1); int[] sccAndTop = Arrays.copyOf(scc, scc.length + 1);
sccAndTop[scc.length] = sharedDom; sccAndTop[scc.length] = sharedDom;
djGraph.collapse(sccAndTop); collapse(djGraph, sccAndTop, nodeMap);
} }
private void splitStronglyConnectedComponent(DJGraph djGraph, IntSet domain, int sharedDom, private void splitStronglyConnectedComponent(DJGraph djGraph, IntSet domain, int sharedDom,
@ -241,6 +230,20 @@ class IrreducibleGraphConverter {
handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap); handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap);
} }
private void collapse(DJGraph djGraph, int[] scc, int[][] nodeMap) {
int cls = djGraph.collapse(scc);
IntegerArray nodes = new IntegerArray(djGraph.getGraph().size());
for (int representative : djGraph.classRepresentatives(cls)) {
for (int node : nodeMap[representative]) {
nodes.add(node);
}
}
for (int representative : djGraph.classRepresentatives(cls)) {
nodeMap[representative] = new int[0];
}
nodeMap[cls] = nodes.getAll();
}
private static int[] flatten(int[][] array) { private static int[] flatten(int[][] array) {
int count = 0; int count = 0;
for (int i = 0; i < array.length; ++i) { for (int i = 0; i < array.length; ++i) {

View File

@ -107,6 +107,41 @@ public class GraphTest {
assertThat(sccs[2], is(new int[] { 2 })); assertThat(sccs[2], is(new int[] { 2 }));
} }
@Test
public void stronglyConnectedComponentCalculated4() {
GraphBuilder builder = new GraphBuilder();
builder.addEdge(0, 1);
builder.addEdge(0, 2);
builder.addEdge(1, 2);
builder.addEdge(1, 3);
builder.addEdge(1, 4);
builder.addEdge(2, 1);
builder.addEdge(2, 3);
builder.addEdge(3, 4);
builder.addEdge(4, 5);
builder.addEdge(4, 6);
builder.addEdge(5, 6);
builder.addEdge(6, 5);
builder.addEdge(6, 7);
builder.addEdge(7, 4);
builder.addEdge(7, 3);
builder.addEdge(7, 8);
builder.addEdge(8, 7);
Graph graph = builder.build();
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, new int[] { 1, 2, 3, 4 },
new GraphNodeFilter() {
@Override public boolean match(int node) {
return node != 0;
}
});
sortSccs(sccs);
assertThat(sccs.length, is(2));
assertThat(sccs[0], is(new int[] { 1, 2 }));
assertThat(sccs[1], is(new int[] { 3, 4, 5, 6, 7, 8 }));
}
@Test @Test
public void irreducibleGraphSplit() { public void irreducibleGraphSplit() {
GraphBuilder builder = new GraphBuilder(); GraphBuilder builder = new GraphBuilder();
@ -152,6 +187,39 @@ public class GraphTest {
assertTrue("Should be equialent", isEquialent(backend, graph)); assertTrue("Should be equialent", isEquialent(backend, graph));
} }
@Test
public void irreducibleGraphSplit3() {
GraphBuilder builder = new GraphBuilder();
builder.addEdge(0, 1);
builder.addEdge(0, 2);
builder.addEdge(1, 2);
builder.addEdge(1, 3);
builder.addEdge(1, 4);
builder.addEdge(2, 1);
builder.addEdge(2, 3);
builder.addEdge(3, 4);
builder.addEdge(4, 5);
builder.addEdge(4, 6);
builder.addEdge(5, 6);
builder.addEdge(6, 5);
builder.addEdge(6, 7);
builder.addEdge(7, 4);
builder.addEdge(7, 3);
builder.addEdge(7, 8);
builder.addEdge(8, 7);
Graph graph = builder.build();
DefaultGraphSplittingBackend backend = new DefaultGraphSplittingBackend(graph);
int[] weights = new int[graph.size()];
Arrays.fill(weights, 1);
GraphUtils.splitIrreducibleGraph(graph, weights, backend);
Graph result = backend.getGraph();
assertTrue("Should be irreducible", GraphUtils.isIrreducible(graph));
assertFalse("Should be reducible", GraphUtils.isIrreducible(result));
assertTrue("Should be equialent", isEquialent(backend, graph));
}
private boolean isEquialent(DefaultGraphSplittingBackend backend, Graph proto) { private boolean isEquialent(DefaultGraphSplittingBackend backend, Graph proto) {
Graph graph = backend.getGraph(); Graph graph = backend.getGraph();
for (int node = 0; node < graph.size(); ++node) { for (int node = 0; node < graph.size(); ++node) {