
overflowdb.algorithm.DependencySequencer.scala Maven / Gradle / Ivy
package overflowdb.algorithm
import scala.annotation.tailrec
object DependencySequencer {
/**
* Find the sequence of dependencies a set of nodes in a directed acyclic graph (DAG).
* Sample use case: concurrent task processing: given a set of tasks, determine which ones can be
* executed in parallel, and which ones need to run in sequence.
*
* @throws java.lang.AssertionError if given nodes have cyclic dependencies
*
* Algorithm: variant of Kahn's algorithm for topological sort
* 1) for given nodes, find all leaves, i.e. the those without parents (e.g. task dependencies)
* 2) disregard all that have already been visited and add to the results sequence
* 3) repeat for the remainder of nodes
*
* see https://en.wikipedia.org/wiki/Topological_sorting#Kahn%27s_algorithm
*/
def apply[A: GetParents](nodes: Set[A]): Seq[Set[A]] = {
apply0(nodes, Seq.empty, Set.empty)
}
@tailrec
private def apply0[A: GetParents](nodes: Set[A], accumulator: Seq[Set[A]], visited: Set[A]): Seq[Set[A]] = {
if (nodes.size == 0) {
accumulator
} else {
val getParents = implicitly[GetParents[A]]
val leaves = nodes.filter(getParents(_).diff(visited).isEmpty)
val remainder = nodes.diff(leaves)
assert(remainder.size < nodes.size, s"given set of nodes is not a directed acyclic graph (DAG): ${nodes ++ accumulator.flatten}")
apply0(remainder, accumulator :+ leaves, visited ++ leaves)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy