Coverage Summary for Class: GraphAlgorithmsKt (it.unibo.tuprolog.argumentation.core.primitives.graph)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| GraphAlgorithmsKt |
100%
(2/2)
|
100%
(18/18)
|
100%
(33/33)
|
100%
(241/241)
|
| GraphAlgorithmsKt$stronglyConnectedComponents$$inlined$sortedBy$1 |
0%
(0/1)
|
|
| Total |
66.7%
(2/3)
|
100%
(18/18)
|
100%
(33/33)
|
100%
(241/241)
|
package it.unibo.tuprolog.argumentation.core.primitives.graph
/**
* Strongly connected components of a directed graph (Tarjan's algorithm, iterative), in topological order:
* every edge between two components goes from an earlier one to a later one. Nodes keep their input order
* within a component, and successors outside nodes are ignored.
*/
internal fun <T> stronglyConnectedComponents(
nodes: Iterable<T>,
successors: (T) -> Iterable<T>,
): List<List<T>> {
val order = nodes.withIndex().associate { (i, node) -> node to i }
val index = HashMap<T, Int>()
val lowLink = HashMap<T, Int>()
val onStack = HashSet<T>()
val stack = ArrayDeque<T>()
val components = mutableListOf<List<T>>()
for (root in order.keys) {
if (root in index) continue
// explicit call stack of (node, iterator over its successors)
val calls = ArrayDeque<Pair<T, Iterator<T>>>()
fun visit(node: T) {
index[node] = index.size
lowLink[node] = index.getValue(node)
stack.addLast(node)
onStack += node
calls.addLast(node to successors(node).filter { it in order }.iterator())
}
visit(root)
while (calls.isNotEmpty()) {
val (node, next) = calls.last()
if (next.hasNext()) {
val successor = next.next()
if (successor !in index) {
visit(successor)
} else if (successor in onStack) {
lowLink[node] = minOf(lowLink.getValue(node), index.getValue(successor))
}
continue
}
calls.removeLast()
calls.lastOrNull()?.let { (caller, _) -> lowLink[caller] = minOf(lowLink.getValue(caller), lowLink.getValue(node)) }
if (lowLink[node] == index[node]) {
val component = mutableListOf<T>()
do {
val member = stack.removeLast()
onStack -= member
component += member
} while (member != node)
components += component.sortedBy { order.getValue(it) }
}
}
}
// Tarjan completes a component after all the components reachable from it
return components.asReversed()
}