commonMain.com.javiersc.kotlin.stdlib.graph.Graph.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-stdlib Show documentation
Show all versions of kotlin-stdlib Show documentation
Adds missing features in the official Kotlin stdlib
The newest version!
package com.javiersc.kotlin.stdlib.graph
public interface Graph : Map, List>> {
public var renderer: (Any?.() -> String)
public val circularVertexes: Map>
get() {
val circularDependencies: MutableMap> = mutableMapOf()
val visited: MutableSet> = mutableSetOf()
for (vertex: Vertex in keys) {
if (vertex !in visited) {
val path: MutableList> = mutableListOf()
vertex.deepFirstSearchCircularDependencies(visited, path, circularDependencies)
}
}
return circularDependencies.mapValues { it.value.toList() }
}
public val hasCircularVertexes: Boolean
get() = circularVertexes.isNotEmpty()
public val duplicatedVertexes: Map
get() = keys.groupingBy(Vertex::value).eachCount().filterValues { it > 1 }
public val hasDuplicatedVertexes: Boolean
get() = duplicatedVertexes.isNotEmpty()
public val missingVertexes: Set
public val hasMissingVertexes: Boolean
get() = missingVertexes.isNotEmpty()
public fun asString(): String = buildString {
[email protected] { (vertex: Vertex, edges: List>) ->
val value: String = renderer(vertex.value)
val edgeString: String = edges.joinToString { renderer(it.destination.value) }
appendLine("$value -> [$edgeString]")
}
}
public fun contains(value: T): Boolean = keys.any { it.value == value }
public fun contains(value: T, predicate: (T) -> Boolean): Boolean =
keys.any { predicate(it.value) }
public fun toGraph(): Graph = this
public fun containsCircularVertexes(value: T): Boolean =
circularVertexes[value]?.isNotEmpty() == true
public fun doesNotContainsCircularVertexes(value: T): Boolean = !containsCircularVertexes(value)
public fun vertexesFor(value: T, predicate: (T) -> Boolean = { it == value }): List {
if (containsCircularVertexes(value)) return emptyList()
val vertex: Vertex = keys.find { predicate(it.value) } ?: return emptyList()
val edges: List> = this[vertex] ?: return emptyList()
val destinationVertexes: Sequence> = edges.asSequence().map(Edge::destination)
val destinations: Sequence = destinationVertexes.map(Vertex::value)
return (destinations + destinationVertexes.flatMap { vertexesFor(it.value) }).toList()
}
public fun vertexesFor(vararg values: T): List = values.flatMap(::vertexesFor)
public fun toGraphSortedByEdges(): Graph = buildGraph {
val sortedGraph: MutableGraph = this
val graph: Graph = this@Graph
val remainingMap: MutableMap, List>> = graph.toMutableMap()
while (remainingMap.isNotEmpty()) {
val vertexesToBeRemoved: MutableList> = mutableListOf()
for ((vertex: Vertex, edges: List>) in remainingMap) {
if (edges.isEmpty()) {
sortedGraph.addVertex(vertex.value)
vertexesToBeRemoved.add(vertex)
println()
}
for (edge: Edge in edges) {
if (edge.destination.value in sortedGraph.keys.map(Vertex::value)) {
sortedGraph.addVertex(edge.source.value)
sortedGraph.addEdge(edge.source.value, edge.destination.value)
vertexesToBeRemoved.add(edge.source)
println()
}
}
}
for (vertexToBeRemoved: Vertex in vertexesToBeRemoved) {
remainingMap.remove(vertexToBeRemoved)
}
vertexesToBeRemoved.clear()
}
}
public fun renderer(block: Any?.() -> String) {
this.renderer = block
}
public data class Vertex(val index: Int, val value: T)
public data class Edge(val source: Vertex, val destination: Vertex)
private fun Vertex.deepFirstSearchCircularDependencies(
visited: MutableSet>,
path: MutableList>,
circularDependencies: MutableMap>,
) {
val map: Graph = this@Graph
val vertex: Vertex = this
visited.add(vertex)
path.add(vertex)
val edges: List> = map[vertex] ?: return
for (edge: Edge in edges) {
val destination: Vertex = edge.destination
if (destination in path) {
val circularDependency =
path.subList(path.indexOf(destination), path.size).map { it.value }
circularDependencies
.getOrPut(circularDependency.first()) { mutableListOf() }
.addAll(circularDependency)
} else if (destination !in visited) {
destination.deepFirstSearchCircularDependencies(visited, path, circularDependencies)
}
}
if (path.last() == vertex) {
path.remove(vertex)
}
}
}
public class MutableGraph internal constructor() : Graph {
override var renderer: (Any?.() -> String) = { this.toString() }
private val _missingVertexes: MutableSet = mutableSetOf()
override val missingVertexes: Set = _missingVertexes
private val map: MutableMap, MutableList>> = mutableMapOf()
override val entries: Set, List>>>
get() = map.entries
override val keys: Set>
get() = map.keys
override val size: Int
get() = map.size
override val values: Collection>>
get() = map.values
public fun addVertex(data: T): T {
val vertex: Graph.Vertex = Graph.Vertex(this.count(), data)
map[vertex] = mutableListOf()
return data
}
public fun addEdge(source: T, destination: T) {
val sourceVertex: Graph.Vertex? = keys.find { it.value == source }
val destinationVertex: Graph.Vertex? = keys.find { it.value == destination }
if (sourceVertex == null) _missingVertexes.add(source)
if (destinationVertex == null) _missingVertexes.add(destination)
if (sourceVertex != null && destinationVertex != null) {
val edge: Graph.Edge = Graph.Edge(sourceVertex, destinationVertex)
map[sourceVertex]?.add(edge)
}
}
override fun isEmpty(): Boolean = map.isEmpty()
override fun get(key: Graph.Vertex): List>? = map[key]
override fun containsValue(value: List>): Boolean = map.containsValue(value)
override fun containsKey(key: Graph.Vertex): Boolean = map.containsKey(key)
override fun toString(): String = asString()
}
public fun buildGraph(builderAction: MutableGraph.() -> Unit = {}): Graph =
MutableGraph().apply(builderAction)
public fun mutableGraphOf(builderAction: MutableGraph.() -> Unit = {}): MutableGraph =
MutableGraph().apply(builderAction)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy