JavaTXCompilerInJavaTX/javatx-src/main/java/de/dhbwstuttgart/target/generate/CycleFinder.java

105 lines
4.1 KiB
Java

package de.dhbwstuttgart.target.generate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CycleFinder {
private CycleFinder() {}
static Set<GenerateGenerics.TPH> allNodes(Set<? extends GenerateGenerics.Pair> input) {
return input.stream()
.filter(GenerateGenerics.PairLT.class::isInstance)
.map(GenerateGenerics.PairLT.class::cast)
.flatMap(pair -> Stream.of(pair.left, pair.right)).collect(Collectors.toSet());
}
static Set<GenerateGenerics.TPH> outgoingEdgesOf(GenerateGenerics.TPH tph, Set<? extends GenerateGenerics.Pair> input) {
return input.stream()
.filter(GenerateGenerics.PairLT.class::isInstance)
.map(GenerateGenerics.PairLT.class::cast)
.filter(pair -> pair.left.equals(tph))
.map(pair -> pair.right).collect(Collectors.toSet());
}
static boolean containsEdge(GenerateGenerics.TPH a, GenerateGenerics.TPH b, Set<? extends GenerateGenerics.Pair> input) {
return input.stream()
.filter(GenerateGenerics.PairLT.class::isInstance)
.map(GenerateGenerics.PairLT.class::cast)
.anyMatch(pair -> pair.left.equals(a) && pair.right.equals(b));
}
// Tiernan simple cycles algorithm
// Adapted from https://github.com/jgrapht/jgrapht/blob/master/jgrapht-core/src/main/java/org/jgrapht/alg/cycle/TiernanSimpleCycles.java
static Set<List<GenerateGenerics.TPH>> findCycles(Set<? extends GenerateGenerics.Pair> input) {
Map<GenerateGenerics.TPH, Integer> indices = new HashMap<>();
List<GenerateGenerics.TPH> path = new ArrayList<>();
Set<GenerateGenerics.TPH> pathSet = new HashSet<>();
Map<GenerateGenerics.TPH, Set<GenerateGenerics.TPH>> blocked = new HashMap<>();
Set<List<GenerateGenerics.TPH>> cycles = new HashSet<>();
int index = 0;
for (var tph : allNodes(input)) {
blocked.put(tph, new HashSet<>());
indices.put(tph, index++);
}
var vertexIterator = allNodes(input).iterator();
if (!vertexIterator.hasNext()) return cycles;
GenerateGenerics.TPH startOfPath = null;
GenerateGenerics.TPH endOfPath = vertexIterator.next();
GenerateGenerics.TPH temp = null;
int endIndex = 0;
boolean extensionFound = false;
path.add(endOfPath);
pathSet.add(endOfPath);
while (true) {
do {
extensionFound = false;
for (GenerateGenerics.TPH n : outgoingEdgesOf(endOfPath, input)) {
int cmp = indices.get(n).compareTo(indices.get(path.get(0)));
if ((cmp > 0) && !pathSet.contains(n) && !blocked.get(endOfPath).contains(n)) {
path.add(n);
pathSet.add(n);
endOfPath = n;
extensionFound = true;
break;
}
}
} while (extensionFound);
startOfPath = path.get(0);
if (containsEdge(endOfPath, startOfPath, input)) {
List<GenerateGenerics.TPH> cycle = new ArrayList<>(path);
cycles.add(cycle);
}
if (path.size() > 1) {
blocked.get(endOfPath).clear();
endIndex = path.size() - 1;
path.remove(endIndex);
pathSet.remove(endOfPath);
--endIndex;
temp = endOfPath;
endOfPath = path.get(endIndex);
blocked.get(endOfPath).add(temp);
continue;
}
if (vertexIterator.hasNext()) {
path.clear();
pathSet.clear();
endOfPath = vertexIterator.next();
path.add(endOfPath);
pathSet.add(endOfPath);
for (GenerateGenerics.TPH tph : blocked.keySet()) {
blocked.get(tph).clear();
}
continue;
}
break;
}
return cycles;
}
}