All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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