Fix Mod Sorting reporting incorrect cycles when sorting fails. Closes #10942

Co-authored-by: ZZZank <[email protected]>
This commit is contained in:
LexManos committed 2026-11-12 13:16:53 -08:00
1 parent 9cd61b99f1
commit f375683bcd
1 file changed
+26 -28
@@ -22,15 +22,18 @@ import java.util.Set;
* *
* <p>This detector evaluates the graph lazily and won't reflect the modifications in the * <p>This detector evaluates the graph lazily and won't reflect the modifications in the
* graph after initial evaluation. * graph after initial evaluation.
*
* <p> Implementation based on <a href="https://en.wikipedia.org/w/index.php?title=Tarjan%27s_strongly_connected_components_algorithm&oldid=1384955226">Wikipedia Psudocode</a>
*/ */
public class StronglyConnectedComponentDetector<T> { public class StronglyConnectedComponentDetector<T> {
private final Graph<T> graph; private final Graph<T> graph;
private final Map<T, Integer> ids = new HashMap<>(); private final Map<T, Integer> ids = new HashMap<>();
private T[] elements; private T[] elements;
private int[] dfn; private int[] indexes;
private int[] low; private int[] lowlinks;
private int[] stack; private int[] stack;
private int top; private int top;
private int index;
private BitSet onStack; private BitSet onStack;
private Set<Set<T>> components; private Set<Set<T>> components;
@@ -58,48 +61,43 @@ public class StronglyConnectedComponentDetector<T> {
} }
final int n = nodes.size(); final int n = nodes.size();
dfn = new int[n]; indexes = new int[n];
low = new int[n]; lowlinks = new int[n];
stack = new int[n]; stack = new int[n];
onStack = new BitSet(n); onStack = new BitSet(n);
top = -1; top = -1;
index = 1;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
if (dfn[i] == 0) { if (indexes[i] == 0)
dfs(i, 1); dfs(i);
}
} }
} }
private void dfs(int now, int depth) { private void dfs(int now) {
dfn[now] = depth; indexes[now] = lowlinks[now] = index++;
low[now] = depth; stack[++top] = now;
top++;
stack[top] = now;
onStack.set(now); onStack.set(now);
for (T each : graph.successors(elements[now])) { for (T each : graph.successors(elements[now])) {
int to = ids.get(each); int to = ids.get(each);
if (dfn[to] != 0) { if (indexes[to] == 0) { // 0 is unvisited
if (low[now] > dfn[to]) { dfs(to);
low[now] = dfn[to]; if (lowlinks[now] > lowlinks[to])
} lowlinks[now] = lowlinks[to];
} else { } else if (onStack.get(to)) {
dfs(to, depth + 1); if (lowlinks[now] > indexes[to])
if (low[now] > low[to]) { lowlinks[now] = indexes[to];
low[now] = low[to];
}
} }
} }
if (dfn[now] == low[now]) { if (indexes[now] == lowlinks[now]) {
Set<T> component = new HashSet<>(); Set<T> component = new HashSet<>();
while (top >= 0) { while (top >= 0) {
final int t = stack[top]; final int w = stack[top--];
component.add(elements[t]); onStack.clear(w);
onStack.clear(t); component.add(elements[w]);
top--; if (w == now)
if (t == now) {
break; break;
}
} }
components.add(component); components.add(component);
} }