mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add unit tests for irreducible graph splitter
This commit is contained in:
parent
04677d0103
commit
e2aababde8
|
@ -31,37 +31,8 @@ public final class GraphUtils {
|
|||
private GraphUtils() {
|
||||
}
|
||||
|
||||
public static Graph invert(Graph graph) {
|
||||
public static int[] findBackEdges(Graph graph) {
|
||||
int sz = graph.size();
|
||||
GraphBuilder result = new GraphBuilder();
|
||||
int[] sourceEdges = new int[sz];
|
||||
for (int node = 0; node < sz; ++node) {
|
||||
int sourceCount = graph.copyIncomingEdges(node, sourceEdges);
|
||||
for (int i = 0; i < sourceCount; ++i) {
|
||||
int source = sourceEdges[i];
|
||||
result.addEdge(node, source);
|
||||
}
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
|
||||
public static Graph close(Graph graph) {
|
||||
GraphBuilder result = new GraphBuilder();
|
||||
for (int node = 0; node < graph.size(); ++node) {
|
||||
int[] next = graph.outgoingEdges(node);
|
||||
for (int target : next) {
|
||||
result.addEdge(node, target);
|
||||
}
|
||||
if (next.length == 0) {
|
||||
result.addEdge(node, graph.size());
|
||||
}
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
|
||||
public static Graph removeLoops(Graph graph) {
|
||||
int sz = graph.size();
|
||||
GraphBuilder result = new GraphBuilder();
|
||||
int[] stack = new int[sz * 2];
|
||||
int stackSize = 0;
|
||||
byte[] state = new byte[sz];
|
||||
|
@ -70,6 +41,7 @@ public final class GraphUtils {
|
|||
stack[stackSize++] = i;
|
||||
}
|
||||
}
|
||||
IntegerArray result = new IntegerArray(2);
|
||||
while (stackSize > 0) {
|
||||
int node = stack[--stackSize];
|
||||
switch (state[node]) {
|
||||
|
@ -79,11 +51,11 @@ public final class GraphUtils {
|
|||
for (int next : graph.outgoingEdges(node)) {
|
||||
switch (state[next]) {
|
||||
case NONE:
|
||||
result.addEdge(node, next);
|
||||
stack[stackSize++] = next;
|
||||
break;
|
||||
case VISITED:
|
||||
result.addEdge(node, next);
|
||||
case VISITING:
|
||||
result.add(node);
|
||||
result.add(next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -93,22 +65,25 @@ public final class GraphUtils {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return result.build();
|
||||
return result.getAll();
|
||||
}
|
||||
|
||||
public static int edgeCount(Graph graph) {
|
||||
int cnt = 0;
|
||||
int sz = graph.size();
|
||||
for (int node = 0; node < sz; ++node) {
|
||||
cnt += graph.outgoingEdgesCount(node);
|
||||
public static boolean isIrreducible(Graph graph) {
|
||||
DominatorTree dom = buildDominatorTree(graph);
|
||||
int[] backEdges = findBackEdges(graph);
|
||||
for (int i = 0; i < backEdges.length; i += 2) {
|
||||
if (!dom.dominates(backEdges[i + 1], backEdges[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tarjan's algorithm
|
||||
*/
|
||||
public static int[][] findStronglyConnectedComponents(Graph graph, int[] start, GraphNodeFilter filter) {
|
||||
// TODO: can show incorrect behaviour sometimes
|
||||
List<int[]> components = new ArrayList<>();
|
||||
int[] visitIndex = new int[graph.size()];
|
||||
int[] headerIndex = new int[graph.size()];
|
||||
|
|
|
@ -17,6 +17,8 @@ package org.teavm.common;
|
|||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||
import com.carrotsearch.hppc.IntSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import org.junit.Test;
|
||||
|
@ -86,6 +88,71 @@ public class GraphTest {
|
|||
assertThat(sccs[0], is(new int[] { 1, 2, 3, 4, 5 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void irreducibleGraphSplit() {
|
||||
GraphBuilder builder = new GraphBuilder();
|
||||
builder.addEdge(0, 1);
|
||||
builder.addEdge(0, 2);
|
||||
builder.addEdge(0, 3);
|
||||
builder.addEdge(1, 2);
|
||||
builder.addEdge(2, 1);
|
||||
builder.addEdge(3, 2);
|
||||
builder.addEdge(2, 4);
|
||||
builder.addEdge(4, 5);
|
||||
builder.addEdge(4, 1);
|
||||
builder.addEdge(5, 3);
|
||||
|
||||
Graph graph = builder.build();
|
||||
DefaultGraphSplittingBackend backend = new DefaultGraphSplittingBackend(graph);
|
||||
int[] weights = { 1, 4, 1, 10, 1, 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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void irreducibleGraphSplit2() {
|
||||
GraphBuilder builder = new GraphBuilder();
|
||||
builder.addEdge(0, 1);
|
||||
builder.addEdge(0, 2);
|
||||
builder.addEdge(1, 2);
|
||||
builder.addEdge(2, 1);
|
||||
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) {
|
||||
Graph graph = backend.getGraph();
|
||||
for (int node = 0; node < graph.size(); ++node) {
|
||||
int nodeProto = backend.prototype(node);
|
||||
IntSet succProto = new IntOpenHashSet();
|
||||
for (int succ : graph.outgoingEdges(node)) {
|
||||
succProto.add(backend.prototype(succ));
|
||||
}
|
||||
if (succProto.size() != proto.outgoingEdgesCount(nodeProto)) {
|
||||
return false;
|
||||
}
|
||||
for (int succ : proto.outgoingEdges(nodeProto)) {
|
||||
if (!succProto.contains(succ)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private GraphNodeFilter filter = new GraphNodeFilter() {
|
||||
@Override public boolean match(int node) {
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue
Block a user