
com.jtransc.graph.Digraph.kt Maven / Gradle / Ivy
package com.jtransc.graph
import java.util.*
internal const val UNDEFINED = -1
class SDigraph {
interface Node {
val targets: List
}
interface Edge {
val target: Node
}
}
interface DigraphSimple {
val size: Int
fun getOut(node: Int): List
}
interface Digraph : DigraphSimple {
val nodes: List
val nodeIndices: Map
override val size: Int get() = nodes.size
//fun getIn(node: Int): List
override fun getOut(node: Int): List
}
fun Digraph.descendants(entry: Int = 0): List {
val explored = BooleanArray(size)
val out = arrayListOf(entry)
explored[entry] = true
fun explore(node: Int) {
val childsToExplored = arrayListOf()
for (child in getOut(node)) {
if (!explored[child]) {
explored[child] = true
out += child
childsToExplored += child
}
}
for (child in childsToExplored) explore(child)
}
explore(entry)
return out
}
fun Digraph.calcDepths(entryIndex: Int = 0): IntArray {
val depths = IntArray(size) { UNDEFINED }
fun explore(index: Int, depth: Int = 0) {
depths[index] = depth
for (out in getOut(index)) {
if (depths[out] != UNDEFINED) explore(out, depth + 1)
}
}
explore(entryIndex)
return depths
}
// LCA and LCA tree
fun Digraph.locateFirstConverge(nodes: Iterable): T? {
val result = locateFirstConverge(this.toIndices(nodes))
return if (result != UNDEFINED) getNode(result) else null
}
fun Digraph.locateFirstConverge(indices: Iterable): Int {
val depths = this.calcDepths()
return indices.reduce { a, b -> this.locateFirstConverge(a, b, depths) }
}
fun Digraph.locateFirstConverge(a: Int, b: Int, depths: IntArray): Int {
var l = if (depths[a] > depths[b]) a else b
var r = if (depths[a] > depths[b]) b else a
assert(depths[l] <= depths[r])
while (l != r) {
}
return l
}
fun Digraph.getIndex(node: T): Int = nodeIndices[node]!!
fun Digraph.getNode(index: Int): T = nodes[index]
fun Digraph.toNodes(indices: Iterable): List = indices.map { nodes[it] }
fun Digraph.toIndices(nodes: Iterable): List = nodes.map { nodeIndices[it]!! }
//fun Digraph.getInNodes(index: Int): List = toNodes(this.getIn(index))
fun Digraph.getOutNodes(index: Int): List = toNodes(this.getOut(index))
//fun Digraph.getInNodes(node: T): List = this.getInNodes(nodeIndices[node]!!)
fun Digraph.getOutNodes(node: T): List = this.getOutNodes(nodeIndices[node]!!)
fun Digraph.dump() {
println("DigraphWithNodes: SIZE($size)")
for (n in 0 until size) {
println("NODE: [${nodes[n]}] : OUT[${getOutNodes(n)}]")
}
for (v in nodes) {
for (w in getOutNodes(v)) {
println("EDGE: $v -> $w")
}
}
}
fun Digraph.dumpSimple() {
println("Digraph: SIZE($size)")
for (n in 0 until size) {
//println("[$n] : IN[${getIn(n)}] : OUT[${getOut(n)}]")
println("[$n] : OUT[${getOut(n)}]")
}
}
open class DigraphImpl(override val nodes: List, private val pairFrom: IntArray, private val pairTo: IntArray) : Digraph {
override val nodeIndices = (0 until size).map { nodes[it] to it }.toMap()
//override fun getIn(node: Int): List = input[node]
override fun getOut(node: Int): List = output[node]
val input = (0 until size).map { arrayListOf() }
val output = (0 until size).map { arrayListOf() }
init {
for (n in 0 until Math.min(pairFrom.size, pairTo.size)) {
input[pairTo[n]] += pairFrom[n]
output[pairFrom[n]] += pairTo[n]
}
}
}
fun graphList(edges: Iterable>>): Digraph {
return graphList(*edges.toList().toTypedArray())
}
fun graphList(vararg edges: Pair>): Digraph {
return graph(*edges.flatMap { pair -> pair.second.map { pair.first to it } }.toTypedArray())
}
fun graph(edges: Iterable>): Digraph {
return graph(*edges.toList().toTypedArray())
}
fun graph(vararg edges: Pair): Digraph {
var nodes = LinkedHashMap()
var size = 0
fun getIndex(node: T): Int {
if (node !in nodes) nodes[node] = size++
return nodes[node]!!
}
val pairIn = IntArray(edges.size)
val pairOut = IntArray(edges.size)
for (n in 0 until edges.size) {
var edge = edges[n]
//println("build EDGE: ${edge.first} -> ${edge.second}")
pairIn[n] = getIndex(edge.first)
pairOut[n] = getIndex(edge.second)
}
//for (node in nodes.keys) println("build NODE: $node")
return DigraphImpl(nodes.keys.toList(), pairIn, pairOut)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy